The s
将物体保留在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
好吧,这是一个类型错误(这是一件好事!我们不想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
已“逃”出forall
in runST
。类型变量总是必须出现在 a 的内部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
取决于布尔值是真还是假。这根本就是错误的,就像上面的例子一样ST
.
另一方面,如果你没有s
输入参数,那么所有内容都会进行类型检查,即使代码显然是非常伪造的。
ST的实际工作原理:在实施方面,ST
monad 实际上与IO
monad 但界面略有不同。当您使用ST
你实际上得到的单子unsafePerformIO
或同等的,在幕后。您可以安全地执行此操作的原因是因为所有的类型签名ST
- 相关功能,特别是与forall
.