按照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
的第二个定义中通过明确的模式匹配来解决错误吗?
答案 0 :(得分:10)
原因是即使您没有更改其中的值,您也会更改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
。
答案 1 :(得分:5)
你的问题是第三行:
fmap _ left = left
左侧的left
字词类型为Either a a1
,右侧的字词Either a b
类型为a1
。此外,b
和fmap
不会统一,因为Functor f => (a1 -> b) -> (f a1 -> f b)
的类型为(a1 -> b) -> (Either a a1) -> (Either a b)
,或者,特别是对于此实例,{{1}}。因此类型错误。