[英]How does the ST monad work?
我知道ST monad就像是IO的小弟弟,而后者又是添加了RealWorld
魔法的状态monad。 我可以想象状态,我可以想象RealWorld以某种方式放入IO,但每次我写ST
的类型签名时,ST monad的s
让我感到困惑。
以ST s (STArray sab)
为例。 那里s
工作怎么样? 它是否仅用于在计算之间建立一些人为数据依赖性而不能像状态monad中的状态那样被引用(由于forall
)?
我只是抛出想法,真的很感谢比我更有知识的人向我解释。
在s
保持内部的物体ST
单子泄露到外面ST
单子。
-- This is an error... but let's pretend for a moment...
let a = runST $ newSTRef (15 :: Int)
b = runST $ writeSTRef a 20
c = runST $ readSTRef a
in b `seq` c
好的,这是一个类型错误(这是一件好事!我们不希望STRef
泄漏到原始计算之外!)。 由于额外的s
这是一个类型错误。 请记住, runST
具有签名:
runST :: (forall s . ST s a) -> a
这意味着您正在运行的计算中的s
必须没有约束。 所以,当你试图评估a
:
a = runST (newSTRef (15 :: Int) :: forall s. ST s (STRef s Int))
结果将具有类型STRef s Int
,这是错误的,因为s
在runST
已经“逃逸”在forall
runST
。 类型变量总是必须出现在forall
的内部,而Haskell允许在任何地方使用隐式的forall
量词。 根本没有规则允许你有意义地找出a
的返回类型。
与又如forall
:为了清楚地说明为什么你不能让事情逃脱forall
,这里是一个简单的例子:
f :: (forall a. [a] -> b) -> Bool -> b
f g flag =
if flag
then g "abcd"
else g [1,2]
> :t f length
f length :: Bool -> Int
> :t f id
-- error --
当然f id
是一个错误,因为它将返回Char
列表或Int
列表,具体取决于布尔值是true还是false。 这是完全错误的,就像ST
的例子一样。
另一方面,如果你没有s
类型参数,那么一切都会打字就好了,即使代码显然很伪造。
ST实际上是如何工作的:实现方面, ST
monad实际上与IO
monad相同,但界面略有不同。 当你使用ST
monad时,你实际上得到了unsafePerformIO
或等效的幕后。 您可以安全地执行此操作的原因是因为所有ST
相关函数的类型签名,尤其是具有forall
的部分。
s
只是一个黑客,它使类型系统阻止你做一些不安全的事情。 它在运行时没有“做”任何事情; 它只是使类型检查器拒绝执行可疑事情的程序。 (它是一种所谓的幻像类型 ,只存在于类型检查器的头部,并且在运行时不会影响任何内容。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.