ST monad是如何工作的?
我明白,ST monad就像IO的一个小兄弟,反过来也是joinRealWorld
魔法的状态monad。 我可以描绘出状态,我可以想象RealWorld是以某种方式投入到IO中的,但是每次我写ST
的types签名时,ST monad的s
让我困惑。
以ST s (STArray sab)
为例。 它在那里工作? 它只是用来在计算之间build立一些仿真数据依赖关系,而不能像状态monad中的状态那样引用(由于全部)?
我只是抛出想法,会非常感激比我更懂事的人向我解释。
ST
使ST
monad内部的物体不会泄漏到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
好的,这是一个types错误(这是一件好事!我们不希望STRef
在原始计算之外泄漏!)。 这是一个types错误,因为额外的s
。 请记住, runST
具有签名:
runST :: (forall s . ST sa) -> a
这意味着您正在运行的计算上的s
必须没有限制。 所以当你尝试评估a
:
a = runST (newSTRef (15 :: Int) :: forall s. ST s (STRef s Int))
结果将会有typesSTRef s Int
,这是错误的,因为s
在runST
之外已经“逃脱”了。 typesvariables总是必须出现在所有的内部,并且Haskell允许隐含的所有量词在任何地方。 没有什么规则可以让你有意义地找出a
的返回types。
forall
另一个例子:为了清楚地说明为什么你不能让事情逃脱一个forall
,这里是一个更简单的例子:
f :: (forall a. [a] -> b) -> Bool -> b fg flag = if flag then g "abcd" else g [1,2] > :tf length f length :: Bool -> Int > :tf id -- error --
当然f id
是一个错误,因为它会返回一个Char
列表或一个Int
列表,这取决于布尔值是true还是false。 这是错误的,就像ST
的例子。
另一方面,如果你没有s
types的参数,那么所有s
types都可以检查,即使代码显然是非常不正确的。
ST实际上是如何工作的:实施方面, ST
monad实际上与IO
monad相同,但是接口略有不同。 当你使用ST
monad时,你实际上会在幕后获得unsafePerformIO
或者其他等价物。 你可以安全地做这个事情的原因是所有ST
相关函数的types签名,尤其是所有与ST
相关的函数。
这只是一个黑客,使types系统阻止你做不安全的事情。 它在运行时不会“做”任何事情; 它只是使types检查器拒绝程序做可疑的事情。 (这是一种所谓的幻象types ,只存在于types检查器的头部,并且在运行时不会影响任何东西。)