haskell - 为 Either 编写 Functor 实例时类型不匹配

标签 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 的第二个定义中通过显式模式匹配来解决该错误吗?

最佳答案

原因是您正在更改 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

关于haskell - 为 Either 编写 Functor 实例时类型不匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26563137/

相关文章:

haskell - 尝试更好地理解 Haskell 中应用仿函数的 (<*>) 函数

haskell - 检查字符串是否包含某个字符

haskell - 函数式编程语言中的调用站点代码替换

haskell - 安装 System.FilePath.Find 时遇到问题

haskell - 查找作为类型类实例的所有类型

haskell - 没有 Prelude 的 ghci session

haskell - Haskell 的隐藏功能

haskell - 自然数作为递归数据类型

haskell - 在惰性函数式语言的模板实例化求值器中实现 `case` 表达式有困难吗?

haskell - 修复 HList 中的类型推断