Talk:Haskell/Understanding monads/Nuclear waste

(Prior to the metaphor version)
We have permission to import "All about monads" into this Wikibook. See the discussion associated with the Front Page.

(Prior to the metaphor version, bis)
Feel free to mutilate this page as you see fit, as if you had written it yourself. I don't imagine it's very good :-P --Ihope127 02:04, 23 January 2006 (UTC)

The nuclear waste metaphor
I'm currently in the process of converting my "Of monads and space suits" tutorial to a new, less far fetched metaphor suggested by Paul. I'm a bit ambivalent about the new metaphor. On the one hand, it does seem to simplify explanation somewhat, somehow lends it self to less verbiage. But on the other hand, with nuclear waste, you somehow communicate the idea that the "need" for a container comes from the stuff within, whereas with the space station metaphor, you communicate more the idea that this need comes from something exterior (space)... which seems a bit closer to the truth. I suggest we keep running with this, though and seeing where it can go -- Kowey 00:43, 3 February 2006 (UTC)

The way I see it, the need for the containers is to stop the waste contaminating our pure functional world with its horrible side effects. By the way, sorry I haven't been contributing much recently. Occasionaly my life needs a bit of maintenance. -- Paul Johnson 23:06 6 Feb 2006 (UTC).

I made a very minor change around where the original article had "running around with nuclear waste wouldn't be very healthy... indeed, would cause workers to die." I thought the tone of the original version was slightly flippant, and on the off chance that the reader has someone he loves who got radiation poisoning, strikes the wrong note. Other than that, I like the article a lot: very helpful in learning haskell.


 * Well, maybe you shouldn't mention nuclear waste at all, some activist might get a fit ... And the space example is far from perfect too, you didn't think of people with agoraphobia or claustrophobia at all. I, for example, have political-correctness-phobia and am presently pretty disgusted ;-). Pople are just like that, they like to take offense, so don't get your knickers in twist sidestepping everybody, sooner or later they'll push you into a corner ...


 * Ouch. I hadn't thought of that.  I guess in the old space suit metaphor, the same flippant tone was more acceptable since... well... how many astronauts do you know? Or maybe that's just not very nice of me in general :-( Thanks for the edit.  -- Kowey 15:58, 18 December 2006 (UTC)

Thank-you anonymous contributer!
Why thank you! You give me faith in wikis. -- Kowey 10:07, 15 February 2006 (UTC)

Import of Monads and Space Suits complete
Whew! Now, time for us to remix this with Jeff Newbern's stuff. -- Kowey 11:29, 15 February 2006 (UTC)

A bit of feedback
First off, this is far and away the best monad tutorial I've come across. The metaphor really explains the concepts well. I read it (and then All about Monads to consilodate) through yesterday, and I'm now in a position to say I fully understand monads. Thanks!

My ideas for improvement:


 * Add a sentence at the end of the 'Use a container' section with words to the effect of "the reason for using containers in actual programming will be explained later", and then explain it later on. It fits in quite naturally with the state monad stuff. It is in fact implied there but we might as well make it explicit.
 * The state monad section diagrams: we've lost the processing robot from the diagrams! This is a shame as it helps visualise (especially with the complicated bind diagram) exactly what we're linking together.
 * I think there's scope for a sequel to this chapter: "Advanced Monads" or something. It would explain the monads as computations metaphor, about >> and fail, and explain the MonadPlus class. It might also be nice to talk about lifting, etc.

Thanks once again for the excellent article. DavidHouse 13:26, 17 February 2006 (UTC)


 * Thanks for your comments! I like the metaphor a lot, basically an instantiation of Cale Gibbard's monads as containers notions. Thanks go to Paul, naturally, for suggesting the shift away from space suits and astronauts.
 * I'll think about adding the processing robot into the state diagram: at first, I was a bit afraid to over-complicate things, so I figured I would focus only on the fancy container that the robot returns.
 * And yes, I do agree that somewhere between this chapter and the Programming:Haskell monad transformers chapter could be much more to say! Lifting is discussed in the transformers chapter, by the way.  -- Kowey 23:33, 17 February 2006 (UTC)

Some Feedback
Thanks for this tutorial. Still making my way through it, but what I've gotten through so far has been helpful.

I have a minor comment about one of the earlier bits. I don't particularly find the use of dollar any less hard to read than using parens. When I read the bit about the paren-use being ugly, I became puzzled and attempted to examine the dollar expression in more detail to see if I'd missed anything. If anything I find 'i (h (g (f x)))' to be a lot easier to read compared to 'i $ h $ g $ f x'. Perhaps how readable people find these types of expressions is subjective.


 * I agree that in this particular example, the clarity of both variants is about the same. But there are times that dollar does clearly (in my opinion) help readability out.  Something like

a (b ((c d e) (f g h) i) a $ b $ (c d e) (f g h) i
 * Might be an example. I guess the point isn't that $ lets you replace parens, but that sometimes, mixed paren-dollar use can make your intention more apparant.  -- Kowey 22:39, 30 March 2006 (UTC)

get and put
Dear anonymous contributer,

Thanks for your correction to the wikibook! I agree with you that your implementation of get and put (after checking with the Haskell library) is correct, but this implementation needs to be used with an anonymous bind operator, whereas such an operator does not exist in the tutorial. Please excuse my brutal reverting of your attempt at improving this article. I think ultimately what I have is bad for people because it does not correspond to the real implemenation of get they will see in real life. There are several potential fixes to this: What do you think? I don't really have time to work on the wikibook right now, but I definitely agree with you that what I have is not quite right. -- Kowey 08:08, 9 April 2006 (UTC)
 * Overhaul the State explanation, and work in (1) the type constructor (2) anonymous bind
 * Call our version of State something like State_ and note that the real State is different, likewise for get_ and put_.

Telling them that the do-notation will translate  into   would be fine I think. A much bigger problem here is that  and   has the wrong type, so   and will not compile at all. 128.12.197.163 02:30, 10 April 2006 (UTC)


 * I've got a game plan, but I don't have time to put it into action just yet. Just to reiterate, I completely agree with you that we need to change get/put to the "correct" version ASAP.  The basic idea is that we'll introduce the correct get/put and then point out there is a type mismatch, from there say that you need to use it with   and from there, and maybe introduce the  .  Will look at it when I have time... or maybe somebody could do something like the above? -- Kowey 20:42, 11 April 2006 (UTC)


 * Ok, I've taken a few moments this morning to write it up. Is it to your satisfaction? -- Kowey 05:10, 22 April 2006 (UTC)

modify

 * I am saving this text here for now, due to recent work with the anonymous bind operator

Suppose somewhere along the line you want to modify the current state. That is, you want to  it, change it in some way, then   the new value. So, using do notation you'd have something like this:

do st <- get let st' = f st   put st'

is a nice little function which you can use instead of the above monotony. It takes a function from state to state, i.e. if you're using s as states then the function you pass in has to be of type. Using modify, the above example becomes:

modify f

Nice, no?


 * Kowey's comments: First of all, thank-you! I greatly appreciate your contribution to the wiki!  There's a couple of minor issues I have with this, however, and I'm really sorry to be difficult (just like I was being with anonymous bind).  Namely
 * I do not introduce do-notation until the very end of this module
 * While  is immensely useful, but it isn't strictly neccessary for understanding monads.
 * It breaks the flow from introducing get/put to introducing the anonymous bind operator, to introduce the Haskell State datatype
 * How about we put this into the intermediary chapter on monads that we were planning? Sort of a monads-in-practice chapter that goes right before the monad transformers one?  What do you think?  -- Kowey 05:12, 22 April 2006 (UTC)

Puzzling metaphor for puzzling concept?
As probably many of haskell newbies, I got excited initially, but soon stumbled upon monads. I've read a number of monad tutorials since, and I think that I began to understand them, partially. I have a big trouble though with the metaphor of "processors" and "containers" (or "trays" as they are called in another tutorial): to me, it seems deeply illogical that the "processor" has the "packager" built in, while the "unpackager" needs to be external. In a real world (or "metaphor world") factory, you would rather have either machines that consume containers with input and produce containers with output, or machines that consume raw material and produce raw material, coupled with two robots: an unpackager in front and a packager at the back. Likewise, in programming, it seems illogical to develop functions that accept "raw" data but must return "container with data". A function that would take a "container with raw data" as input and return a "container of the same type with processed data" would look cleaner.

I am sure that there must be some very good and simple explanation for this discrepancy, but as far as I have seen, everyone is just taking it for granted. To me, it's an ugly spot in a beautiful picture.

Am I the only one? If I am not, maybe it would make sense to discuss this issue in the tutorial?

And, oh, this article still is the most comprehensible of what I've read so far... Thanks! --Crosser 19:33, 29 January 2007 (UTC)


 * So the question is why there isn't symmetry in this, if I understand correctly. Well, it's clear that we can't just have raw-raw factories.  Or rather, we can, but then it'd just be regular functions, which we already know how to sequence (think dollar).  Now we want to do fancy things like IO or State passing (it gets much better!), and to do that we can use some kind of container mechanism.  Ok, so that's why we don't have raw-raw factories.


 * The symmetric case would be  which is an arrow, albeight a particular one.
 * Anyway, I think that the explanation of the metaphor slightly misses the point of monads. Maybe this is what has raised the irritation here. The point of monads is that nothing is ever unpacked, i.e. the waste processor goes into the container (going into means lifting  to  ), processes the waste resulting in a new container inside the container. After that, the nested containers get flattened to single one (with  ). This way, the hole processing steps happens inside a container and no radioactive material ever leaks outside. Of course, the metaphorical problem is now "why do I have processors that pack the waste into containers  ? I mean, I can process the waste with   and leave out the extra flattening step ?". Well, the answer in "real world" is that some functions like   do magical things with the  . Perhaps, the solution is to modify the metaphor: we glue container and waste together in the monad   and retain "pure" types   and  . This way,   takes a precious value   and returns a precious value , but unfortunately produces nuclear waste as a side effect so we only get   which is tainted forever. But thanks to  , we can still operate with the stuff inside tightly sealed containers. --  a  p  f  e  l m  u  s  21:51, 22 February 2007 (UTC)


 * Now the next question is why we don't have container-container factories... and for that I have two answers. The first is "well, if we can get by just wrapping the output, why make life any more complicated than that?".  The second answer is that, well there is a different abstraction called arrows, which sort of looks like that; but I still don't understand them well enough to say more.  It just turns out that if we drop down from the metaphor in to the real world of Haskell hacking, monads are pretty darn useful by themselves (consider Maybe and List).


 * Finally, I'd suggest you check out sigfpe's excellent "You Could Have Invented Monads", which presents a very down-to-earth non-metaphorical approach, that works with you to re-invent the monads concept without even noticing it. -- Kowey 20:29, 29 January 2007 (UTC)


 * Yes, Kowey, it's indeed the lack of symmetry in the metaphor/programming concept that haunts me. And the explanation "asymmetric is good enough to do the job" is not satisfying ;-) Maybe I could be happier with another similar metaphor, like "the processor always attaches a pouch with documentation to its output"... I need to mull over it some more.


 * I've read sigfpe's article, and honestly I find the concept of "debuggable functions" of the kind f :: Float -> (Float,String) no less irritating than asymmetric nuclear waste processors. Oh well... --Crosser 13:56, 30 January 2007 (UTC)


 * Crosser, try this one on for size. In fact, we very well could have symmetrical functions (taking containers in and spitting them back out).  Since all the containment business is taken care of, we can then sequence them by using our old friend, the   operator:

cf € cg € ch


 * Great! Ok, so we don't need any complicated robots to control what happens between each function (dollar or euro do the trick just fine).  So what happens within the function?  In most cases, it's not very useful for us to be processing the container; we want to get at the stuff that's inside the container, right?  It turns out that the mechanism we invent for getting the stuff out of the container is going to be a bit of boilerplate code.  Because we're diligent programmers, we're going to "factor out" the boring code, separating each function ,   and   into a boring end and its core business logic.    then becomes something like  ; likewise,   becomes   and so forth.  Oh wait a second, what's this   function we introduce then?  It turns out that this is exactly the   operator from this chapter.  The code from our symmetrical model of computation would then look something like this:

(>>= f) € (>>= g) € (>>= h)


 * And if we wanted to use this, we'd still have to have a function that wraps something into a container:

return x € (>>= f) € (>>= g) € (>>= h)


 * So that's fine, and maybe there is some kind of use for it. But in many cases, this is just a lot of extra cruft, so we can just do away with the 'front' end container and use   directly, thus making the code a lot lighter-weight:

return x >>= f >>= g >>= h


 * Is this any more convincing? -- Kowey 14:36, 30 January 2007 (UTC)


 * Yes, Kowey, I understand the explanation. Still, even more, I am beginning to think that the ugliness (as perceived by myself) of the monad concept is the penalty for the attempt to shove side effects into purely functional paradigm. I found this post rather in line with my subconscious impressions.


 * Thank you for discussion and explanations, anyway, they where very educative. --Crosser 14:17, 2 February 2007 (UTC)


 * Thanks for the link. One thing I can point out is the usefulness of monads goes far beyond IO. While IO may the first place we encounter monads, Haskellers eventually discover (1) the usefulness of Maybe and List monad in real-life code (2) monadic parser combinator libraries [Parsec] (3) combining monads together with  transformers (4) generic functions that work on any monad.  Point being that it would not do to restrict our view of monads on IO or side-effects; there's much more fun to be had than that!  In any case, happy travels.  I hope you find what you're looking for either in Haskell or another language. -- Kowey 07:43, 3 February 2007 (UTC)

This is an excellent tutorial
I was searching for a tutorial on monads and I think the nuclear waste metaphor (however contrived it is!) clearly put things in perspective.

Please *donot* change this metaphor, people new to computer science stumble upon various Monad tutorial sites with no avail! This wikibook is excellent - and thanks to the contributor!

--[User:dormant25]

This is excellent!
God bless you! I've been trying to understand monands for hours! But I couldn't. I knew it was a very simple concept, but the bind operator was killing me Now thanks to this metaphore I finally got it!

Thank you!

Yet Another fan of this tutorial
I've tried to understand what Monads are and are good for for years. This tutorial finally made it all clear to me. Thanks! --Andrew Eisenberg 21:56, 2 January 2007 (UTC)

Kowey responds
Thanks, everyone, for your kind words. I hope you'll have a chance to read the next chapters in this section, and the other articles on the Haskell MetaTutorial (I'm a big fan of Monads as Containers and You Could Have Invented Monads myself). These will give you other ways of understanding monads, which should help to clarify the idea even more. Best, -- Kowey 13:04, 3 January 2007 (UTC)

Macro metaphor
If it's any help, I found the macro metaphor for monads of [http://kawagner.blogspot.com/2007/02/understanding-monads-for-real.html "Understanding Monads. For real."] to be nice. --Gwern (contribs) 01:23, 18 February 2007 (UTC)

What's with that "euro"?
I'm hopelessly missing the point with the "euro". It's being said "use (|>) instead" - when I try it in my GHCI: f x |> g |> h it says "Not in scope: `|>'". Are those symbols "vertical bar" and "greater than" symbols? Is it necessary to turn on some extension module before?


 * You'll have to define it first. In GHCI:

let x |> f = f x "hello world" |> reverse |> dropWhile (/= ' ')
 * Hope that helps -- Kowey 13:07, 17 March 2007 (UTC)

I miss the point with (€) and sequencing
The section introducing (€) ends with 'Nevertheless, this notion of "sequencing" is basically 1/3 of the story behind monads'. I don't get what is ment with 'notion of sequencing'. In a strict language I had no problem identifying nested function application with sequencing. But Haskell expression are evaluated lazily and that confuses me a bit. If you consider the expression 'do_some_logging € print_current_time' then there is no guarantee, that do_some_logging is evaluated before print_current_time. What am I missing here?


 * Hi, the 'sequencing' does not refer to execution order at all. Here it is just a case that the result of one in the pipeline is used in the next, instead of the other way around (in functional languages, we have 'backwards' pipelines).  The point is merely that we write it as   instead of  .  Same execution order in the end (afaik), just defined in a more familiar way.  I wouldn't read too much into it.    just makes things look different wrt ($), but that is all. -- Kowey 13:18, 2 April 2007 (UTC)


 * Thank you very much for your prompt answer! Let me also say, this tutorial is great! It helped me a lot to understand all the type signatures used in monadic frameworks. In the meanwhile I also found the [IO inside] tutorial, in which chapter 3 discusses how the intended execution order emerges in the case of the IO monad, which to understand was my main concern for a long time.

Unhappy customers
For people who want more than a superficial explanation, this tutorial is very very bad:


 * Monads! And Why Monad Tutorials are All Awful
 * see #haskell discussion (with Cale) on badness of wikibook monads tutorial - the nuclear waste metaphor is also bad because the dangerous bit (nuclear waste) is on the inside! (I would say "can we bring space suits back", but I think there is a point somewhere that this use of metaphor might be bad)
 * see Crosser's helpful remarks above (the notion is irritating)
 * people complain that the $/€ thing is confusing...
 * the writing is very clumsy (Kowey); a small part of the problem is that I got into my head that we shouldn't use you/I (and use more we instead), but that was severely misguided because I ended up making things even worse in the process
 * Apfelmus points out that we're missing the point slightly about the  stuff (right?); the two container image

It's important that we get this one right, because this is the Haskell "thing". So feel free to be Really Really Bold. Maybe replace it with the sigfpe tutorial? (note: Crosser cautions that he found the 'debuggable function' idea 'no less irritating'). Maybe wait to see what Cale can cook up? -- Kowey 07:08, 2 August 2007 (UTC)


 * I concur. Here's further analysis
 * Concerning the metaphor, its goal is to enforce the mental picture that there cannot be a function, i.e. removing the container will result in a radioactive disaster, removing the space suit will kill the astronaut. Thus, the metaphor can be very helpful in removing the mental block of "why do I need such strange operations like   and   when I have  ?". The bad thing about the waste metaphor is that the   in   gets the negative connotation "nuclear waste". Why would I want to process that?
 * The bad thing about metaphors in general is that they fail to explain the why/purpose/usefulness of monads. I mean, a metaphor is just a silly mental game you can play.
 * Personally, I learned monads with the "metaphor" . Indeed a very useful monad :-) and the need to hide the   naturally leads to   and  . Only after that, I learned that containers like   and   support the same structure.
 * However, a point that sometimes/often goes unnoticed when having "monads = sequencing actions" or "monads = reprogram the semicolon" in mind is that sequencing actions means to feed the results of one action to the next one. Sequencing alone can be done with any monoid. I once encountered this in Re: Practical Haskell question. Note that imperative programming languages don't feed results of one action to the next ones, a monoid is enough for them! Instead, they use variable assignments like  to memorize "results" of previous actions. In other words, you can't "reprogram the semicolon" from   to say   in C because of this stupid way to "return" results. Put differently,   is very different from.
 * Concerning style, I think that many parts of the wikibooks are affected, the standard textbook tone is we/passive voice. Fortunately, I think that there are two simple principles for writing high quality texts. Unfortunately, the principles are: Invest a lot of time and Know (or learn) much more about the subject than you actually write down.
 * -- apfe&lambda;mus 12:21, 2 August 2007 (UTC)

