Having briefly looked at Haskell recently, what would be a brief, succinct, practical explanation as to what a monad essentially is?
I have found most expla
In practice, monad is a custom implementation of function composition operator that takes care of side effects and incompatible input and return values (for chaining).
http://code.google.com/p/monad-tutorial/ is a work in progress to address exactly this question.
Let the below "{| a |m}
" represent some piece of monadic data. A data type which advertises an a
:
(I got an a!)
/
{| a |m}
Function, f
, knows how to create a monad, if only it had an a
:
(Hi f! What should I be?)
/
(You?. Oh, you'll be /
that data there.) /
/ / (I got a b.)
| -------------- |
| / |
f a |
|--later-> {| b |m}
Here we see function, f
, tries to evaluate a monad but gets rebuked.
(Hmm, how do I get that a?)
o (Get lost buddy.
o Wrong type.)
o /
f {| a |m}
Funtion, f
, finds a way to extract the a
by using >>=
.
(Muaahaha. How you
like me now!?)
(Better.) \
| (Give me that a.)
(Fine, well ok.) |
\ |
{| a |m} >>= f
Little does f
know, the monad and >>=
are in collusion.
(Yah got an a for me?)
(Yeah, but hey |
listen. I got |
something to |
tell you first |
...) \ /
| /
{| a |m} >>= f
But what do they actually talk about? Well, that depends on the monad. Talking solely in the abstract has limited use; you have to have some experience with particular monads to flesh out the understanding.
For instance, the data type Maybe
data Maybe a = Nothing | Just a
has a monad instance which will acts like the following...
Wherein, if the case is Just a
(Yah what is it?)
(... hm? Oh, |
forget about it. |
Hey a, yr up.) |
\ |
(Evaluation \ |
time already? \ |
Hows my hair?) | |
| / |
| (It's |
| fine.) /
| / /
{| a |m} >>= f
But for the case of Nothing
(Yah what is it?)
(... There |
is no a. ) |
| (No a?)
(No a.) |
| (Ok, I'll deal
| with this.)
\ |
\ (Hey f, get lost.)
\ | ( Where's my a?
\ | I evaluate a)
\ (Not any more |
\ you don't. |
| We're returning
| Nothing.) /
| | /
| | /
| | /
{| a |m} >>= f (I got a b.)
| (This is \
| such a \
| sham.) o o \
| o|
|--later-> {| b |m}
So the Maybe monad lets a computation continue if it actually contains the a
it advertises, but aborts the computation if it doesn't. The result, however is still a piece of monadic data, though not the output of f
. For this reason, the Maybe monad is used to represent the context of failure.
Different monads behave differently. Lists are other types of data with monadic instances. They behave like the following:
(Ok, here's your a. Well, its
a bunch of them, actually.)
|
| (Thanks, no problem. Ok
| f, here you go, an a.)
| |
| | (Thank's. See
| | you later.)
| (Whoa. Hold up f, |
| I got another |
| a for you.) |
| | (What? No, sorry.
| | Can't do it. I
| | have my hands full
| | with all these "b"
| | I just made.)
| (I'll hold those, |
| you take this, and /
| come back for more /
| when you're done /
| and we'll do it /
| again.) /
\ | ( Uhhh. All right.)
\ | /
\ \ /
{| a |m} >>= f
In this case, the function knew how to make a list from it's input, but didn't know what to do with extra input and extra lists. The bind >>=
, helped f
out by combining the multiple outputs. I include this example to show that while >>=
is responsible for extracting a
, it also has access to the eventual bound output of f
. Indeed, it will never extract any a
unless it knows the eventual output has the same type of context.
There are other monads which are used to represent different contexts. Here's some characterizations of a few more. The IO
monad doesn't actually have an a
, but it knows a guy and will get that a
for you. The State st
monad has a secret stash of st
that it will pass to f
under the table, even though f
just came asking for an a
. The Reader r
monad is similar to State st
, although it only lets f
look at r
.
The point in all this is that any type of data which is declared itself to be a Monad is declaring some sort of context around extracting a value from the monad. The big gain from all this? Well, its easy enough to couch a calculation with some sort of context. It can get messy, however, when stringing together multiple context laden calculations. The monad operations take care of resolving the interactions of context so that the programmer doesn't have to.
Note, that use of the >>=
eases a mess by by taking some of the autonomy away from f
. That is, in the above case of Nothing
for instance, f
no longer gets to decide what to do in the case of Nothing
; it's encoded in >>=
. This is the trade off. If it was necessary for f
to decide what to do in the case of Nothing
, then f
should have been a function from Maybe a
to Maybe b
. In this case, Maybe
being a monad is irrelevant.
Note, however, that sometimes a data type does not export it's constructors (looking at you IO), and if we want to work with the advertised value we have little choice but to work with it's monadic interface.
If I've understood correctly, IEnumerable is derived from monads. I wonder if that might be an interesting angle of approach for those of us from the C# world?
For what it's worth, here are some links to tutorials that helped me (and no, I still haven't understood what monads are).
The two things that helped me best when learning about there were:
Chapter 8, "Functional Parsers," from Graham Hutton's book Programming in Haskell. This doesn't mention monads at all, actually, but if you can work through chapter and really understand everything in it, particularly how a sequence of bind operations is evaluated, you'll understand the internals of monads. Expect this to take several tries.
The tutorial All About Monads. This gives several good examples of their use, and I have to say that the analogy in Appendex I worked for me.
What the world needs is another monad blog post, but I think this is useful in identifying existing monads in the wild.
The above is a fractal called Sierpinski triangle, the only fractal I can remember to draw. Fractals are self-similar structure like the above triangle, in which the parts are similar to the whole (in this case exactly half the scale as parent triangle).
Monads are fractals. Given a monadic data structure, its values can be composed to form another value of the data structure. This is why it's useful to programming, and this is why it occurrs in many situations.