[Haskell-cafe] About the Monad Transformers

Neil Brown nccb2 at kent.ac.uk
Wed Jun 17 13:09:19 EDT 2009


.shawn wrote:
> On page 141 of "Yet another Haskell Tutorial" (9.7 Monad Transformers)
>
> mapTreeM action (Leaf a) = do
> lift (putStrLn ("Leaf" ++ show a))
> b <- action a
> return (Leaf b)
>
> mapTreeM :: (MonadTrans t, Monad (t IO), Show a) => (a -> t IO a1) ->
> Tree a -> t IO (Tree a1)
>
> Why does the type signature of mapTreeM look like this?
> And what does it mean by "The lift tell us that we're going to be
> executing a command in an enclosed monad. In this case the enclosed
> monad is IO"? Why does the author put lift here? How does the lift work?
The idea of a monad transformer is to add a second monad (the
transformer) onto a first (I find thatoften, as in this case, IO is
involved). The type parameter t (standing for the monad transformer)
takes two arguments: the first is the monad being added to (IO) and the
second is the normal monadic return value. For example, with the StateT
transformer using a state with type Int, the type signature becomes:

mapTreeM :: (MonadTrans (StateT Int), Monad (StateT Int IO), Show a) =>
(a -> StateT Int IO a1) -> Tree a -> StateT Int IO (Tree a1)

So it takes a function from a to a1 in our combined StateT Int IO monad,
a Tree of a, and gives you back a Tree of a1 in the monad, by
transforming each value in the tree monadically.

When you write the do block, you are writing in the StateT Int IO monad
(or whatever transformer you happen to be using). Thus, the compiler
expects the statements of the do block to be of this type. putStrLn
gives back something in the IO monad, and there is no support in the
language/type-system for automatically turning an IO thing into a StateT
Int IO thing. Hence where lift comes in. lift is used to make something
of the inside monad (IO) become something of the transformed monad
(StateT Int IO). The call of action does not need lift, because its
result is already in the StateT Int IO monad.

The times where lift becomes particularly important is when you end up
with two state monads (or two writer monads, or whatever) in a stack. If
you had the nasty construction StateT Int (StateT Int IO) as your monad,
you'd need a lift to access the inner state, but you'd leave off the
lift to access the outer state.

Hope that helps,

Neil.


More information about the Haskell-Cafe mailing list