runST和函数组成
为什么这个types检查:
runST $ return $ True
虽然以下不:
runST . return $ True
GHCI抱怨:
Couldn't match expected type `forall s. ST s c0' with actual type `m0 a0' Expected type: a0 -> forall s. ST s c0 Actual type: a0 -> m0 a0 In the second argument of `(.)', namely `return' In the expression: runST . return
简而言之,types推断并不总是适用于更高级的types。 在这种情况下,它不能推断(.)
的types,但是它会检查是否添加显式types注释:
> :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
如果我们用自己的版本replace($)
,第一个例子也会出现同样的问题:
> let app fx = fx > :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)'
再次,这可以通过添加types注释来解决:
> :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中有一个特殊的input规则,它只适用于标准($)
操作符。 Simon Peyton-Jones 在GHC用户邮件列表的答复中解释了这种行为:
这是types推断的一个激励范例,可以处理impandicativetypes。 考虑
($)
的types:($) :: forall p q. (p -> q) -> p -> q
在这个例子中,我们需要实例化
(forall s. ST sa)
s。ST(forall s. ST sa)
,这就是impressiveic polymorphism的意思:实例化一个具有多态types的typesvariables。可悲的是,我知道没有合理的复杂性系统可以单独检查[this]。 有很多复杂的系统,我至less在两篇文章上合作过,但都过于复杂,生活在GHC中。 我们确实有一个boxytypes的实现,但是在实现新的types检查器时我拿出来了。 没有人明白这一点。
但是,人们经常写作
runST $ do ...
在GHC 7中,我实现了一个特殊的input规则,仅用于
($)
缀使用。 只要把(f $ x)
看作一种新的语法forms,用明显的键入规则就可以了。
你的第二个例子失败,因为(.)
没有这样的规则。
runST $ do { ... }
模式非常常见,而且通常不会进行types检查的事实非常令人讨厌,所以GHC包含了一些ST
特定的types检查黑客来使其工作。 这些黑客可能在这里为($)
版本,但不是(.)
版本。
这些信息有点混乱(或者我觉得)。 让我重写你的代码:
runST (return True) -- return True is ST s Bool (runST . return) True -- cannot work
另一种说法是单态m0 a0
(返回的结果,如果得到a0)不能与(s.ST sa)统一。