[英]How does the ST monad work?
I understand that the ST monad is something like a little brother of IO, which in turn is the state monad with added RealWorld
magic. 我知道ST monad就像是IO的小弟弟,而后者又是添加了
RealWorld
魔法的状态monad。 I can picture states and I can picture that RealWorld is somehow put into IO, but every time I write a type signature of ST
the s
of the ST monad confuses me. 我可以想象状态,我可以想象RealWorld以某种方式放入IO,但每次我写
ST
的类型签名时,ST monad的s
让我感到困惑。
Take, for example, ST s (STArray sab)
. 以
ST s (STArray sab)
为例。 How does the s
work there? 那里
s
工作怎么样? Is it just used to build up some artificial data dependency between computations without being able to be referenced like states in the state monad (due to the forall
)? 它是否仅用于在计算之间建立一些人为数据依赖性而不能像状态monad中的状态那样被引用(由于
forall
)?
I'm just throwing out ideas and would really appreciate someone more knowledgeable than I to explain it to me. 我只是抛出想法,真的很感谢比我更有知识的人向我解释。
The s
keeps objects inside the ST
monad from leaking to the outside of the ST
monad. 在
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
Okay, this is a type error (which is a good thing! we don't want STRef
to leak outside the original computation!). 好的,这是一个类型错误(这是一件好事!我们不希望
STRef
泄漏到原始计算之外!)。 It's a type error because of the extra s
. 由于额外的
s
这是一个类型错误。 Remember that runST
has the signature: 请记住,
runST
具有签名:
runST :: (forall s . ST s a) -> a
This means that the s
on the computation that you're running has to have no constraints on it. 这意味着您正在运行的计算中的
s
必须没有约束。 So when you try to evaluate a
: 所以,当你试图评估
a
:
a = runST (newSTRef (15 :: Int) :: forall s. ST s (STRef s Int))
The result would have type STRef s Int
, which is wrong since the s
has "escaped" outside of the forall
in runST
. 结果将具有类型
STRef s Int
,这是错误的,因为s
在runST
已经“逃逸”在forall
runST
。 Type variables always have to appear on the inside of a forall
, and Haskell allows implicit forall
quantifiers everywhere. 类型变量总是必须出现在
forall
的内部,而Haskell允许在任何地方使用隐式的forall
量词。 There's simply no rule that allows you to to meaningfully figure out the return type of a
. 根本没有规则允许你有意义地找出
a
的返回类型。
Another example with forall
: To clearly show why you can't allow things to escape a forall
, here is a simpler example: 与又如
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 --
Of course f id
is an error, since it would return either a list of Char
or a list of Int
depending on whether the boolean is true or false. 当然
f id
是一个错误,因为它将返回Char
列表或Int
列表,具体取决于布尔值是true还是false。 It's simply wrong, just like the example with ST
. 这是完全错误的,就像
ST
的例子一样。
On the other hand, if you didn't have the s
type parameter then everything would type check just fine, even though the code is obviously pretty bogus. 另一方面,如果你没有
s
类型参数,那么一切都会打字就好了,即使代码显然很伪造。
How ST actually works: Implementation-wise, the ST
monad is actually the same as the IO
monad but with a slightly different interface. ST实际上是如何工作的:实现方面,
ST
monad实际上与IO
monad相同,但界面略有不同。 When you use the ST
monad you actually get unsafePerformIO
or the equivalent, behind the scenes. 当你使用
ST
monad时,你实际上得到了unsafePerformIO
或等效的幕后。 The reason you can do this safely is because of the type signature of all ST
-related functions, especially the part with the forall
. 您可以安全地执行此操作的原因是因为所有
ST
相关函数的类型签名,尤其是具有forall
的部分。
The s
is just a hack that makes the type system stop you doing things which would be unsafe. s
只是一个黑客,它使类型系统阻止你做一些不安全的事情。 It doesn't "do" anything at run-time; 它在运行时没有“做”任何事情; it just makes the type checker reject programs that do dubious things.
它只是使类型检查器拒绝执行可疑事情的程序。 (It is a so-called phantom type , a thing with only exists in the type checker's head, and doesn't affect anything at run-time.)
(它是一种所谓的幻像类型 ,只存在于类型检查器的头部,并且在运行时不会影响任何内容。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.