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

frm*_*frm 6 haskell

在Typeclassopedia中练习之后,我尝试为Either实现一个Functor实例.我的第一次尝试如下:

instance Functor (Either a) where
  fmap f (Right a) = Right (f a)
  fmap _ left = left
Run Code Online (Sandbox Code Playgroud)

这会引发以下编译时错误:

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
Run Code Online (Sandbox Code Playgroud)

解决此问题的最简单方法是替换第二个定义,fmap如下所示:

instance Functor (Either a) where
  fmap f (Right a) = Right (f a)
  fmap _ (Left a) = Left a
Run Code Online (Sandbox Code Playgroud)

有人可以解释为什么错误是通过在第二个定义中明确模式匹配来解决的fmap吗?

bhe*_*ilr 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’
Run Code Online (Sandbox Code Playgroud)

即使两个值都是空列表,列表也有不同的类型. x有类型[String]fmap length x类型[Int].由于等式具有类型(==) :: Eq a => a -> a -> Bool,因此您看到无法比较两种不同类型的值是否相等,因为它们是相同的a.


pyo*_*yon 5

你的问题是第三行:

fmap _ left = left
Run Code Online (Sandbox Code Playgroud)

left左侧的术语有类型Either a a1,右侧有预期的类型Either a b.此外,a1并且b不期望统一,因为类型fmapFunctor f => (a1 -> b) -> (f a1 -> f b),或者,特别是对于这种情况(a1 -> b) -> (Either a a1) -> (Either a b).因此类型错误.