runST和函数组合

时间:2012-02-27 16:59:43

标签: haskell function-composition

为什么这个类型检查:

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

3 个答案:

答案 0 :(得分:47)

简短的回答是,类型推断并不总是适用于更高级别的类型。在这种情况下,它无法推断(.)的类型,但它会检查我们是否添加了显式类型注释:

> :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
     

在示例中,我们需要使用p实例化(forall s. ST s a),就是这样   impredicative polymorphism意味着:用a实例化一个类型变量   多态类型。

     

可悲的是,我知道没有任何合理复杂的系统可以进行类型检查   [这]没有帮助。有很多复杂的系统,我有   至少有两篇关于论文的共同作者,但他们都是太多   Jolly复杂地生活在GHC。我们确实有一个实现   boxy类型,但我在实现新的类型检查器时将其取出。   没有人理解它。

     

然而,人们经常写

runST $ do ... 
     

在GHC 7中我实现了一个特殊的输入规则,仅用于($)的中缀使用。只需将(f $ x)视为新的   句法形式,明显的打字规则,然后离开。

您的第二个示例失败,因为(.)没有此类规则。

答案 1 :(得分:34)

runST $ do { ... }模式是如此常见,并且它通常不会进行类型检查的事实是如此令人烦恼,GHC包含了一些ST特定的类型检查黑客以使其工作。这些黑客攻击可能是($)版本,而不是(.)版本。

答案 2 :(得分:3)

这些消息有点令人困惑(或者我觉得)。 让我重写你的代码:

runST (return True)   -- return True is ST s Bool
(runST . return) True  -- cannot work

另一种说法是单形m0 a0(返回的结果,如果得到a0)不能与(forall s.ST s a)统一。