假设我们有一些这样的代码,它的类型检查很好:
{-# LANGUAGE RankNTypes #-}
data Foo a
type A a = forall m. Monad m => Foo a -> m ()
type PA a = forall m. Monad m => Foo a -> m ()
type PPFA a = forall m. Monad m => Foo a -> m ()
_pfa :: PPFA a -> PA a
_pfa = _pfa
_pa :: PA a -> A a
_pa = _pa
_pp :: PPFA a -> A a
_pp x = _pa $ _pfa x
main :: IO ()
main = putStrLn "yay"
我们注意到这_pp x = _pa $ _pfa x
太冗长了,我们尝试将其替换为_pp = _pa . _pfa
. 突然代码不再进行类型检查,失败并出现类似的错误消息
• Couldn't match type ‘Foo a0 -> m0 ()’ with ‘PA a’
Expected type: (Foo a0 -> m0 ()) -> Foo a -> m ()
Actual type: PA a -> A a
我猜这是因为m
类型别名的定义是forall
'd —— 实际上,用m
一些确切的类型替换可以解决问题。但问题是:为什么forall
在这种情况下会破坏事物?
试图弄清楚为什么用GHC 抱怨统一变量和暗示性多态性的通常结果替换虚拟递归定义的_pfa
加分点:_pa
_pfa = undefined
• Cannot instantiate unification variable ‘a0’
with a type involving foralls: PPFA a -> Foo a -> m ()
GHC doesn't yet support impredicative polymorphism
• In the expression: undefined
In an equation for ‘_pfa’: _pfa = undefined