.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. _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe