ST monad 是如何工作的? [英] How does the ST monad work?
问题描述
我知道 ST monad 有点像 IO 的小兄弟,而 IO 又是添加了 RealWorld
魔法的状态 monad.我可以想象状态,我可以想象 RealWorld 以某种方式放入 IO,但是每次我编写 ST
的类型签名时,ST monad 的 s
都会让我感到困惑.
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. 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.
以ST s (STArray s a b)
为例.s
在那里如何工作?它是否只是用于在计算之间建立一些人工数据依赖性,而不能像状态 monad 中的状态一样被引用(由于 forall
)?
Take, for example, ST s (STArray s a b)
. How does the s
work there? 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
)?
我只是提出一些想法,非常感谢比我知识渊博的人向我解释.
I'm just throwing out ideas and would really appreciate someone more knowledgeable than I to explain it to me.
推荐答案
s
保持 ST
monad 内的对象不会泄漏到 ST 的外部
单子.
The s
keeps objects inside the ST
monad from leaking to the outside of the ST
monad.
-- 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
有签名:
Okay, this is a type error (which is a good thing! we don't want STRef
to leak outside the original computation!). It's a type error because of the extra s
. Remember that runST
has the signature:
runST :: (forall s . ST s a) -> a
这意味着您正在运行的计算中的 s
必须没有约束.因此,当您尝试评估 a
时:
This means that the s
on the computation that you're running has to have no constraints on it. So when you try to evaluate a
:
a = runST (newSTRef (15 :: Int) :: forall s. ST s (STRef s Int))
结果将具有 STRef s Int
类型,这是错误的,因为 s
已转义"到 forall
之外的 >runST
.类型变量总是必须出现在 forall
的内部,而 Haskell 允许在任何地方使用隐式的 forall
量词.没有任何规则可以让您有意义地找出 a
的返回类型.
The result would have type STRef s Int
, which is wrong since the s
has "escaped" outside of the forall
in runST
. Type variables always have to appear on the inside of a forall
, and Haskell allows implicit forall
quantifiers everywhere. There's simply no rule that allows you to to meaningfully figure out the return type of a
.
forall
的另一个例子: 为了清楚地说明为什么不能让事物逃脱 forall
,这里有一个更简单的例子:
Another example with forall
: To clearly show why you can't allow things to escape a forall
, here is a simpler example:
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
列表,这取决于布尔值是真还是假.简直是错误的,就像带有ST
的例子一样.
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. It's simply wrong, just like the example with ST
.
另一方面,如果您没有 s
类型参数,那么一切都会很好地进行类型检查,即使代码显然很假.
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.
ST 的实际工作原理: 在实现方面,ST
monad 实际上与 IO
monad 相同,但接口略有不同.当您使用 ST
monad 时,您实际上会在幕后获得 unsafePerformIO
或等效物.之所以可以安全地做到这一点,是因为所有 ST
相关函数的类型签名,尤其是带有 forall
的部分.
How ST actually works: Implementation-wise, the ST
monad is actually the same as the IO
monad but with a slightly different interface. When you use the ST
monad you actually get unsafePerformIO
or the equivalent, behind the scenes. 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 monad 是如何工作的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!