Ответ 1
Я нахожу этот контрапункт: хотя ErrorT предположительно обматывает IO, похоже, что информация об ошибке была введена в тип результата действия IO.
Монад-трансформаторы вообще не "обертывают" монаду, к которой они применяются, по крайней мере, не в каком-либо очевидном смысле. Размышление об этом как о "обертывании" подразумевало бы функциональную композицию для моего разума, что конкретно не происходит здесь.
Чтобы проиллюстрировать, структура функтора для State s
и Maybe
с расширенными определениями будет выглядеть так:
newtype StateMaybe s a = StateMaybe (s -> (Maybe a, s)) -- == State s (Maybe a)
newtype MaybeState s a = MaybeState (Maybe (s -> (a, s))) -- == Maybe (State s a)
Обратите внимание, что в первом случае State
ведет себя нормально, а Nothing
не влияет на значение состояния; во втором случае мы либо имеем обычную функцию State
, либо ничего вообще. В любом случае характерное поведение двух монадов фактически не сочетается. Это не должно удивлять, поскольку, в конце концов, это то же самое, что и вы, просто имея значения, используя одну монаду как обычные значения, используемые в другом.
Сравните это с StateT s Maybe
:
newtype StateTMaybe s a = StateTMaybe (s -> Maybe (a, s))
В этом случае они сплетены вместе; все происходит обычным образом для State
, если мы не нажмем a Nothing
, и в этом случае вычисление будет прервано. Это принципиально отличается от вышеуказанных случаев, поэтому монады-трансформаторы даже существуют в первую очередь - составление их наивно не требует какой-либо специальной техники, потому что они работают независимо друг от друга.
Что касается определения того, какой из них находится на "вне", это может помочь подумать о "внешнем" трансформаторе как о том, чье поведение принимает "приоритет", в некотором смысле, когда имеет дело со значениями в монады, в то время как "внутренняя" монада видит бизнес как обычно. Обратите внимание, что именно поэтому IO
всегда является самым внутренним - он не позволяет чему-либо еще вставать в своем бизнесе, тогда как гипотетический трансформатор IOT
будет вынужден разрешить завернутой монаде тянуть все виды махинаций, например дублировать или отбрасывание токена RealWorld
.
-
StateT
иReaderT
обе кладут "внутреннюю" монаду вокруг результата функции; вам нужно предоставить значение состояния или среду, прежде чем попасть в преобразованную монаду. -
MaybeT
иErrorT
оба скользят внутрь внутри преобразованной монады, гарантируя, что она может вести себя обычным образом, за исключением того, что значение может отсутствовать. -
Writer
является полностью пассивным и просто присоединяется к значениям в монаде, поскольку он вообще не влияет на поведение. -
ContT
хранит вещи сам по себе, полностью отделяя преобразованную монаду, только обертывая тип результата.
Это немного волнообразные, но эхо-монадные трансформаторы, вроде бы, разборчивы и сбивают с толку, увы. Я не знаю, есть ли какое-то чистое теоретическое обоснование для конкретного выбора, кроме того, что они работают, и делать то, что вам обычно требуется, чтобы комбинация (а не состав) двух монадов.
Следовательно, мне трудно думать о том, что значит объединить одну монаду с другой, даже когда я не понимаю, что каждая монада означает индивидуально.
Да, это звучит как о том, чего ожидать, я боюсь.