为什么ST
旨在禁止使用以下代码as shown in the wikibook?如果允许的话,文章似乎暗示ST
效果会泄漏到另一个ST
,但我真的不明白为什么。
似乎我无法运行特定的ST s (STRef s a)
。 ST
效果是否包含且引用是否透明,但这种使用仍被视为无效?
Intuition告诉我,IO
和ST
的语义之间存在差异,因为有一个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
答案 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
操作中分配的所有资源都无法逃脱该操作。
IO
和ST s
之间的区别在于没有runIO
功能。您可以创建多个独立的IO
操作,但如果没有runIO
(它们只是值),它们就不重要了。实际运行IO
操作的唯一方法是将其绑定到main
并让运行时系统选择它(它就像那里的单个隐式runIO
缠绕main
),因此只有一个IO
动作可以在程序中执行。
当然,这个单一动作可以通过组合多个较小的动作来组成,但最终它仍然是一个整体。另一方面,runST
允许多个ST s
操作独立执行。