docs для Control.Monad.Trans.Error
предоставляют этот пример объединения двух монад:
type ErrorWithIO e a = ErrorT e IO a
==> ErrorT (IO (Either e a))
Я нахожу этот контрапункт: даже если ErrorT
предположительно обертывает IO
, похоже, что информация об ошибке была введена в тип результата действия IO. Я ожидал, что это будет
==> ErrorT (Either e (IO a))
на основе обычного значения слова "wrap".
Чтобы сделать вещи более запутанными, StateT
выполняет некоторые из них:
type MyError e = ErrorT e Identity -- (see footnote)
type StateWithError s e a = StateT s (MyError e) a
==> StateT (s -> ErrorT (Either e (a, s)))
Тип состояния s
был введен в сторону Either
Right
, но весь Either
также был обернут в функцию.
Чтобы сделать вещи еще более запутанными, если монады объединены наоборот:
type ErrorWithState e s a = ErrorT e (State s) a
==> ErrorT (StateT (s -> (Either e a, s)))
"внешний" по-прежнему является функцией; он не создает нечто вроде Either e (s -> (a, s))
, где функция состояния вложена в тип ошибки.
Я уверен, что есть какая-то основная логическая последовательность для всего этого, но я не совсем это вижу. Следовательно, мне трудно думать о том, что значит объединить одну монаду с другой, даже когда я не понимаю, что каждая монада означает индивидуально.
Может кто-нибудь просветить меня?
( Сноска: Я составляю ErrorT
с Identity
, так что StateWithError
и ErrorWithState
совместимы друг с другом для иллюстративных целей. Обычно я просто использовал StateWithError s e a = StateT s (Either e) a
и отказаться от слоя ErrorT
.