This is my first acquaintance with Monad Transformers, so the answer might be obvious.
Let's say I am inside a do block of type StateT MyMonad MyType, I want to make another function of the same type both modify the state and return a value of type MyMonad MyType. How can I achieve that? I think the examples here show it in guessSession, yet I can't seem to understand how to apply it!
If you want to use the underlying monad in a monad transformer, you can use lift
:
lift :: (MonadTrans t, Monad m) => m a -> t m a
In this case, t
is StateT MyState
, and m
is MyMonad
. So, for example:
foo :: StateT MyState MyMonad MyType
foo = do
modify $ \s -> s+1
lift $ doSomethingInMyMonad 42
Monad transformers aren't "layered on" in the sense that you'd return a value of type MyMonad MyType
from inside; it's a more literal transformation: they turn a monad into a new one that has the ability to run actions in the transformed monad. So, you can think of StateT s m
as just the regular State s
monad, except that you can also use lift
to run turn actions in m
into actions in StateT s m
.
If you're using the standard Monad Transformer Library (mtl) transformers like StateT
, ReaderT
, etc., you don't actually have to use lift
; things like modify
and ask
work in any monad with the right transformer somewhere in the stack. (A stack is just a tower of transformed monads, like StateT s (ReaderT r IO)
.)
Additionally, if you have a large stack with IO
at the bottom, there's a convenience function for lifting an IO
action up any number of layers:
liftIO :: (MonadIO m) => IO a -> m a
So liftIO (putStrLn "Hello, world!")
works in IO
, StateT Int IO
, ContT r (WriterT [String] IO)
, and so on.
(As an additional note, foo
here isn't actually a function; a more accurate term is action or computation.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With