简短的回答是类型推断并不总是适用于更高级别的类型。在这种情况下,它无法推断(.) 的类型,但它会检查我们是否添加了显式类型注释:
> :m + Control.Monad.ST
> :set -XRankNTypes
> :t (((.) :: ((forall s0. ST s0 a) -> a) -> (a -> forall s1. ST s1 a) -> a -> a) runST return) $ True
(((.) :: ((forall s0. ST s0 a) -> a) -> (a -> forall s1. ST s1 a) -> a -> a) runST return) $ True :: Bool
如果我们将 ($) 替换为我们自己的版本,您的第一个示例也会出现同样的问题:
> let app f x = f x
> :t runST `app` (return `app` True)
<interactive>:1:14:
Couldn't match expected type `forall s. ST s t0'
with actual type `m0 t10'
Expected type: t10 -> forall s. ST s t0
Actual type: t10 -> m0 t10
In the first argument of `app', namely `return'
In the second argument of `app', namely `(return `app` True)'
同样,这可以通过添加类型注释来解决:
> :t (app :: ((forall s0. ST s0 a) -> a) -> (forall s1. ST s1 a) -> a) runST (return `app` True)
(app :: ((forall s0. ST s0 a) -> a) -> (forall s1. ST s1 a) -> a) runST (return `app` True) :: Bool
这里发生的情况是 GHC 7 中有一个特殊的键入规则,它仅适用于标准的 ($) 运算符。 Simon Peyton-Jones 在a reply on the GHC users mailing list 中解释了这种行为:
这是一个可以处理类型推断的激励示例
谓语类型。考虑($)的类型:
($) :: forall p q. (p -> q) -> p -> q
在示例中,我们需要用(forall s. ST s a) 实例化p,这就是
指示性多态性意味着:实例化一个类型变量
多态类型。
遗憾的是,我知道没有可以进行类型检查的合理复杂系统
[这] 没有帮助。有很多复杂的系统,我有
是至少两篇论文的合著者,但他们都是太
Jolly 住在 GHC 很复杂。我们确实有一个实施
四四方方的类型,但我在实现新的类型检查器时把它拿出来了。
没人明白。
然而,人们经常写作
runST $ do ...
在 GHC 7 中我实现了一个特殊的类型规则,仅用于 ($) 的中缀使用。只需将(f $ x) 视为一个新的
句法形式,带有明显的打字规则,然后就可以了。
您的第二个示例失败,因为(.) 没有这样的规则。