为什么这段代码正确
instance Functor IO where -- note that IO isn't parametrized, and it's correct
fmap f action = do
result <- action
return (f result)
但以下代码有编译错误?
class Print a where
print :: a -> String
data A t = A t
instance Print A where -- error: expecting one more argument to `A'
print a = "abc"
答案 0 :(得分:11)
这是因为kinds不匹配。常规类型具有类型*
,而类型构造函数(例如A
或IO
)具有类* -> *
,表示它们需要类型参数才能返回类型。
在Print
类的定义中,编译器推断由于a
用作普通类型,因此它必须具有类*
。但是,Functor
适用于类* -> *
的类型构造函数:
class Functor f where
fmap :: (a -> b) -> f a -> f b
这里,f
不是用作普通类型,而是用作类型构造函数,因此推断类型为* -> *
。您可以使用GHCi中的:kind
命令验证这一点:
> :kind Print
Print :: * -> Constraint
> :kind Functor
Functor :: (* -> *) -> Constraint
答案 1 :(得分:9)
当你说
时class Print a where
print' :: a -> String
您确保a
必须是一种类型,但是当您说
data A t = A t
您使A
成为类型构造函数 - A
不是类型,但例如A Int
。 A
是一种关于类型的函数,但Print类中的a
必须是类型值,而不是类型函数。
你可以做到
instance Print (A Int) where
print' a = "abc"
IO
没关系,因为Functor
类要求输入类型构造函数。
class Functor f where
fmap :: (a -> b) -> f a -> f b
您可以看到,由于f a
是一种类型,f
是一种类型构造函数,就像IO
和A
一样。
你将能够做到
instance Functor A where -- OK, A is a constructor, Functor needs one
fmap f (A x) = A (f x)
你将无法做到
instance Eq IO where -- not OK - IO is a constructor and Eq needs a type
(==) = error "this code won't compile"
(我使用了print'
代替print
来避免与标准函数print
发生冲突。)
答案 2 :(得分:1)
在心理上(或使用文本编辑器)尝试使用您在实例中使用的类型填写类定义中给出的类型。
自:
class Print a where
print :: a -> String
和
data A t = A t
我们想要
instance Print A
所以,在类型类定义中用a
替换A
我们说的是一个实例,我们得到了这个:
class Print A where
print :: A -> String
糟糕, A -> String
作为一种类型没有意义,因为函数类型箭头左侧是一个类型,右侧是一个类型,并为您提供函数类型。但A
不是类型,因为您使用A
声明了data A t
; A t
是任何类型t
的类型,但A
是类型构造函数。如果将它应用于类型,它可以创建一个类型,但A
本身是不同的。因此,您可以A t
成为Print
的实例,而不是A
本身。
为什么instance Functor IO
有效?让我们看一下类定义:
class Functor f where
fmap :: (a -> b) -> f a -> f b
现在让我们尝试用IO
代替f
:
class Functor IO where
fmap :: (a -> b) -> IO a -> IO b
IO
s最终应用于类型参数,因此一切正常。如果我们尝试将Int
或A t
这样的具体类型设为Functor
的实例,我们就会遇到问题。