这加载没有错误:
data Const c a = Const c
instance Functor (Const c) where
fmap _ (Const v) = Const v
Run Code Online (Sandbox Code Playgroud)
...但是这个
data Const' c a = Const' c
instance Functor (Const' c) where
fmap _ cv = cv
Run Code Online (Sandbox Code Playgroud)
......失败了:
Couldn't match type `a' with `b'
`a' is a rigid type variable bound by
the type signature for fmap :: (a -> b) -> Const' c a -> Const' c b
at test.hs:4:5
`b' is a rigid type variable bound by
the type signature for fmap :: (a -> b) -> Const' c a -> Const' c b
at test.hs:4:5
Expected type: Const' c b
Actual type: Const' c a
In the expression: cv
In an equation for `fmap': fmap _ cv = cv
In the instance declaration for `Functor (Const' c)'
Run Code Online (Sandbox Code Playgroud)
我不明白这个错误.为什么不能编译器推断类型cv
是Const' c
?鉴于声明的其余部分以及fmap
?的定义,还有什么呢?
如果你想完全明确,你可以写
{-# LANGUAGE ScopedTypeVariables, InstanceSigs #-}
data Const c a = Const c
instance Functor (Const c) where
fmap :: forall a b. (a -> b) -> Const c a -> Const c b
fmap _ (Const v :: Const c a) = Const v :: Const c b
Run Code Online (Sandbox Code Playgroud)
这有点拗口.:-)
forall a b.
带来a
并b
进入范围,以便在定义中引用它们.这是通过ScopedTypeVariables
. InstanceSigs
允许我们首先编写签名fmap
(通常必须从类中推断出来,因此我们无处可从中获取类型变量名称).
cv
是类型Const' c a
,所以它也不能是类型Const' c b
(除非a ~ b
).Const v
并且Const v
,但是,可以是不同类型的.
另一种看待它的方式fmap _ cv = cv
是等同于fmap _ = id
,它必须是类型Const' c a -> Const' c a
,但fmap _
必须是类型Const' c a -> Const' c b
.