6

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.

  • 2
    When `StateT g (Either e) t` fails, it doesn't provide any state. What should the corresponding `ExceptT e (StateT g Identity) t` do? – danidiaz Jan 22 '17 at 22:06
  • I can't recall the exact definitions, but can't the first monad fail depending on the state (e.g. if the state is an even number), when the second one can not? – chi Jan 22 '17 at 22:09

1 Answers1

11

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
Community
  • 1
  • 1
Benjamin Hodgson
  • 42,952
  • 15
  • 108
  • 157
  • 1
    I think `stateTEitherToExceptTState` is not a valid monad morphism. If `m` is an action that doesn't fail, and `f` a Kleisli arrow that always fails, `morph (m >>= f)` is not equal to `morph m >= morph . f`. – danidiaz Jan 23 '17 at 19:55