Search code examples
haskellmonad-transformersstate-monad

evalState in a monad transformer stack


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.


Solution

  • 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.