双类型Functor定义被拒绝

Mau*_*ira -2 haskell types compiler-errors functor

为什么这个算符定义被拒绝了?

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

收到很多错误:

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

这是什么意思呢?请帮忙.

pig*_*ker 6

如果解压缩你的定义,Functor你会看到Second第一个参数保持不变,而第二个参数是转换参数.

class Functor f where
  fmap :: (s -> t) -> f s -> f t
Run Code Online (Sandbox Code Playgroud)

(在那里我已经改名类型变量abst分别,因为你也有值的变量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
Run Code Online (Sandbox Code Playgroud)

现在,当你实现fmap,你必须确保该用户fmap可以任意选择x,st他们想要的.所以你不必对它们做任何假设:它们代表任意的,可能是不同的类型.这就是错误消息在谈论"严格"类型变量时的意思:您的代码不允许为它们选择特定类型,以便其用户可以.编译器抱怨你承诺一个非常多态的函数,但是提供一个不那么多态的函数,只有在什么时候才会出现x=s=t.

也就是说,当你写作

  fmap f (Ok a b) = Ok (f a) b
Run Code Online (Sandbox Code Playgroud)

你有

f :: s -> t
Ok a b :: Second x s
a :: x
b :: s
Run Code Online (Sandbox Code Playgroud)

你回来了

Ok (f a) b :: Second x t
Run Code Online (Sandbox Code Playgroud)

这需要

f a :: x   -- clearly not true, as f :: s -> t
b :: t     -- clearly not true, as b :: s
Run Code Online (Sandbox Code Playgroud)

这里f a需要

a :: s     -- clearly not true, as a :: x
Run Code Online (Sandbox Code Playgroud)

所以,是的,很多错误.

一个Functor实例让你在与该类型相应的位置变换数据最后的参数,即b

data Second a b = Ok a b | Ko a b deriving (Show)
Run Code Online (Sandbox Code Playgroud)

所以你的

  fmap f (Ko a b ) = Ko a (f b)
Run Code Online (Sandbox Code Playgroud)

很好,但你的

  fmap f (Ok a b ) = Ok (f a) b
Run Code Online (Sandbox Code Playgroud)

点击使用不同的参数,但不行.

  fmap f (Ok a b ) = Ok a (f b)
Run Code Online (Sandbox Code Playgroud)

会工作.正如将data声明改为

data Second a b = Ok b a | Ko a b deriving (Show)
Run Code Online (Sandbox Code Playgroud)

然后离开你的instance原样.

要么修复工作,但不要两者兼顾"只是为了安全起见"!