В библиотеке stm haskell есть функция со следующей сигнатурой типа:
alwaysSucceeds :: STM a -> STM ()
Из того, что я понимаю о STM в haskell, есть три способа, которыми что-то может «пойти не так» (используя этот термин в широком смысле) во время выполнения вычисления STM:
- Значение прочитанного TVar изменяется другим потоком.
- Указанный пользователем инвариант нарушен. Обычно это вызывается вызовом
retry
, чтобы начать сначала. Это эффективно блокирует поток, а затем повторяет попытку после изменения TVar в наборе чтения. - Выбрасывается исключение. Вызов
throwSTM
вызывает это. Этот отличается от первых двух тем, что транзакция не перезапускается. Вместо этого ошибка распространяется и либо приводит к сбою программы, либо перехватывается монадой IO.
Если они точны (а если нет, пожалуйста, скажите мне), я не могу понять, что alwaysSucceeds
мог сделать. Функция always
, которая, кажется, построена поверх нее, похоже, может быть написана без alwaysSucceeds
как:
--This is probably wrong
always :: STM Bool -> STM ()
always stmBool = stmBool >>= check
В документации для alwaysSucceeds
говорится:
alwaysSucceeds добавляет новый инвариант, который должен быть истинным при передаче в alwaysSucceeds, в конце текущей транзакции и в конце каждой последующей транзакции. Если он терпит неудачу в любой из этих точек, то транзакция, нарушающая его, прерывается, и распространяется исключение, вызванное инвариантом.
Но поскольку аргумент имеет тип STM a
(полиморфный в a
), он не может использовать значение, возвращаемое транзакцией, ни для какой части процесса принятия решения. Итак, похоже, что он будет искать различные типы сбоев, которые я перечислил ранее. Но какой в этом смысл? Монада STM уже обрабатывает сбои. Как повлияет на это обертывание этой функцией? И почему переменная типа a
отбрасывается, что приводит к STM ()
?