double 类型的 Functor 定义被拒绝

double type Functor definition refused

为什么这个函子定义被拒绝?

data Second a b = Ok a b | Ko a b deriving (Show)

instance Functor (Second x) where
  fmap f (Ok a b ) = Ok (f a) b
  fmap f (Ko a b ) = Ko a (f b) 

get a lot of errors:

GHCi, version 8.0.1

main.hs:4:22: error:
    • Couldn't match type ‘b’ with ‘x’
      ‘b’ is a rigid type variable bound by
        the type signature for:
          fmap :: forall a b. (a -> b) -> Second x a -> Second x b
        at main.hs:4:3
      ‘x’ is a rigid type variable bound by
        the instance declaration at main.hs:3:10
      Expected type: Second x b
        Actual type: Second b a
    • In the expression: Ok (f a) b
      In an equation for ‘fmap’: fmap f (Ok a b) = Ok (f a) b
      In the instance declaration for ‘Functor (Second x)’
    • Relevant bindings include
        a :: x (bound at main.hs:4:14)
        f :: a -> b (bound at main.hs:4:8)
        fmap :: (a -> b) -> Second x a -> Second x b (bound at main.hs:4:3)
main.hs:4:28: error:
    • Couldn't match expected type ‘a’ with actual type ‘x’
      ‘x’ is a rigid type variable bound by
        the instance declaration at main.hs:3:10
      ‘a’ is a rigid type variable bound by
        the type signature for:
          fmap :: forall a b. (a -> b) -> Second x a -> Second x b
        at main.hs:4:3
    • In the first argument of ‘f’, namely ‘a’
      In the first argument of ‘Ok’, namely ‘(f a)’
      In the expression: Ok (f a) b
    • Relevant bindings include
        b :: a (bound at main.hs:4:16)
        a :: x (bound at main.hs:4:14)
        f :: a -> b (bound at main.hs:4:8)
        fmap :: (a -> b) -> Second x a -> Second x b (bound at main.hs:4:3)

这一切是什么意思?请帮忙。

如果你打开 Functor 的定义,你会看到 Second 的第一个参数保持不变,而它的第二个参数正在等待转换。

class Functor f where
  fmap :: (s -> t) -> f s -> f t

(我已将类型变量 ab 分别重命名为 st,因为您还有值变量 ab.)

那个 class 给了我们,在你的特定 instance

instance Functor (Second x) where
  -- fmap :: (s -> t) -> (Second x) s -> (Second x) t
  --    i.e. (s -> t) -> Second x s   -> Second x t

现在,当您实施 fmap 时,您必须确保 fmap 用户 可以选择任何 xst 他们想要的。所以你不能对它们做任何假设:它们代表任意的、可能不同的类型。这就是错误消息在谈论 "rigid" 类型变量时的意思:您的 代码不允许为它们选择特定类型,因此它的用户可以。编译器抱怨说你承诺了一个 非常多态的 函数,但提供了一个较少多态的函数,它只在 x=s=t.

时进行类型检查

也就是你写的时候

  fmap f (Ok a b) = Ok (f a) b

你有

f :: s -> t
Ok a b :: Second x s
a :: x
b :: s

你回来了

Ok (f a) b :: Second x t

需要

f a :: x   -- clearly not true, as f :: s -> t
b :: t     -- clearly not true, as b :: s

f a 需要

a :: s     -- clearly not true, as a :: x

所以,是的,有很多错误。

A Functor 实例允许您在对应于类型的 last 参数的位置转换数据,即 b in

data Second a b = Ok a b | Ko a b deriving (Show)

所以你的

  fmap f (Ko a b ) = Ko a (f b)

很好,但是你的

  fmap f (Ok a b ) = Ok (f a) b

命中不同参数的用法,但不正常。

  fmap f (Ok a b ) = Ok a (f b)

会起作用。将 data 声明更改为

data Second a b = Ok b a | Ko a b deriving (Show)

并让你的 instance 保持原样。

任一修复都有效,但不要同时执行这两个 "just to be on the safe side"!