ST monad如何工作? [英] How does the ST monad work?
问题描述
RealWorld
magic的状态monad。我可以描述状态,我可以看到RealWorld以某种方式放入IO中,但是每次我写一个类型签名 ST
s $ ST monad的c $ c>迷惑了我。
例如, ST s(STArray s a b)
。 s
如何在那里工作?它是否仅用于在计算之间建立一些仿真数据依赖关系,而不能像状态monad中的状态那样引用(由于 forall
)?
我只是抛出一些想法,并且非常感谢有人比我更懂得向我解释它。
解决方案 s
保持 ST
monad中的对象不会泄露到 ST
monad。 - 这是一个错误...但我们假装一会儿......
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 sa) - > a
这意味着 s
你正在运行的计算必须对它没有限制。因此,当您尝试评估 a
时:
a = runST(newSTRef (15 :: Int):: forall s。ST s(STRef s Int))
结果会有类型 STRef s Int
,这是错误的,因为 s
在<$ c $之外有转义 c> forall 在 runST
中。类型变量总是必须出现在 forall
内部,并且Haskell允许在每处都隐式地使用 forall
量词。没有什么规则可以让你有意义地找出 a
的返回类型。
另一个例如 forall
:为了清楚地说明为什么你不能让某些东西转义 forall
,这里是一个更简单的例子:
f ::(forall a。[a] - > b) - >布尔 - > b
f g flag =
if flag
then gabcd
else g [1,2]
> :t f长度
f长度::布尔 - > Int
> :tf id
- error -
当然 f id
是一个错误,因为它会返回 Char
列表或 Int $ c $取决于布尔值是true还是false。这是完全错误的,就像 ST
的例子。
另一方面,如果你没有 s
类型参数,那么所有类型的检查都会很好,即使代码显然很笨。
ST实际工作方式:实施方面, ST
monad实际上与 IO
monad,但接口略有不同。当您使用 ST
monad时,您实际上会在幕后获得 unsafePerformIO
或同等功能。您可以安全地执行此操作的原因是因为所有 ST
相关函数的类型签名,尤其是带有 forall $ c $的部分c>。
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.
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.
解决方案 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
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
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))
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
.
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 --
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
.
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.
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屋!
查看全文