Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swap inner and outer monads

How to convert StateT g (Either E) T to ExceptT E (StateT g Identity) T?

Probably, some mix of traverse and hoist could be useful here.

like image 768
ДМИТРИЙ МАЛИКОВ Avatar asked Jan 22 '17 21:01

ДМИТРИЙ МАЛИКОВ


1 Answers

You can't exchange an arbitrary pair of monads. But you can exchange these two particular monads. It's easiest to understand if you expand the newtypes in the definitions of those monad transformers.

Given

newtype StateT s m a = StateT { runStateT :: s -> m (s, a) }

and

newtype ExceptT e m a = ExceptT { runExceptT :: m (Either e a) }

expanding the newtypes in your first type expression gives us the isomorphism

StateT s (Either e) a   <->   s -> Either e (s, a)

whereas for the second we get

ExceptT e (StateT s Identity) a   <->   s -> (s, Either e a)

Note that Either e (s, a) may or may not contain an s, whereas (s, Either e a) always does. Now, one can go from the latter to the former just by traverseing the tuple inside the function, but going the other way requires some domain-specific reasoning: if the computation throws an error then we should plumb the state through unchanged to the catcher of the error. (Is this the right thing to do? I find it rather debatable.)

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
like image 105
Benjamin Hodgson Avatar answered Nov 07 '22 14:11

Benjamin Hodgson