RankNTypes和点运算符

时间:2015-07-25 13:46:34

标签: haskell

当我使用RankNTypes时,似乎(。)运算符效果不佳。这个限制在哪里记录?

{-# LANGUAGE RankNTypes, ImpredicativeTypes #-}

f :: Int -> (forall r. r -> r)
f = undefined

g :: (forall r. r -> r) -> Int
g = undefined

h :: Int -> Int
-- h v = g (f v) -- It works well
h = g . f -- I can't write it in this way

我收到以下错误。

[1 of 1] Compiling Main             ( test.hs, interpreted )

test.hs:11:9:
    Couldn't match type ‘r0 -> r0’ with ‘forall r. r -> r’
    Expected type: Int -> forall r. r -> r
      Actual type: Int -> r0 -> r0
    In the second argument of ‘(.)’, namely ‘f’
    In the expression: g . f
Failed, modules loaded: none.

1 个答案:

答案 0 :(得分:11)

实际上,f没有类型Int -> (forall r. r -> r),因为GHC floats out每个forall和类约束到范围的顶部。所以f的类型确实是forall r. Int -> r -> r

例如,以下类型检查:

f :: Int -> (forall r. r -> r)
f = undefined

f' :: forall r. Int -> r -> r
f' = f

这会导致g . f合成错误(我们可以看到错误消息明确指出r -> rforall r. r -> r之间的差异。)

GHC在错误的地方找到forall - s时会抛出错误,而不是默默地将它们浮出来,这可能是更好的行为。

在GHC中不允许多态返回类型(浮出forall - s)禁止的原因有多种。有关详细信息,请参阅this paper(具体见4.6节)。简而言之,只有在GHC缺乏的预测性实例化方面有坚实的支持时,它们才有意义。在没有impredicative类型的情况下,浮出允许更多的术语进行类型检查,并且很少在现实世界的代码中造成不便。