为Either编写Functor实例时键入不匹配

时间:2014-10-25 13:52:28

标签: haskell

按照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的第二个定义中通过明确的模式匹配来解决错误吗?

2 个答案:

答案 0 :(得分:10)

原因是即使您没有更改其中的值,您也会更改Left a的类型。请注意,对于Left 1 :: Either Int Stringfmap 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。此外,bfmap不会统一,因为Functor f => (a1 -> b) -> (f a1 -> f b)的类型为(a1 -> b) -> (Either a a1) -> (Either a b),或者,特别是对于此实例,{{1}}。因此类型错误。