haskell 的 stm 库中有一个函数,其类型签名如下:
alwaysSucceeds :: STM a -> STM ()
根据我对 Haskell 中 STM 的了解,在执行 STM 计算时,有三种方式可能会“出错”(松散地使用该术语):
- 已读取的 TVar 的值被另一个线程更改。
- 违反了用户指定的不变量。这似乎通常是通过调用
retry
使其重新开始来触发的。这有效地使线程阻塞,然后在读取集中的 TVar 更改后重试。 - 抛出异常。调用
throwSTM
会导致这种情况。这与前两个不同,因为事务不会重新启动。相反,错误被传播,或者使程序崩溃,或者被 IO monad 捕获。
如果这些是准确的(如果不是,请告诉我),我无法理解alwaysSucceeds
可能会做什么。该always
函数似乎是建立在它之上的,它似乎可以不写alwaysSucceeds
为:
--This is probably wrong
always :: STM Bool -> STM ()
always stmBool = stmBool >>= check
的文档alwaysSucceeds
说:
alwaysSucceeds 添加了一个新的不变量,当传递给 alwaysSucceeds、当前事务结束时以及每个后续事务结束时,该不变量必须为真。如果它在任何这些点失败,那么违反它的事务将被中止,并且由不变量引发的异常被传播。
但是由于参数是类型STM a
(多态 in a
),它不能使用事务返回的值用于决策的任何部分。因此,它似乎会寻找我之前列出的不同类型的故障。但那有什么意义呢?STM monad 已经处理了失败。将它包装在这个函数中会如何影响它?为什么类型的变量a
会被删除,导致STM ()
?