按照 Typeclassopedia 中的练习,我尝试为 Either 实现一个 Functor 实例。我的第一次尝试如下:
instance Functor (Either a) where
fmap f (Right a) = Right (f a)
fmap _ left = left
这会引发以下编译时错误:
functor.hs:7:17:
Couldn't match type ‘a1’ with ‘b’
‘a1’ is a rigid type variable bound by
the type signature for
fmap :: (a1 -> b) -> Either a a1 -> Either a b
at functor.hs:6:3
‘b’ is a rigid type variable bound by
the type signature for
fmap :: (a1 -> b) -> Either a a1 -> Either a b
at functor.hs:6:3
Expected type: Either a b
Actual type: Either a a1
Relevant bindings include
left :: Either a a1 (bound at functor.hs:7:10)
fmap :: (a1 -> b) -> Either a a1 -> Either a b
(bound at functor.hs:6:3)
In the expression: left
In an equation for ‘fmap’: fmap _ left = left
解决此问题的最简单方法是替换 fmap
的第二个定义,如下所示:
instance Functor (Either a) where
fmap f (Right a) = Right (f a)
fmap _ (Left a) = Left a
有人可以解释一下为什么在 fmap
的第二个定义中通过显式模式匹配来解决该错误吗?
最佳答案
原因是您正在更改 Left a
的类型,即使您没有更改其中的值。请注意,对于 Left 1::Either Int String
,fmap length (Left 1)
的类型为 Either Int Int
。尽管 Left 1
的值中只出现一个整数,但它的类型已更改,因为其他类型参数发生了更改。
这类似于以下情况:
> let x = [] :: [String]
> x == fmap length x
Couldn't match type ‘Int’ with ‘[Char]’
Expected type: [Char] -> String
Actual type: [Char] -> Int
In the first argument of ‘fmap’, namely ‘length’
In the second argument of ‘(==)’, namely ‘fmap length x’
尽管两个值都是空列表,但列表具有不同的类型。 x
的类型为 [String]
,fmap length x
的类型为 [Int]
。由于相等性的类型为 (==)::Eq a => a -> a -> Bool
,因此您会发现无法比较两个不同类型的值是否相等,因为它是相同的 a
。
关于haskell - 为 Either 编写 Functor 实例时类型不匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26563137/