Haskell STM总是会成功
Haskell的stm库中有一个函数,它具有以下类型的签名:
alwaysSucceeds :: STM a -> STM ()
根据我对haskell中STM的理解,在执行STM计算时,有三种方式可能“出错”(松散地使用该术语):
retry
来retry
启动来触发。 这有效地使线程阻塞,然后在读取集中的TVar改变后重试。 throwSTM
导致这一点。 这与前两个不同,因为事务不会重新启动。 相反,该错误会传播并导致程序崩溃或陷入IO monad中。 如果这些都是准确的(如果它们不是,请告诉我),我不明白什么alwaysSucceeds
可能做的。 always
功能,似乎是建立在它的上面,看起来好像它可以写成没有alwaysSucceeds
的:
--This is probably wrong
always :: STM Bool -> STM ()
always stmBool = stmBool >>= check
alwaysSucceeds
的文档说:
alwaysSucceeds添加了一个新的不变量,在传递给alwaysSucceeds时,在当前事务结束时以及在每个后续事务结束时都必须为true。 如果它在任何这些点上失败,那么违反它的事务将被中止,并且由不变量引发的异常将被传播。
但由于参数的类型为STM a
(多态a
),它不能使用该交易的决策的任何部分返回值。 所以,它似乎在寻找我之前列出的不同类型的故障。 但是,这有什么意义呢? STM monad已经处理了这些故障。 如何将它包裹在这个函数中影响它呢? 为什么类型a
的变量会丢失,导致STM ()
?
alwaysSucceeds
的特殊效果并不是它在它运行的地方检查失败(运行“不变”操作本身应该做同样的事情),而是它如何在事务结束时重新执行不变检查。
基本上,这个函数创建了一个用户指定的不变量,如上面(2)所示,它不得不保持在现在,而且还在后面的事务结束时。
请注意,“交易”不是指STM
monad中的每一个子动作,而是指以atomically
方式传递的组合动作。
为了方便起见,我认为a
被放弃了,所以在将它传递给alwaysSucceeds
之前,你不必将一个动作转换成STM ()
(例如用void
)。 无论如何,返回值对于稍后的重复检查都是无用的。