
The “What Are Monads?” Fallacy - psibi
http://two-wrongs.com/the-what-are-monads-fallacy
======
olavk
I think it is a cultural mismatch. The Haskell community seem to be very
influenced by mathematicians and their way of describing everything as
abstractly a possible. You can even see it in code examples where it is pretty
common to see arbitrary one-letter variable names.

The software development community is by and large much more pragmatic and
focused on solving real-world problems. They have an easier time understanding
concepts and code examples when explained in the context of real-world
problems.

So when the Haskell people try to explain monads, they start with the abstract
definition, the monadic laws and so on, and they focus on explaining the
_concept_ of a monad, rather than what they are practially useful for. Even
the many infamous monad-metaphors (its like a spacesuit! No its like a
burrito!) try to find a metaphor for the abstract concept of a monad, not for
any practical use. For the typical developer this might seem like a lot of
mathematical wanking for little benefit.

The language F# seem to have a more 'pragmatic' culture. 'Monads' are called
'computation builders' in F#, and the equivalent to do-notation is called
'computation expression'. Yeah it is just naming, but it shows a focus on the
_use_ of monads rather than on the underlying mathematical concept.

A typical F# example of the use of monads - sorry, _computation builders_ is
the Async monad:

    
    
      let AsyncHttp(url:string) =
        async {  
                 let req = WebRequest.Create(url)
                 let! rsp = req.GetResponseAsync()
                 use stream = rsp.GetResponseStream()
                 use reader = new System.IO.StreamReader(stream)
                 return reader.ReadToEnd() 
        }
    

This example fetches a resource over http without blocking. It is immediately
obvious why this is useful. After all, similar functionality was recently
added to C# through the keywords 'async' and 'await'. But in F# it didn't
require the addition of new keywords but could be implemented as a library,
due to support for monads in the language.

~~~
chriswarbo
> You can even see it in code examples where it is pretty common to see
> arbitrary one-letter variable names.

This is usually because Haskell functions are _really short_. For example:

    
    
        compose f g x = f (g x)
    

We _could_ write this with more descriptive variable names, but there are only
3 variables and they're only in scope for one very tiny line:

    
    
        compose outerFunction innerFunction argumentForInnerFunction = outerFunction (innerFunction argumentForInnerFunction)
    

There are certain conventions as well; if a variable must be present, but
isn't used, it gets called `_`:

    
    
        first (x, _) = x
    

Lists tend to get a plural "s" on their name:

    
    
        elem x xs = any (map (x ==) xs)
    

> So when the Haskell people try to explain monads, they start with the
> abstract definition, the monadic laws and so on, and they focus on
> explaining the concept of a monad, rather than what they are practially
> useful for. For the typical developer this might seem like a lot of
> mathematical wanking for little benefit.

This is because functional programmers tends to spend the most time on writing
generic, abstract, re-usable libraries. Particular applications are just thin
veneers on top of these libraries. For example, I might spend most of my time
writing generic, abstract code to deal with tuples. To make an application, I
can just pick and choose the library code I want to use:

    
    
        type Name = String
        type Address = String
        type Quantity = Int
        type OrderID = Int
        type SKU = Int
        type Customer = Tuple Name Address
        type Order = [Tuple SKU Quantity]
        type Invoice = Tuple Customer Order
    

Given that I'm using Tuples for Orders, Invoices and Customers, the time I
spent writing abstract code to deal with tuples wasn't "a lot of mathematical
wanking for little benefit".

The time spent writing generic, abstract monad libraries isn't wasted either;
by picking and choosing which monads to use, our application can automatically
get error-handing, non-determinism, backtracking, exceptions, state, software
transactional memory, etc.