Just dashing off a quick note to say how relieved I am to see your two succinct/accurate notes about the purpose of the metaphor (and its potential inappropriateness). You have hit the nail on the head on the pedagogical dilemma I was facing: how to isolate the 'how' from the 'why'. My problem (premondial eric) was that I would really stumble over the 'how' part, because the 'why' part was never really clear to me. So my hope was the metaphor would let us liberate one from the other. Give the user a convenient substitute for understanding why, so that they can focus on the 'how'. Only when they are comfortable with the sort of basic mechanics do we move it to a deeper level, so goes the thinking. Of course, the problem is that I never really moved on, never gave the 'real why'. Anyway, I'm perfectly happy to get rid of the metaphor, if the person doing it understands the 'mental block' problem as well as you do :-D -- Kowey 13:15, 2 August 2007 (UTC)


 * Oh, I actually like the space-suit metaphor :-) so I wouldn't discard it.
 * But I'm not sure whether it's a good idea to introduce the 'how', i.e. the abstract notions  and , before introducing the 'why', i.e. useful examples. You could have invented Monads does the opposite, it introduces the 'why' before the 'how', apparently with big success. Personally, I too prefer the latter style. And Simon Peyton Jones says on slide 14 of How to give a great research talk: "(When time is short,) omit the general case, not the example" :-)
 * Which example to choose for the 'why' before the 'how'? I'd choose  since this is the one type that requires the programmer to know what a monad is, the other monads are more or less optional. It makes abstract   and   necessary, in the sense that there is no way to implicitely code them by hand and thereby miss the abstraction behind. I mean, there is   and   for lists but who would think that these two innocent functions are part of a greater conspiracy.
 * I'd also explain monadic parser combinators  in detail, they are a must for any solid book about monads :-) But probably in a separate chapter.
 * -- apfe&lambda;mus 18:45, 2 August 2007 (UTC)


 * Ok, I'm starting a major rewrite now. Just for reference, here's the version before the rewrite -- apfe&lambda;mus 10:31, 3 August 2007 (UTC)


 * I was thinking of something else when I meant 'why', I don't remember people trying to explain the fundamental "point" before I even really knew what they were talking about. 'Why' via concrete examples sounds like a good idea.  I also like Cale's Monads as Computation from two days ago which pointed out all the handy little functions like   (something which I hardly even knew about when I wrote the 1st version of space suits!) Good luck on the rewrite.  I'll be cheering on the sidelines. -- Kowey 13:12, 3 August 2007 (UTC)