There is a function in haskell's stm library with the following type signature:
alwaysSucceeds :: STM a -> STM ()
From what I understand of STM in haskell, there are three ways that something can "go wrong" (using that term loosely) while an STM computation is executing:
- The value of an TVar that has been read is changed by another thread.
- An user-specified invariant is violated. This seems to usually be triggered by calling
retry
to make it start over. This effectively makes the thread block and then retry once a TVar in the read set changes. - An exception is thrown. Calling
throwSTM
causes this. This one differs from the first two because the transaction doesn't get restarted. Instead, the error is propagated and either crashes the program or is caught in the IO monad.
If these are accurate (and if they are not, please tell me), I can't understand what alwaysSucceeds
could possibly do. The always
function, which appears to be built on top of it, seems like it could be written without alwaysSucceeds
as:
--This is probably wrong
always :: STM Bool -> STM ()
always stmBool = stmBool >>= check
The documentation for alwaysSucceeds
says:
alwaysSucceeds adds a new invariant that must be true when passed to alwaysSucceeds, at the end of the current transaction, and at the end of every subsequent transaction. If it fails at any of those points then the transaction violating it is aborted and the exception raised by the invariant is propagated.
But since the argument is of type STM a
(polymorphic in a
), it can't use the value that the transaction returns for any part of the decision making. So, it seems like it would be looking for the different types of failures that I listed earlier. But what's the point of that? The STM monad already handles the failures. How would wrapping it in this function affect it? And why does the variable of type a
get dropped, resulting in STM ()
?