~~~
dllthomas
Moreover, there are some conventions (which you followed but didn't call out)
that make the single letter names clearer. Whether that makes them clear
_enough_ is more debatable, but I think they're worth noting.

For values:

    
    
       f, g, h: functions
       x, y, z: numbers or generic values
       m, n, o: monadic values
    

For polymorphic types:

    
    
       a, b, c: arbitrary value type
       s, t, u: state or structure
       f, g, h: functor (possibly applicative)
       m, n, o: monad
       i: index
    

There are probably some others that I'm not thinking of, too.

------
sillysaurus3
The fact that no one is able to show a canonical, succinct example of a monad
makes me suspect it's multiple concepts under a single banner. But I haven't
spent much time trying to understand what one is.

EDIT: Thanks for the responses. I'd love to study any resources that you found
useful when learning Monads. Do you know of any?

~~~
aikah
I'd say Monads shouldn't require the use of Haskell to be understood.

I personally don't understand them.Some people told me it's a bit like
"reversed" generics,some others pointed me at promises in Javascript which are
"monadic".

I guess I don't understand them because I work with languages that make them
either hard to implement or totally unnecessary.

~~~
olavk
F# also has monads. However both Haskell and F# has syntactic sugar which
makes the use of monads convenient. Without some syntactic sugar, using mondas
requires chains of nested lambdas which quickly becomes convoluted and
unreadable.

E.g. you could use monads in JavaScript, but it would probably be simpler to
solve the same problem without monads.

~~~
eru
You can use the chain of nested lambdas for monads in Haskell easily. That's
bearable mostly thanks to the way lambda syntax works.

------
flebron
It's kind of ironic that the author states "In his article, Byorgey hints at
what I'm going to say, but I think it deserves to be said again, with slightly
different words.", which is essentially what monad tutorials say about other
monad tutorials :)

~~~
justinpombrio
The 'The "What are Monads?" Fallacy' Fallacy?

~~~
crispweed
Yeah, it's kind of like: There's a problem with too many people making blog
posts with dubious metaphors for monads, so here's a blog post with another
dubious metaphor for monads.

Quite liked the post, nevertheless..

------
fubarred
There's a bigger issue: using computational and mathematical complexity that
is confusing to large swaths of mere mortal coders. This is sadly why
languages, to pick on some easy target religions like PHP and so on have
proliferated.

Sure it's possible to reduce LoC and look clever with ever more complex
representations of computational structures, but it's another thing to write
supportable code that's straightforward to debug, improve and maintain.

If someone wants to use a "research" language in production and/or want
perpetual job security, there are plenty of languages for those requirements
too.

(There's never a perfect Turing power language for anything, only better fits
than others. Clarity for a new-hire reader should be most valued goal after
functionality.)

~~~
noelwelsh
A monad is just a code pattern. If you try to program in a style that
minimises mutate state you'll probably end up inventing something like a
monad. Heck, jQuery is almost a monad -- it's not a true monad but it is
similar in concept.

Monads are not a big deal. Indeed they are so much of a not big deal that I
expect this is a big part of the problem learning monads. People expect them
to be something difficult and exotic, and go looking for hidden depths where
there aren't any. I know I did when I first learned them. Eventually you break
through and realise there is no hidden mystery. It's just a data type with a
few functions, and they happen to be usable in a wide variety of contexts.
That's what this blog post is trying to explain.

Finally, you can teach monads to new hires in a very short period of time. We
do in our training courses.

~~~
phamilton
I like this post because it describes specific monads and why they are useful.

If I were to recommend a basic path to understanding monads, I'd say do this:

1\. Understand `map` in the context of lists. This can be done in Ruby or
Scala very easily if you don't want to get into Haskell directly.

2\. Learn about the Maybe monad (or Option in scala). Understand what mapping
an Option or a Maybe means. A simplified explanation is to compare it to a
list of either length 1 or 0.

3\. Learn about the IO monad in Haskell. Understand how IO monads can compose.
At this point, it's ok to just say magic happens and the compiler then cause a
single IO monad (the result of composing multiple IO monads) assigned to main
to execute and the side effects will happen.

At that point, you've got a general understanding of how to use monads. It
will actually take you pretty far.

One key point that might be a hangup is going from `map` meaning "apply this
function to every element and return a new list of the results" to `>>=`
meaning "apply this function as dictated by the monad and return the result".
It's probably good enough to acknowledge that `map` is a simplified case of
`>>=`.

