如何在 haskell 中创建 class 的类型实例?
How to create a type instance of class in haskell?
我是 Haskell 的新手。
我正在寻找是否有任何方法可以创建 class 类型的实例。
有没有什么方法可以在不使用数据或新类型的情况下使这段代码正常工作?
type N = ∀n. (n -> n) -> n -> n
instance Printable N where
print :: N -> IO ()
read :: String -> N
当我尝试在 GHCi 中加载模块时,它告诉我:
Illegal polymorphic or qualified type: N
In the instance declaration for ‘Printable N’
您在那里写的内容看起来很像 class 声明,而不是实例。也许你是这个意思?
class Printable n where
print :: n -> IO ()
read :: String -> n
请注意 n
必须是小写的,因为这是 类型变量 你正在量化 class 。如果你真的想定义一个实例,那么你 instantiate n
with N
:
instance Printable N where
print n = ...
read str = ...
此时 类型签名 都已固定(来自 class 定义),您需要编写的是这些函数的实际绑定,因此它必须是 =
,而不是 ::
.
问题是:为什么您仍然需要自己的 class?它只会导致名称与前奏中已有的标准函数 print
和 read
发生冲突。你实际上应该做的是用你的N
类型实例化那些标准classes,即
instance Show N where
show n = ...
instance Read N where
readsPrec _ str = ...
就是说,要回答您提出的实际问题:no,无法明智地定义 any 实例对于像 ∀ n . (n->n) -> n->n
这样的多态类型。编译器应该如何将其与 (Int->Int) -> Int->Int
等更具体的类型或 ∀ n m . (n->m) -> n->m
等更一般的类型区分开来?真是没希望了。 正确 要做的就是将它包装在一个新类型中;隐藏通用量化并允许编译器正确区分 N
与其他类型。
或者,您可以直接编写单态函数 accept/yield N
:
showChurch :: N -> String
showChurch n = ...
readsPrecChurch :: Int -> ReadS N
readsPrecChurch _ str = ...
实际上后一个对于类型系统来说已经太多了:ReadS N
是
的缩写
readsPrecChurch :: Int -> String -> [(∀ n . (n->n) -> n->n, String)]
列表中的通用量化?呃哦。那是一种间接的类型。 GHC 确实有一个 -XImpredicativeTypes
扩展,但它并没有真正起作用。
同样,只要不公开使用多态类型就可以避免这些问题。 N 级类型(特别是镜头)有一些很好的用途,但大多数时候它们完全是多余的和不必要的。确实没有充分的理由实际使用这样的教堂数字。
newtype N = Church { getChurch :: ∀ n . (n->n) -> n->n }
将允许您毫无问题地定义任意实例或函数。而且,实际上,简单地做
type N = Int
对于整数的所有标准实例当然也一样好...
我是 Haskell 的新手。
我正在寻找是否有任何方法可以创建 class 类型的实例。
有没有什么方法可以在不使用数据或新类型的情况下使这段代码正常工作?
type N = ∀n. (n -> n) -> n -> n
instance Printable N where
print :: N -> IO ()
read :: String -> N
当我尝试在 GHCi 中加载模块时,它告诉我:
Illegal polymorphic or qualified type: N
In the instance declaration for ‘Printable N’
您在那里写的内容看起来很像 class 声明,而不是实例。也许你是这个意思?
class Printable n where
print :: n -> IO ()
read :: String -> n
请注意 n
必须是小写的,因为这是 类型变量 你正在量化 class 。如果你真的想定义一个实例,那么你 instantiate n
with N
:
instance Printable N where
print n = ...
read str = ...
此时 类型签名 都已固定(来自 class 定义),您需要编写的是这些函数的实际绑定,因此它必须是 =
,而不是 ::
.
问题是:为什么您仍然需要自己的 class?它只会导致名称与前奏中已有的标准函数 print
和 read
发生冲突。你实际上应该做的是用你的N
类型实例化那些标准classes,即
instance Show N where
show n = ...
instance Read N where
readsPrec _ str = ...
就是说,要回答您提出的实际问题:no,无法明智地定义 any 实例对于像 ∀ n . (n->n) -> n->n
这样的多态类型。编译器应该如何将其与 (Int->Int) -> Int->Int
等更具体的类型或 ∀ n m . (n->m) -> n->m
等更一般的类型区分开来?真是没希望了。 正确 要做的就是将它包装在一个新类型中;隐藏通用量化并允许编译器正确区分 N
与其他类型。
或者,您可以直接编写单态函数 accept/yield N
:
showChurch :: N -> String
showChurch n = ...
readsPrecChurch :: Int -> ReadS N
readsPrecChurch _ str = ...
实际上后一个对于类型系统来说已经太多了:ReadS N
是
readsPrecChurch :: Int -> String -> [(∀ n . (n->n) -> n->n, String)]
列表中的通用量化?呃哦。那是一种间接的类型。 GHC 确实有一个 -XImpredicativeTypes
扩展,但它并没有真正起作用。
同样,只要不公开使用多态类型就可以避免这些问题。 N 级类型(特别是镜头)有一些很好的用途,但大多数时候它们完全是多余的和不必要的。确实没有充分的理由实际使用这样的教堂数字。
newtype N = Church { getChurch :: ∀ n . (n->n) -> n->n }
将允许您毫无问题地定义任意实例或函数。而且,实际上,简单地做
type N = Int
对于整数的所有标准实例当然也一样好...