当我使用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.
答案 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 -> r
和forall r. r -> r
之间的差异。)
GHC在错误的地方找到forall
- s时会抛出错误,而不是默默地将它们浮出来,这可能是更好的行为。
在GHC中不允许多态返回类型(浮出forall
- s)禁止的原因有多种。有关详细信息,请参阅this paper(具体见4.6节)。简而言之,只有在GHC缺乏的预测性实例化方面有坚实的支持时,它们才有意义。在没有impredicative类型的情况下,浮出允许更多的术语进行类型检查,并且很少在现实世界的代码中造成不便。