交换内部和外部单子
Swap inner and outer monads
如何将StateT g (Either E) T
转换成ExceptT E (StateT g Identity) T
?
可能 traverse
和 hoist
的一些组合在这里很有用。
You can't exchange an arbitrary pair of monads。但是你可以交换这两个特定的单子。如果你在那些 monad 转换器的定义中扩展 newtype
s 是最容易理解的。
给定
newtype StateT s m a = StateT { runStateT :: s -> m (s, a) }
和
newtype ExceptT e m a = ExceptT { runExceptT :: m (Either e a) }
扩展第一个类型表达式中的 newtype
s 得到同构
StateT s (Either e) a <-> s -> Either e (s, a)
而第二次我们得到
ExceptT e (StateT s Identity) a <-> s -> (s, Either e a)
请注意 Either e (s, a)
可能包含也可能不包含 s
,而 (s, Either e a)
始终包含。现在,只需 traverse
ing 函数内部的元组,就可以从后者转到前者,但从另一种方式转到前者需要一些 domain-specific 推理:如果计算抛出错误,那么我们应该检测通过不变的状态到错误的捕捉器。 (这是正确的做法吗?我觉得这很值得商榷。)
stateTEitherToExceptTState :: (s -> Either e (s, a)) -> (s -> (s, Either e a))
stateTEitherToExceptTState f s =
case f s of
Left e -> (s, Left e)
Right sa -> fmap Right sa
如何将StateT g (Either E) T
转换成ExceptT E (StateT g Identity) T
?
可能 traverse
和 hoist
的一些组合在这里很有用。
You can't exchange an arbitrary pair of monads。但是你可以交换这两个特定的单子。如果你在那些 monad 转换器的定义中扩展 newtype
s 是最容易理解的。
给定
newtype StateT s m a = StateT { runStateT :: s -> m (s, a) }
和
newtype ExceptT e m a = ExceptT { runExceptT :: m (Either e a) }
扩展第一个类型表达式中的 newtype
s 得到同构
StateT s (Either e) a <-> s -> Either e (s, a)
而第二次我们得到
ExceptT e (StateT s Identity) a <-> s -> (s, Either e a)
请注意 Either e (s, a)
可能包含也可能不包含 s
,而 (s, Either e a)
始终包含。现在,只需 traverse
ing 函数内部的元组,就可以从后者转到前者,但从另一种方式转到前者需要一些 domain-specific 推理:如果计算抛出错误,那么我们应该检测通过不变的状态到错误的捕捉器。 (这是正确的做法吗?我觉得这很值得商榷。)
stateTEitherToExceptTState :: (s -> Either e (s, a)) -> (s -> (s, Either e a))
stateTEitherToExceptTState f s =
case f s of
Left e -> (s, Left e)
Right sa -> fmap Right sa