# A Neighborhood of Infinity

## Thursday, May 04, 2006

Another literate Haskell post:I've tried a few times to read various documents on the web aboutMonad Transformers in Haskell. I think that in almost every case theauthors are trying to show how clever they are rather than explainingtheir use. If I had just seen the simplest possible examples of MonadTransformers at work I would have been able to figure out what was goingon and that would have given me enough information to bootstrap myselfinto Monad Transforming enlightenment.So to save other people the trouble I went through I'm providing youwith examples of Monad Transformers at work. I'm not even going toexplain in detail how they work, they're close to self-evident once themain features are pointed out.> import Control.Monad.State> import Control.Monad.IdentityFirstly here are two examples of the use of the State Monad. Thiscode isn't intended as a tutorial on the State Monad so I won'texplain how they work.> test1 = do>             a <- get>             modify (+1)>             b <- get>             return (a,b)> test2 = do>             a <- get>             modify (++"1")>             b <- get>             return (a,b)> go1 = evalState test1 0> go2 = evalState test2 "0" Note how evalState 'unwraps' the State Monad and gives you back theanswer at the end.So the question is: how do I combine both of these states into oneso that I can update or read either the integer or the string stateat will? I could cheat and make a new state of type (Int,String)but that isn't a general solution.The idea is that you use a Monad Transformer. A Monad Transformerif like a layer of onion peel. You start with the Identity monadand then use Monad Transformers to add layers of functionality.So to get a two-state monad you take the Identity and add twolayers of stateness to it. To get the answer at the end you needto unwrap the State layers and then unwrap the Identity layer too.When you're inside your 'do' expression you need a way to choosewhich Monad you're talking to. Ordinary Monad commands willtalk to the outermost layer and you can use 'lift' to send yourcommands inwards by one layer.The following should now be self-evident:> test3 = do>     modify (+ 1)>     lift $modify (++ "1")> a <- get> b <- lift get> return (a,b)> go3 = runIdentity$ evalStateT (evalStateT test3 0) "0"Note that we use evalStateT to unwrap the State layer insteadof evalState. evalStateT is what you use to unwrap one layerof the Monad. evalState is what you use when your entire Monadis just the State monad. When State is a layer, rather thanthe whole thing, it's called StateT. (Try :type go3 in ghci.)What if you want to combine IO and State? For various reasonsthe IO monad must form the innermost core of your onion sothere's no need to wrap an IO layer around the Identity,you can just start with IO. And when you unwrap you don'tneed to unwrap the IO layer because the Haskell compiler doesthat for you. (Now you can see why you can't layer IO, you'renot supposed to unwrap IO as it's the job of the code thatcalls main at the top level to do that.)So here we go:> test5 = do>     modify (+ 1)>     a <- get>     lift (print a)>     modify (+ 1)>     b <- get>     lift (print b)> go5 = evalStateT test5 0At this point you might be suspicious that IO is being handledslightly differently from State. So here's a StateT layerwrapped around State:> test7 = do>     modify (+ 1)>     lift \$ modify (++ "1")>     a <- get>     b <- lift get>     return (a,b)> go7 = evalState (evalStateT test7 0) "0"You can probably safely ignore my comments and crib the code abovedirectly for your own use.And credit where credit's due: I found the following link to bemore helpful than any other in trying to figure this stuff outhttp://www.cs.nott.ac.uk/~nhn/MGS2006/LectureNotes/lecture03-9up.pdf(But I still felt that this link was obfuscating.)You may now be wondering where test4 and test6 are. So am I.Update: I just figured out that you don't always need to use the'lift' operation. Some of the Monad Transformers have been definedso that the commands will automatically be passed into the innerMonad (and further) if needed. I think it's slightly confusing towrite code this way, however.

Pete Kazmier said...

Great post! I've been struggling with the concept of monad transformers. This post was very concise and to the point without obfuscating the reader with unnecessary details. Would it be possible to take the content of your post to one of the more public Haskell wikis (of course with proper attribution)? I wish I had discovered this much sooner!

One followup question related to the "update" at the end of the post. It's not clear to me when you say one doesn't always have to use lift. Could you give a concrete example?

sigfpe said...

Pete,

I was going to post this very example on the Haskell Wiki but I had trouble figuring out how to do this. I'm happy for you to do it. If you want, add a link back to here.

If I remember I'll write an example that doesn't use 'lift' and post it here. Otherwise search for "Looking for basic state transformer example" on USENET where I first posted an example. (The title of the USENET post is wrong, I meant to say "monad" but said "state" by accident.)

Luke Plant said...

jto said...

Thanks. Great post.

jto said...

Thanks. I found this quite useful.

kc5tja said...

I STILL can't think of one real-world reason why I'd want to use one. I just don't get it (yet).

Tim Stewart said...

So, if I wanted two kinds of state, one readable and one readable and writable, I could wrap a StateT in a ReaderT? Or vice versa?

sigfpe said...

Tim,

Exactly. Except that if you just have two types then one can be an ordinary monad, and the other can be a monad transformer. Or you can use three levels where both the reader and the writer are monad transformers and they are applied to the identity monad. (I do the former in this post.)

yaxu said...

One thing - did you mean to say "Try :type test3 in ghci." rather than :type go3 ?

The latter just yields:
go3 :: (Integer, [Char])

Krzysztof "Tener" S. said...

This post is really great. Thanks!

chessguy said...

Hmm, do you really need to wrap this around Identity? Can't you just stack StateT on top of State to just get sort of a DoubleState monad?

sigfpe said...

chessguy,

It's up to you. If you're bothered by the lack of symmetry from having a StateT and a State then you can use the Identitiy monad.

Sean Kanaley said...

For those wondering why you would want to use this: as an example, I'm trying to implement Ruby Quiz 19 (Yahtzee). How am I supposed to set up an interactive loop with the user and save the current score and random state (for die rolls) throughout the loop? You can't do IO () stuff like putStrLn to show dice rolls while using State (Score,StdGen) x because your return type is no longer IO (). But with something like the test5 example, it's now entirely possible. A terrible workaround would've been to use IO () to read/write the state to a file... Now I can StateT (Score,StdGen) IO () and all is solved.

Mitchell said...

Yeah, I'm going to have to agree with sigfpe... it's really just up to you how you want to do it. Sometimes multiple solutions stink!

Can not agree any more with your comments on those egghead's explanation on Monad Transformers. Thanks a lot. Really what I want to know.

Can not agree more with your comments on those fake tutorials. This is just what I want to know. After using that for few weeks, I will begin to understand what Transformer really is.

Michael Roger said...

Here's another nice and thorough and typeset :-) tutorial, posted shortly after sigfpe's original:

http://www.grabmueller.de/martin/www/pub/Transformers.en.html