我知道ST monad就像是IO的小兄弟,后者又是状态monad,增加了 RealWorld
魔法 . 我可以想象状态,我可以想象RealWorld以某种方式放入IO,但每次我写一个 ST
的类型签名时,ST monad的 s
都会让我困惑 .
举个例子, ST s (STArray s a b)
. s
如何在那里工作?它是否仅用于在计算之间 Build 一些人为数据依赖性而不能像状态monad中的状态那样被引用(由于 forall
)?
我只是抛出想法,真的很感谢比我更有知识的人向我解释 .
2 回答
s
使ST
monad中的对象不会泄漏到ST
monad的外部 .好的,这是一个类型错误(这是一件好事!我们不希望
STRef
在原始计算之外泄漏!) . 由于额外的s
,这是一个类型错误 . 请记住runST
有签名:这意味着您正在运行的计算上的
s
必须没有约束 . 所以当你尝试评估a
时:结果将具有类型
STRef s Int
,这是错误的,因为s
在runST
中的forall
之外具有"escaped" . 类型变量总是必须出现在forall
的内部,而Haskell允许隐含的forall
量词 . 根本没有规则可以让你有意义地找出a
的返回类型 .Another example with forall: 为了清楚地说明为什么你不能让事情逃脱
forall
,这里有一个更简单的例子:当然
f id
是一个错误,因为它将返回Char
列表或Int
列表,具体取决于布尔值是true还是false . 这是完全错误的,就像ST
的例子一样 .On the other hand, 如果你没有
s
类型参数那么一切都会打字就好了,即使代码显然很伪造 .How ST actually works: 实现方面,
ST
monad实际上与IO
monad相同,但界面略有不同 . 当你使用ST
monad时,你实际上得到unsafePerformIO
或等效的幕后 . 您可以安全地执行此操作的原因是因为所有ST
相关函数的类型签名,尤其是具有forall
的部分 .s
只是一个黑客,它使类型系统阻止你做一些不安全的事情 . 它在运行时没有任何东西;它只是使类型检查器拒绝执行可疑事情的程序 . (它是一种所谓的幻像类型,只存在于类型检查器中的事物's head, and doesn' t在运行时影响任何东西 . )