In any case, as the linked article says here, you should be able to understand
specific Monads fairly quickly. Perhaps truly understanding monads means
knowing when to create new monadic structures but that's hardly a prerequisite
to being productive with monads.

~~~
vertex-four
Haskell's IO monad is decidedly not useful outside the context of Haskell and
pure functional programming, both of which I do not find fun. Are monads in
general useful outside that context - for example, in mostly-imperative
languages like Rust?

~~~
olavk
The IO and State monads is specifically to solve the problem of side effects
in a purely functional language, so they are not really relevant in other
languages.

But other uses of monads, like say monadic parsers could be useful in other
languages. And list comprehensions is also based on a monad in Haskell - this
functionality is clearly useful in many other languages.

But without some kind of syntactic sugar (like do-notation in Haskell) the use
of monads becomes far to cumbersome, and it ends up being easier to solve the
same problem in an ad-hoc manner.

~~~
fubarred
Check out [https://youtu.be/xKRndVoo2ms](https://youtu.be/xKRndVoo2ms), it
explains how monads can refactor messy things like call chaining if you're
building SQL-like result interfaces.

~~~
olavk
In what language?

~~~
kqr
C++ it seems.

~~~
fubarred
Thanks. The speaker mentions Haskell, hopefully the religion isn't so
important as the code patterns.

------
hmexx
I've never really done anything seriously in Haskell, but this is how I feel
monads could be explained through example. Let me know what you guys think. If
it's good I'll add it to the stackoverflow question on Monads.

\---

We know how operators (add, substract, multiply,...) work on integers.
example: 5 + 6 = 11.

Now let's add some extra state/dimension to integers. Let's assume this extra
state is ROCK, PAPER or SCISSORS.

Here are possible values:

5_ROCK

6_PAPER

999_SCISSOR

...etc...

\---

What is the result of 5_ROCK + 6_PAPER ?

There is no answer unless someone defines it. That's what a monad does. In
this case I am deciding that 5_ROCK + 6_PAPER = 11_PAPER

The way MY monad works is to use the operator on the integer portion ( 5 + 6)
and then use the winner of ROCK, PAPER, SCISSORS game as the non-integer
portion.

3_ROCK * 4_SCISSOR = 12_ROCK

8_SCISSOR / 2_PAPER = 4_SCISSOR

...etc...

~~~
tome
So what is `return` (also known as `pure` or `unit`) and does it satisfy the
monad laws?

~~~
hmexx
Hmm... I guess Rock, Paper, Scissors game is non-associative so it does not
meet all 3 laws, but I feel like that's more of a detail. Perhaps a different
game would be better for an example.

------
logicallee
I'm really sorry author, but this is how I read your post:

> _This is like someone new to a language with regular expressions asking what
> a regular expression, is, or someone new to object oriented programming
> asking what a class or object is, or someone new to functional programming
> asking what functional programming is, or someone new to node.js asking what
> node.js is, or someone new to programming asking what a program is.

>What's _wrong_ with you people? These are horrible questions. I refuse to
answer them, and you should know better than to ask. Yes, I could illustrate,
but why should I?

>I prefer to just explain that it's a question that won't help you in the
slightest. I'm not going to illustrate something that will, or give you any
examples.

>Just do it. The important thing is, not in front of me._

Author, you could vastly improve your blog post by actually doing the teaching
instead of sending the student off.

~~~
tome
The article is criticizing people who explain monads badly, not people who are
trying to learn about monads.

~~~
logicallee
You didn't really read it carefully then. It's criticizing the question. You
can't "criticize people who explain monads badly" without explaining monads
well. Think about it.

This is like me criticizing how classes are taught, without offering my
version or showing how they should be taught. Come on.

I'm afraid this post is completely without any value. It's an outline for the
post that the author should write, when the author figures out how to teach
monads (which don't exist in all languages) properly. Building up from several
usage cases, per the author's outline.

The only problem with the outline is that it's notes to self on how to teach
monads well. Well, go ahead then. Put your money where your mouth is and teach
people who have never used a monad how to use a monad. Which is why they're
asking.

------
jamesfisher
For the same reason, we should not say, "use the IO monad to do output". We
should just say, "use IO to do output".

You may not even need the monad instance for IO -- for example, you might just
use its functor instance.

~~~
eru
Or just use the IO combinators directly (if there were exposed outside the
typeclass instances).

~~~
jamesfisher
Of course! It turns out that GHC implements the Monad instance for IO by using
`returnIO` and `bindIO` in `GHC.Base`.

I played around with these as a mini demonstration of using IO in Haskell
without any mention of monads:
[https://gist.github.com/jameshfisher/1d735b5267e8f848b280](https://gist.github.com/jameshfisher/1d735b5267e8f848b280)

~~~
dllthomas
It's cute, but I think it's misleading to call it "non-monadic" \- you're
calling the same functions in the same way, just not through the Monad
typeclass.

------
dschiptsov
Each narcissistic blogger should at least once write about monads -
[http://karma-engineering.com/lab/wiki/Monads2](http://karma-
engineering.com/lab/wiki/Monads2)

------
Scea91
I don't agree with the blog post since the same argument could be made for any
design pattern. There is nothing wrong at trying to understand things at a
higher level of abstraction.

~~~
kqr
I'm probably one of those rare programmers who has never had any real
experience with OOP. I can tell you that reading about design patterns makes
my head spin. I've been able to understand a few design patterns, but that has
been because I've had an actual, practical problem in my code and the design
pattern could be applied to solve it.

Take as an example the following paragraph from Wikipedia:

> The essence of the Mediator Pattern is to "define an object that
> encapsulates how a set of objects interact". It promotes loose coupling by
> keeping objects from referring to each other explicitly, and it allows their
> interaction to be varied independently. Client classes can use the mediator
> to send messages to other clients, and can receive messages from other
> clients via an event on the mediator class.

I have no idea what that means and how and when I apply it in practise. It's
just a bunch of abstract mumbo-jumbo, like an explanation of "what a monad is"
will be.

So I still hold that the abstract description comes after you learn how to use
the thing, not before it.

~~~
NateDad
FWIW, I have done a ton of OOP experience, and I have trouble understanding
most descriptions of design patterns. One you see them implemented, you
generally think, oh, well, duh, I've done that before.

I think the main problem is that most programmers are terrible at explaining
things, and should just stick to code examples, because they're usually a lot
easier for other programmers to understand.

------
bsaul
i think i got what functors are in category theory ( aka morphisms between
categories , IIUC ), but i can't understand what it is in haskell. There's a
link missing in my head between category theory and programming language.

I also couldn't find a post or a video that would explain what monads are in
cateogy theory.

~~~
dllthomas
First, all functors in Haskell are endofunctors in Hask. They map Haskell
types to other Haskell types, and Haskell functions to other Haskell
functions.

A functor in Category Theory has two parts - a map of the objects and a map of
the arrows. In Haskell, when you create a Functor instance, you are saying
"this type constructor _is_ the map for objects; here's how you map the
arrows".

It's typically not the best place to start, but since you asked - a monad, in
category theory, is a functor plus two natural transformations. In Haskell,
the functor is the type constructor plus fmap from the Functor instance. The
natural transformations are return (eta, in the math) and join (mu). Haskell
programmers have historically found it more useful to talk about bind than
join, but in the presence of fmap you can implement either from the other, so
there's not much theoretical difference:

    
    
       join m = bind m id
       bind m f = join (fmap f m)

~~~
bsaul
Thanks for that answer. I first thought monads were a completely different
beast than functors, but considering the small number of fundamental objects
category theory deals with, i had a hard time finding out what.

------
toddkaufmann
Who's on first ?

No results found for "abbott and costello explain monads".

------
crispweed
Is there an rss feed for this blog?

~~~
kqr
Unfortunately no, but that's in the works. Now that several people have
requested it, I've bumped it up on my list of priorities.

------
michaelsbradley
Having also struggled with Monads before having an _aha!_ moment, I've tried
on occasion to help boil it down for those on the search for understanding.

The hardest thing to get is that Monads aren't quite as "tangible" (not sure
of a better word) as concepts like variable, object, property, instance,
function, method. They are essentially relational and require something of a
mental leap akin to coming to grips with how JavaScript's event loop is bound
up in the control flow of your code, which otherwise proceeds from top to
bottom of a .js file; or the rules governing closures and asynchronous
function evaluation in this or that language.

The following is reprised from one of my HN comments in 2013.

\-------

Monads are _programming patterns_ which relate a set of values to a set of of
functions – that's pretty much it! For any monad X, we can say that a function
is monadic if it returns a value in the X Monad. The set of values are
precisely those such that the following three Monad Laws[1] hold:

[ Using JavaScript syntax, they can be approximated as... ]

Left Identity

    
    
        mBind( mReturn(a), f ) == f(a);
        // => true
      
    

Right Identity

    
    
        mBind( mReturn(a), mReturn ) == mReturn(a);
        // => true
      
    

Associativity

    
    
        mBind( mBind( mReturn(a), f ), g ) == mBind( mReturn(a),
                                                     function(a) {
                                                         return mBind( f(a), g );
                                                     } );
        // => true
    

Above, `a` is (basically) any value, while `f` and `g` are any monadic
functions for the same Monad. The definitions of `mBind` and `mReturn` will
vary depending on the Monad, but the same laws (and sometimes additional
properties) hold for each group of things taken as a whole – the monadic
values, monadic functions, and the `mBind` and `mReturn` pair for those values
and functions.

As you can see, there is nothing special that requires a statically typed
language. That being said, if your language is statically typed, and even more
so if its type system has advanced capabilities (e.g. Haskell's type system),
then the relationships between the monadic values and functions can be
leveraged to do a number of useful things, e.g. catching a host of bugs at
compile time (though that's true regardless of Monads).

If your language is dynamically typed, then you won't get those extra
benefits, but you can still take advantage of the fact that Monads can
abstract away a great deal of plumbing between various pieces of your program.

Sometimes the _Monad patterns_ will appear in a language under another name,
or will be used "under the hood" to implement a particular API.
Clojure/Script's `let` for example is essentially the Identity Monad; and its
`for` is very much akin to the List Monad (the same is true for list
comprehensions in other languages). The core.async library involves an
inspiring application of the State Monad pattern[2].

[1]
[http://en.wikipedia.org/wiki/Monad_(functional_programming)#...](http://en.wikipedia.org/wiki/Monad_\(functional_programming\)#Monad_laws)

[2]
[https://github.com/clojure/core.async/blob/master/src/main/c...](https://github.com/clojure/core.async/blob/master/src/main/clojure/clojure/core/async/impl/ioc_macros.clj#L56)

[&]
[https://github.com/clojure/core.async/blob/master/src/main/c...](https://github.com/clojure/core.async/blob/master/src/main/clojure/cljs/core/async/impl/ioc_macros.clj#L46)

~~~
StavrosK
I read your explanation, but couldn't make any sense of it. To begin with, you
completely lost me in the second sentence:

> For any monad X, we can say that a function is monadic if it returns a value
> in the X Monad.

You're defining a monad by using itself in the definition! A definition is
recursive if it recurses.

I sort of understand the three laws after that, but it's like someone asking
"what are operations on numbers" and getting the answer "operation is any
operation that's associative, commutative, etc". It does nothing to explain
monads to me, it just tells me that a monad is any thing that obeys three
things. That information is completely useless to me.

~~~
wz1000
> You're defining a monad by using itself in the definition! A definition is
> recursive if it recurses.

The parent is not defining a monad with that sentence, he is defining what a
monadic function is given that you have something that behaves like a monad

> I sort of understand the three laws after that, but it's like someone asking
> "what are operations on numbers" and getting the answer "operation is any
> operation that's associative, commutative, etc". It does nothing to explain
> monads to me, it just tells me that a monad is any thing that obeys three
> things. That information is completely useless to me.

The thing is that there is not much more to a monad than those three laws and
the two functions(return and bind/join).

Nonads are remarkable because lots of things happen to behave like monads(i.e
have return and bind defined in a way that follows those operations). This
includes interpreters, actions with side affects, non deterministic
computations, computations with the possibility of failure and many other
things.

Monads are useful because they let you write code that is reusable across all
monads and not just the one you happen to be coding for. If you look at code
that is written like this, after enough experience you will get a vague idea
of what it does, but its actual function will almost completely differ based
on what kind of monad you use it for. This gives you a great amount of
flexibility and refactorability as you can tweak and extent monads or create
entirely new monads while still having this great mass of reusable code
already written for you to use.

Like the OP says, a monad is not some tangible concept like an object or a
function. It is a concept that groups other concepts together.

To learn about monads, you have to look at specific examples like the List
monad, or the State monad or the IO monad. But there is no general explanation
of a monad any more tangible than what the parent said.

~~~
StavrosK
> The parent is not defining a monad with that sentence, he is defining what a
> monadic function is given that you have something that behaves like a monad

But I have no idea what a monad is, so it's all equivalent to "a blorx
function is a function that returns a value in the blarx blorx". He never
explained that a monad is different from a function, or that a monad is
something that has values, or that you can return them, or any of the parts
that make up that sentence.

> To learn about monads, you have to look at specific examples like the List
> monad, or the State monad or the IO monad. But there is no general
> explanation of a monad any more tangible than what the parent said.

I have a feeling that that's exactly what someone who attempts to explain what
monads are should talk about. If they're a general concept, like patterns (the
concept of patterns in general, not specific patterns), it is probably clearer
to show how specific examples work and then how they relate to each other, so
someone who doesn't know anything about them can grasp their significance.

~~~
logicallee
You're not seriously asking for a definition of a basic everyday English word
like monad, are you? (hmmm, Chrome underlines this word in this edit box for
some reason - probably some political thing since C++, Go, and Python -
Google's go-to languages - don't support this extremely mundane and everyday
feature.)

Anyway it's like the word 'if' or 'except'. You just need to know about the
syntax or any rules. Type "define monad" into Google if you don't know this
super-basic word. (Personally, I would have thought most of us learned it when
we were 3 or 4 and learning the numbers or the alphabet song). Anyway watch:

[http://google.com/search?q=define%20monad](http://google.com/search?q=define%20monad)

it clearly tells you,

>Monad: a single unit; the number one.

What could be simpler?

So we can simply understand the OP's definition:

> For any monad X, we can say that a function is monadic if it returns a value
> in the X Monad.

plainly:

> For any X that is equal to the number one, we can say that a function for it
> is equivalent to the number one if it returns a value that is the number
> one.

in other words, the definition of a monad is just a function that returns 1 in
all cases. This definition is super-simple. I have no idea why you object.

here are some examples of monads written in C:

int raise_to_zero(int x){ return 1; }

this is a monad to raise a number to 0. Here is another one:

int multiply_by_zero_and_add_one(int x){ return 1; }

this is a monad for multiplying by zero and adding one.

yet another would be:

int divide_by_self(int x){ return 1; }

You get the idea. Likewise there are monads for all sorts of times that you
need a function to return one in all cases.

It's really not hard. There's nothing circular or unusual about the OP's
definition. He's just using plain everyday words we've all known since second
grade, in their usual meanings. I'm at a loss why you would have trouble with
this.

NOTE: I'm certainly not an expert, so if I've left anything out, anyone should
feel free to correct me!

( _pssst - this might be the only way of getting anything out of these folks._
)

~~~
StavrosK
Oh, sorry, I'm not a native English speaker, which confused things. This is
the clearest explanation on monads I've seen yet. I am going to try to
implement these in Python right away, I think something like "return 1" should
do the trick. Version 2 will support different values of 1.

