我试图按照Gabriel Gonzalez 的文章进行操作,但遇到了类型不匹配的问题。考虑以下短模块:
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE Rank2Types #-}
module Yoneda where
newtype F a = F a deriving (Show, Functor)
type G f a = forall a'. (a -> a') -> f a'
fw :: Functor f => G f a -> f a
fw x = x id
bw :: Functor f => f a -> G f a
bw x = \f -> fmap f x
它编译得很好。(使用ghc
8.2.2 和 8.4.3。)但是当我在 repl 中戳它时,fw
不要bw
编写:
λ :t bw . fw
<interactive>:1:6: error:
• Couldn't match type ‘a’ with ‘G f a1’
‘a’ is a rigid type variable bound by
the inferred type of it :: Functor f => a -> (a1 -> a') -> f a'
at <interactive>:1:1
Expected type: a -> f a1
Actual type: G f a1 -> f a1
• In the second argument of ‘(.)’, namely ‘fw’
In the expression: bw . fw
当我仔细观察时bw
,它所采用和返回的函子的类型似乎是不同的:
λ :t bw
bw :: Functor f1 => f2 a1 -> (a2 -> a') -> f1 a'
— 即使我在类型签名中声明它们应该是相同的!无论我使用什么类型的注释fw
,bw
他们都不想统一。
如果我从中删除类型签名fw
,一切都会顺利进行。特别是,推断的类型签名将是:
fw :: ((a -> a) -> t) -> t
forall
因此,量词似乎破坏了事物。但我不明白为什么。它不应该意味着“任何类型a -> a'
都可以,包括a -> a
”?似乎相同的类型同义词在andG f a
的类型签名中以不同的方式起作用!fw
bw
这里发生了什么?
更多实验:
λ (fw . bw) (F 1)
...error...
λ (fw (bw (F 1)))
F 1
λ :t fw . undefined
...error...
λ :t undefined . fw
...error
λ :t bw . undefined
bw . undefined :: Functor f => a1 -> (a2 -> a') -> f a'
λ :t undefined . bw
undefined . bw :: Functor f => f a -> c
所以(正如@chi 在回答中指出的那样)任何函数都不能用fw
. 但对于bw
. 为什么?