ST参考是否透明?

时间:2017-11-19 20:06:25

标签: haskell

为什么ST旨在禁止使用以下代码as shown in the wikibook?如果允许的话,文章似乎暗示ST效果会泄漏到另一个ST,但我真的不明白为什么。

似乎我无法运行特定的ST s (STRef s a)ST效果是否包含且引用是否透明,但这种使用仍被视为无效?

Intuition告诉我,IOST的语义之间存在差异,因为有一个IO和许多独立的ST,但我不确定

> runST (newSTRef True)

<interactive>:5:8: error:
    • Couldn't match type ‘a’ with ‘STRef s Bool’
        because type variable ‘s’ would escape its scope
      This (rigid, skolem) type variable is bound by
        a type expected by the context:
          forall s. ST s a
        at <interactive>:5:1-21
      Expected type: ST s a
        Actual type: ST s (STRef s Bool)
    • In the first argument of ‘runST’, namely ‘(newSTRef True)’
      In the expression: runST (newSTRef True)
      In an equation for ‘it’: it = runST (newSTRef True)
    • Relevant bindings include it :: a (bound at <interactive>:5:1)

> :t newSTRef
newSTRef :: a -> ST s (STRef s a)

> :t runST
runST :: (forall s. ST s a) -> a

2 个答案:

答案 0 :(得分:7)

问题标题的答案多于问题本身,但仍然是:

是的,ST是引用透明的。

很长一段时间,这只是推测和相信,只有今年我们有适当的证据:

Monadic封装状态的逻辑关系:在runST存在的情况下证明上下文等价
Amin Timany,LéoStefanesco,Morten Krogh-Jespersen,Lars Birkedal
有条件地接受POPL 2018
http://iris-project.org/ Preprint PDF

答案 1 :(得分:6)

我真的不明白你在问什么,所以我要假装你的问题是:

  

为什么ST设计为不允许runST (newSTRef True)

如果允许,它将不再是引用透明的:

main = do
    let r = runST (newSTRef True)
    evaluate (runST (writeSTRef r False))
    print (runST (readSTRef r))

此代码将输出False

main = do
    evaluate (runST (writeSTRef (runST (newSTRef True)) False))
    print (runST (readSTRef (runST (newSTRef True))))

此代码(在每个用户中内联r的结果)将输出True,因为runST (newSTRef True)的每个实例都会分配一个新的STRef变量。

实际实施runST的方式可确保在ST s操作中分配的所有资源都无法逃脱该操作。

IOST s之间的区别在于没有runIO功能。您可以创建多个独立的IO操作,但如果没有runIO(它们只是值),它们就不重要了。实际运行IO操作的唯一方法是将其绑定到main并让运行时系统选择它(它就像那里的单个隐式runIO缠绕main),因此只有一个IO动作可以在程序中执行。

当然,这个单一动作可以通过组合多个较小的动作来组成,但最终它仍然是一个整体。另一方面,runST允许多个ST s操作独立执行。