evalState in a monad transformer stack

282 Views Asked by At

Given a mtl monad stack, e.g. ExceptT String (WriterT String (State s a)), how can I evaluate the inner state monad without needing to unwrap the outer monads?

have :: ExceptT String (WriterT String (State s)) a
f    :: State s a -> a

want :: ExceptT String (WriterT String Identity) a

I can do this by calling runExceptT followed by runWriterT and repacking the results afterward but it seems like the wrong way to accomplish this.


As far as I tried, something like fmap or similar won't work because the monad transformer stack is treated as an entire monad on it's own. What I need is a functionality to "split" the monad transformer stack like this:

split :: (MonadTrans s, Monad t) => (s t) a -> s (t a)

Either I haven't found this function or the solution works entirely differently.

2

There are 2 best solutions below

1
On BEST ANSWER

The approach that seems simplest in this particular case is to use the MFunctor instances of the ExceptT e and WriterT w transformers:

import Control.Monad.Morph

floop :: Monad m
      => s
      -> ExceptT e (WriterT w (StateT s m)) a
      -> ExceptT e (WriterT w m) a
floop s = hoist (hoist $ flip evalStateT s)

Since State s = StateT s Identity, the slight generalization above is immediate.

0
On

I'm not aware of anything as general as your split, but using the map...T functions could prevent the explicit manipulation:

have :: ExceptT String (WriterT String (State s)) a
f    :: State s a -> a

want :: ExceptT String (WriterT String Identity) a
want = mapExceptT (mapWriterT (return . f)) have