Обработка Либо и ST монад - PullRequest
4 голосов
/ 20 марта 2019

Допустим, у меня есть следующие функции:

checkA :: a -> Either err b
checkA = undefined

checkB :: b -> ST s (Either err c)
checkB = undefined

check :: a -> ST s (Either err c)
check a = either (return . Left) checkB (checkA a)

Можно ли написать check так, чтобы не требовалось return . Left?Обычно я делал бы что-то вроде >>=, но в этом случае возвращаемое значение checkB заключено в другую монаду состояний, поэтому оно не работает.Другое ограничение заключается в том, что checkB должен запускаться только в том случае, если checkA a оценивается как Right, и должен просто не работать с ошибкой Left

В целом, существуют ли какие-либо стандартные подходы к использованию вложенных монад

1 Ответ

4 голосов
/ 20 марта 2019

Вот один из способов сделать это с ExceptT:

checkA :: a -> Either err b
checkA = undefined

checkB :: b -> ExceptT err (ST s) c
checkB = undefined

check :: a -> ExceptT err (ST s) c
check a = except (checkA a) >>= checkB
-- or
check = except . checkA >=> checkB

except превращает Either err b в Monad m => ExceptT err m b, а затем вы можете делать все остальное в монаде ExceptT err (ST s).

Как правило, ExceptT - отличный способ работать с монадическими действиями, которые могут завершиться неудачей, когда вы обычно хотите получить залог при неудаче. Основным исключением является случай, когда основной монадой является IO, и в этом случае более распространенным является использование встроенных функций исключений из Control.Exception.

Конечно, если вам нужна только одна монадная привязка, ExceptT выглядит как избыточное убийство, но как только вам нужно больше, это определенно имеет смысл.

...