Вот один из способов сделать это с 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
выглядит как избыточное убийство, но как только вам нужно больше, это определенно имеет смысл.