[Haskell-cafe] Explaining monads

Brian Brunswick brian at ithil.org
Mon Aug 13 07:31:14 EDT 2007

On 11/08/07, Ronald Guida <ronguida at mindspring.com> wrote:
> Here's my interpretation of the table:
> ----------------------------------------------------------------------
> Structure   | Subject  |  Action    |  Verb      |  Result
> ------------+----------+------------+------------+----------
> function    |  a       |  a->b      |  flip ($)  |  b
> Functor     |  f a     |  a->b      |  <$>       |  f b
> Applicative |  f a     |  f (a->b)  |  flip <*>  |  f b
> Monad       |  m a     |  a->m b    |  >>=       |  m b
> Comonad     |  w a     |  w a->b    |  =>>       |  w b
> Arrow       |  a b c   |  a c d     |  >>>       |  a b d
> ----------------------------------------------------------------------


Kim-Ee Yeoh wrote:
> > ... I think you'll find that each of those structures have their
> > privileged place in your code.
> Agreed.  I'm still a beginner; I'm not sure how to choose one
> structure over another, at least not yet.  But that's because ...
> > Monads are undoubtedly more pervasive, and that could be because there
> > aren't as many arrow and comonad tutorials, atomic ones or otherwise.

And I'm trying to say that these shouldn't be separate tutorials at all -
much more instructive to compare and contrast.

Moreover, Comonad isn't even in the standard libraries (Hoogle returns
> no results for it).
> When I searched for tutorials on monads, I found lots of them.  In
> fact, I have heard that writing (yet another) monad tutorial is part
> of standard Haskell initiation.

Thats what I was doing above :-)


One thing that I keep seeing people say (not you), is that monads /sequence/
side effects. This is wrong, or at
least a limited picture.

/All/ of the above structures are about combining compatible things things
together in a row.
/None/ of them force any particular order of evaluation - that all comes
from the particular instance. So its
only a particular feature of IO that it sequences the side effects. Others
don't - we can have a lazy State
monad that just builds up big thunks.

IO could be implemented as any of the above structures, and still be
perfectly able to keep
things in order. Indeed, uniqueness types as in clean, are arguably just the
first one - function composition

functor IO would be really boring - we could just perform a sequence of
actions with no choices at all.
(But the whole sequence could be repeated, and I guess the Structure could
be nested for fixed loops)

The key to the choice of IO as a Monad comes back the the argument about
'simplicity' or what ever we
want to call it - I agree its rather context dependent, and indeed I was
rather flippant at the end of my first message

But lets look at the nature of the actual things being sequenced, the
actions above.

In only 3 cases are the actions simple enough to take a single /a/ argument.
Function a->b; Functor a->b;  Monad a->m b

In function and functor, the action takes no part in the complexity, doesn't
know about it.
In function application the action gets used (possibly) once, in functor and
monad possibly many times.
Only in Monad does the action have a say in the complexity, by returning an
possibly non-trivial m b.

So thats the reason Monads are so handy - the combined actions are simple,
but they can
at least participate - influence the flow of control if we are talking about
a IO-like Monad.

Also, arrows are supposed to be more general than both monads and
> comonads.  If I could just figure out what each structure (functor,
> monad, comonad, arrow) is doing, and compare and contrast them, then I
> probably will have made leaps of understanding.  I have a sense that
> tells me that the table above and the data structures below probably
> start to scratch the surface of understanding.
> ----------------------------------------------------------------------
Arrows are most general because they have full access to the complexity
going on in the
structure. Each arrow can do arbitrarily complex (possibly bidirectional)
negotiation with its
input, and possibly asynchronously arbitrarily complex negotiation with its
output. Any sort of
data can flow any way at any time, the only restriction is that for an
'Arrow a b' object, the
input side uses a's and the output b's.

Compare a monad - the input must be single, simple a's. All that can happen
is that the function gets called multiple times.

Brian_Brunswick____brian at ithil.org____Wit____Disclaimer____!Shortsig_rules!
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.haskell.org/pipermail/haskell-cafe/attachments/20070813/bc4d7152/attachment.htm

More information about the Haskell-Cafe mailing list