11

haskell 的 stm 库中有一个函数,其类型签名如下:

alwaysSucceeds :: STM a -> STM ()

根据我对 Haskell 中 STM 的了解,在执行 STM 计算时,有三种方式可能会“出错”(松散地使用该术语):

  1. 已读取的 TVar 的值被另一个线程更改。
  2. 违反了用户指定的不变量。这似乎通常是通过调用retry使其重新开始来触发的。这有效地使线程阻塞,然后在读取集中的 TVar 更改后重试。
  3. 抛出异常。调用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 ()

4

1 回答 1

8

的特殊效果alwaysSucceeds不是它如何在运行时检查故障(单独运行“不变”操作应该做同样的事情),而是它如何在事务结束时重新运行不变检查。

基本上,这个函数创建了一个用户指定的不变量,如上面的(2),它不仅现在必须保持,而且在以后的事务结束时也必须保持。

请注意,“事务”并不是指STMmonad 中的每个子操作,而是指传递给atomically.

我猜这a只是为了方便而被删除,因此您不必在将操作传递给之前将其转换为STM ()(例如 with ) 。无论如何,返回值对于以后的重复检查将毫无用处。voidalwaysSucceeds

于 2014-09-07T05:17:43.660 回答