
An Overview of the Monad - kvalle
https://functional.christmas/2019/5
======
cousin_it
> _we can think of a monad as a datatype with_

Aaaaaaa

Be more precise about instance relations! They are the first source of
confusion!

\- String is a type. The value "abcde" is an instance of that type.

\- Num is a typeclass. The type Int is an instance of that typeclass. The
value 12345 is an instance of that type.

\- Monad is a typeclass whose instances are generic types. The generic type
List is an instance of that typeclass. The type List Int is an instance of
that generic type. The value [1,2,3] is an instance of that type.

Explaining the operations of Monad is only useful when you're comfortable with
"value belongs to type which belongs to generic type which belongs to
typeclass".

~~~
patrickthebold
And if you think about it, you're just asking the author to be clear about the
types of the things they are talking about.

------
Rerarom
My problem with understanding monads was as follows: I had no problem with
understanding the mathematical definition, it was easy to check that a given
monad verifies the axioms.

No, my problem was this one: everyone was saying "hey, you know if you have a
purely functional language, it would be impossible to have IO, since e.g. a
read function would have different outputs every time. We solve that with
monads."

But that didn't feel like an explanation. I couldn't draw a line from the
monad axioms to dissolving that impossibility. It was like saying "Einstein
says we can't do FTL, but we can solve that with monads".

~~~
codeflo
The way most people explain this is completely backwards. Monads don't
actually solve the I/O problem. So forget about monads and just consider how
to mathematically model I/O.

Take something like getStrLn (which reads a line from STDIN). What is
"getStrLn", as a mathematical object? It's not a string, rather, it's some
kind of "I/O operation" that when executed, returns a string. Haskell calls
such an object an "IO String". Similarly, the expression (putStrLn "foo") is
an I/O operation that when executed, doesn't return anything. Haskell calls
this an "IO ()".

Once you develop an intuition of I/O operations, you can see how you might
want to combine atomic I/O operations into larger and larger I/O operation,
feeding the output from one as input into the other. Or how you could treat a
plain Int as an "empty" I/O operation that when executed, simply returns the
Int. And how your entire program, its "main" entry point, can be modeled
simply as one large I/O operation.

You can do all of that, and write every possible kind of I/O code in Haskell,
without ever learning about monads.

What are monads for, then? They generalize the structure of this approach,
with its (>>=) and return operators, and apply it to other cases that don't
have anything to do with I/O. But this step is completely optional! This is
very similar to how the idea of a mathematical "field" generalizes the
arithmetic operators (+, -, *, /) and applies them to objects that don't look
anything like the rational numbers. You don't have to learn about fields to
successfully use rational numbers. And we would never dream of explaining the
abstract idea of fields to people before we introduce them to rational
numbers. Yet almost every I/O tutorial in Haskell begins with a half-baked
explanation of monads.

~~~
Rerarom
That is how I finally got it, because I knew what groups/rings/fields were but
did not realize at first that monads were just another abstraction like those
and not an ontologically fundamental category. The way monads are usually
presented leads you to believe that there is something magical in those axioms
that somehow makes the impossible happen.

------
BoiledCabbage
I'll post this again "If you are interested in learning functional programming
_do not_ learn about monads".

There is no practical justifiable reason to learn about monads unless you
already know Haskell. And there is no reason to learn Haskell unless you
already know another statically typed functional language.

If you are interested in learning functional programming then either

Learn dynamically typed functional programming and pick Clojure (or Racket).

Or learn statically typed functional programming and learn Elm then F# (or
OCaml).

Haskell is the worst language you could choose to learn FP. If you're trying
to lean FP, stay away from it. If you're a huge FP advocate don't push it. And
finally monads tutorials are the white noise at the end of a wrong way track
in learning about functional programming.

Outside of Haskell, monads are about as important in terms of learning,
knowing and effectively using functional programming languages and concepts,
as braces being on the same line or next line is important to learning about
general programming. It's not.

Does that mean no-one can ever mention a monads, no of course not. But it's
such a tiny topic, that it's absurd it gets so much discussion like it's some
key to learning fp or some incredibly crucial concept. It's not.

~~~
jolmg
> Haskell is the worst language you could choose to learn FP.

Why?

~~~
BoiledCabbage
Can't post full thoughts now, but will cover a few points.

Haskell has an extremely steep learning curve. And you have to make it very
far up that curve to begin to see or understand any of the value you're
getting from FP. Up until then, it's just different and it's hard to see why
you're jumping through all of these hoops when you could easily use a non FP
language. You have to pay very significant signiticant learning costs before
the benefits of any new insights stary to outweight those costs. Elm in
contrast you can honestly learn in a weekend and demonstrates 60% of the
values a user gets from FP. Very high ROI for expanding your knowledge of
programming ideas and approaches.

Haskell evolved as a language to explore programming language ideas in, as a
result it is filled with warts. You still need to learn and deal with a lot of
those warts to be decently productive, none of those warts are relevant
concepts just warts. You also need to be perfect and jump through a lot of
hoops with strict adherence to all the rules to get things working. In
contrast F# allows you to be non strict in your application of FP concepts.
This is actually really beneficial for learners. It allows for separation of
concerns - apply the new concept your learning now, and do everything else in
the way you're accustomed it. Its roughly equivalent to updating a codebase
with gradual typing. Your a lot more likely to be successful if you can add
typescript typing one file or area at a time, than if typescript only worked
if all of your files or non of your files had types.

Also Clojure (and F#) rely on the JVM and .NET so a lot practical use cases
are already solved and solved well. As well, a lot of your existing knowledge
will transfer over.

Finally once you've learned those core FP concepts Haskell is _significantly_
easier to learn so you can easily dive into the Haskell unique parts.

There are other thoughts, but this should be a good jist.

~~~
verttii
Interestingly, I started off with Elixir & Elm and then moved on to Haskell.
Elixir & Elm both feel like DSLs with abstraction level purposefully
constrained relatively low. A lot of the concepts in those languages didn't
make sense until I started picking up Haskell.

I don't really know if it's ultimately _worth it_ or not but as a programmer I
want to evolve by raising the abstraction level in my code. Haskell is the
perfect platform for that.

Btw any examples of those warts in Haskell?

------
bobmichael
I found the article the author links to, which explains functors,
applicatives, and monads in pictures, to be way more helpful:
[http://adit.io/posts/2013-04-17-functors,_applicatives,_and_...](http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html)

~~~
itronitron
Yeah, interesting to learn that a monad is a value in a box, _almost as if it
were an object_

~~~
chongli
It isn’t though. A monad is just an abstract mathematical object that
satisfies a few axioms. It doesn’t have anything to do with implementations or
computations, let alone objects in the OOP sense.

It’s better to think of it like this: a value in a box is one example of a
data type that can satisfy the monad axioms. Another example is a delayed
computation that produces a value when executed. Yet another is a delayed
computation which produces no value at all but causes a message to be printed
to the screen.

------
harry8
Oh for the day when monad tutorials and explanations don't outnumber useful
Haskell programs with a purpose other than programming a computer by many
orders of magnitude.

The list of such programs hasn't grown much since the last time I noticed that
we did this 2-3 years ago has it? Git annexe, ion, pandoc, and..? There were a
couple more than that, i think.

~~~
goto11
“There are only two kinds of languages: the ones people complain about and the
ones nobody uses.”

Except for Haskell which happens to be both!

------
goto11
> We simply cannot think about such abstract concepts without introducing some
> sort of metaphor.

Metaphors are overrated. Often they obscures more than they explain,
especially for such an abstract concept.

What if you had to explain "statements" with a metaphor? Or "expression"? I
challenge anyone to come up with metaphors which help more than they confuse.

We learn programming concepts through examples, and seeing how they are
useful. Not through metaphors.

~~~
maweki
But usually nobody cares about or checks whether your implementation of the
operator your overriding still obeys all the axioms. Sometimes we have tests
whether some interface implementation fulfills some axioms, but usually we do
not.

Somehow with monads we do. And I suspect the reason is, that monads come from
an area where of Programming where proving a program correct is preferred to
testing. And for proving correctness, you need a proper specification and then
implementations that follow that specification. And a specification is done
using abstract concepts.

If you want to prove anything about your program (or even understand obscure
edge cases), concepts through examples will not work for you.

~~~
marcosdumay
> But usually nobody cares about or checks whether your implementation of the
> operator your overriding still obeys all the axioms.

Make some non-associative implementation of (+) and see on how many compilers
code using it will work.

------
simendsjo
Bartosz Milewskis Category Theory for Programmers also has nice explanations
for all these concepts. Haven't read through everything, but what I've read
has been very high quality.

[https://bartoszmilewski.com/2014/10/28/category-theory-
for-p...](https://bartoszmilewski.com/2014/10/28/category-theory-for-
programmers-the-preface/)

~~~
phs
His video lecture series is also well-paced.

[https://www.youtube.com/user/DrBartosz/videos](https://www.youtube.com/user/DrBartosz/videos)

------
the_af
Here's an interesting article about the "Fallacy of Monad Tutorials" and why
most metaphors fail: [https://byorgey.wordpress.com/2009/01/12/abstraction-
intuiti...](https://byorgey.wordpress.com/2009/01/12/abstraction-intuition-
and-the-monad-tutorial-fallacy/)

The key insight here is: there are no shortcuts. Most metaphors are useful but
limited. Once a metaphor "clicks" for a person, they forget all the work it
took them for the concept to really click, and think the shortcut will help
other people: "Monads are like burritos! If only other people understood this,
they would get them!".

> _" But now Joe goes and writes a monad tutorial called “Monads are
> Burritos,” under the well-intentioned but mistaken assumption that if other
> people read his magical insight, learning about monads will be a snap for
> them. “Monads are easy,” Joe writes. “Think of them as burritos.” Joe hides
> all the actual details about types and such because those are scary, and
> people will learn better if they can avoid all that difficult and confusing
> stuff. Of course, exactly the opposite is true, and all Joe has done is make
> it harder for people to learn about monads, because now they have to spend a
> week thinking that monads are burritos and getting utterly confused, and
> then a week trying to forget about the burrito analogy, before they can
> actually get down to the business of learning about monads."_

Already in this comments section I see this kind of misunderstandings: "monads
are containers with values in them, almost like objects", "monads are for
effectful computations", "monads are for imposing a sequential order", etc.
These are all particular uses of monads, but not what monads _are_.

------
sullyj3
[https://xtendo.org/monad](https://xtendo.org/monad)

This is the best introduction to the topic I've seen for Haskell beginners. It
provides some much needed context.

~~~
classified
That's a great presentation that every Haskell beginner should see.

As an extra it has some insights on the failure modes of (monad) tutorials,
like " _Using things you don 't know in order to teach you something you don't
know_".

------
the_af
This isn't an useful article about monads in my opinion. It adds neither
insight nor depth, is completely redundant given the hundreds of articles out
there, and is unlikely to give anyone struggling with monads an insight that
would help them. Particularly egregious is the fact it introduces a formal
definition only to immediately ditch it because it's "probably pretty
incomprehensible" \-- and this in 2-minute read with no room to spare.

Besides, everybody knows monads are not like containers. They are like
burritos!
[https://blog.plover.com/prog/burritos.html](https://blog.plover.com/prog/burritos.html)

------
tutfbhuf
I think in order to understand Monads you should try to invent them yourself.
Try to create a pure IO function in the programming language you know best.
Consider the state of the world as input parameter of your function and return
a modified version of the worlds state. Then try to compose IO functions and
try to write an interface for IO function composition.

------
ashton314
This was the first time I've seen the "A monad over a category C is a triple
(T,η,µ)" in a definition. That confirmed some mental models that I was a
little unsure about. I'm new to the fp scene; still trying to get a good
foundational understanding.

~~~
TheAsprngHacker
If you're new to functional programming, you don't need to worry about the
category theory definition. Especially since this tutorial simply mentions it
as a way to say, "this is too complicated for us, so we're going to explain it
another way," and makes no attempt to break down the definition as code. In
fact, be careful that you're not seeing category theory definition and
_misunderstanding_ it to confirm a mistaken intuition.

The category-theoretic definition basically states that a monad is an
endofunctor T equipped with two operations, return :: a -> T a and join :: T
(T a) -> T a. T being a endofunctor just means that it is "mappable," AKA it
has a function fmap :: (a -> b) -> T a -> T b that "lifts" functions into the
type.

Monads capture the idea of flattening. If fmap changes the "contents" while
preserving the "shape," join collapses nested layers to change the "shape."

Instead of join, the Haskell typeclasses (and this article) uses another
function called bind, or >>=. You can derive join from >>=, and you can derive
>>= from join and fmap. For lists, a more familiar name for >>= might be
flatmap.

------
skrunch
The visualisation linked to at the end goes into some more detail and was
definitely worth the extra 5 minute read for me!

------
AzzieElbab
A monad certainly is not a container. None of the functional patterns are
containers.

------
jcmontx
TIL that the domain extension ".christmas" exists. I wonder why though...

~~~
WorldMaker
Capitalism

------
selbekk
I've always struggled to grok the concept of monads. Worth the 2 minute read.

~~~
tylerhou
Except this “simple” metaphor isn’t too useful. For monads like IO and State,
“monad as a container” is a stretch. And some don’t fit at all — the list
monad often is imagined as a computational context with nondeterminism, not
simply a container.

[https://byorgey.wordpress.com/2009/01/12/abstraction-
intuiti...](https://byorgey.wordpress.com/2009/01/12/abstraction-intuition-
and-the-monad-tutorial-fallacy/)

~~~
mikekchar
I don't really understand your point of view. Especially the list monad is
literally a list. The shape of bind for the list monad is [a] -> (a -> [b]) ->
[b]. If that's not a container, I don't know what is. The fact that it can be
used to solve problems where the list represents a non-deterministic result is
really secondary. I mean, I suppose you can think of it as being different,
but it seems a lot more complicated in my mind.

I think some "containers" a definitely hard to envision. A partially applied
function is also a monad (i.e. it's trivial to write a meaningful bind for
it). It may be hard to think of a partially applied function as "containing"
the applied parameters, but I still think that's easier than any other way of
envisioning it. But maybe it's a matter of horses for courses.

------
darkkindness
I always see monad tutorials like this conflate (1) "understanding using
particular monads" with (2) "understanding using monads in general", which are
completely different things. Luckily it's easy to not confuse those two with
(3) "understanding monads abstractly" which tends to break out the category
theory, but some tutorials like jumping on that too.

To demonstrate the differences, suppose now that you're deep diving into a
codebase which depends on a Async monad. Your eyes light up and you go aha(!)
that means async programming, I've done that before! The point is, you saw
"Async", you know it means "make some task's outcome depend on a previous
task", which is the behavior of bind for that particular monad. Without (1)
the word "monad" is really unnecessary. Why not just refer to bind as some
arbitrary async-API function? In summary, you don't need (1), (2), or (3) for
this! Monad is just a word.

Okay, when do we need (1)? Let's say you've changed companies, and now you're
plugged into another codebase and oh(!) there's that word "monad" again, but
this time it's the "Future" monad. Another whole API to learn... but soon you
realize that it's again the same old "make some task's outcome depend on a
previous task". Except they just call it "Future", and instead of "bind", they
say "flatMap" which is the same thing! And you bump into it again and again
with different names -- Deferred, Aff, Task -- but in the end it's the same
behavior and API. How upsetting that they don't call them all Async and be
done with it! But if you have (1) you'll know they are just the same monad,
given different names. That's (1): familiarity with the usage of a particular
monad. Later on you might collect understanding of the Option/Maybe/Nullable
monad, or the Result/Either/Error monad, or the List/Stream/Nondeterministic
monad, so now names don't bother you because you know CONCEPTS, but all of
this is still (1) if each monad is being treated as an independent API to
grok.

That's where (2) comes in. Suppose now that you're deep diving into a codebase
which depends on the "Anisotrope" monad. You've never heard of this before[0],
but you know monads in general i.e. (2), so you know you can make functions
whose output (an Ansiotrope object) depends on some property of a Ansiotrope
object, and that all the details about this dependency can be found in the
definition of bind for this particular monad. In other words you can use
knowledge of (2) to quickly adapt to new monads without having to regard them
as a completely new concept. It lets you answer questions like "what's this
Probability monad supposed to do? what about this Forkable monad?" in a
general way. Conversely, you can now start writing monads of your own by
thinking about what bind could mean for your new "Transmogrifying" monad.

Is this useful? Imagine learning all OOP patterns knowing that every pattern
is the same concept except for this one thing: bind. That means it's
relatively trivial to learn these patterns and make new ones. Except they're
not OOP patterns, it's monads, and no, you can't generalize OOP patterns the
same way.

Anyways, this is also where "monad is a box"-esque metaphors fall short. It's
rather descriptive of particular monads, but doesn't generalize well when you
start reaching for many others: Reader(environment-passing),
List(nondeterministic computations), Probability(probabilistic programming),
or fun ones like parser monads, Amb(backtracking), Tardis(state-access-
timeline-specifying)[1].

[0] I hope not, since I made it up. If you have (3) you're probably deriving a
working definition already. Have fun! [1]
[http://hackage.haskell.org/package/tardis-0.4.1.0/docs/Contr...](http://hackage.haskell.org/package/tardis-0.4.1.0/docs/Control-
Monad-Tardis.html)

~~~
AnimalMuppet
I really like the distinctions you are drawing. And I think that it's better
for people to walk through this in (1), (2), (3) order rather than jumping to
(2) or (3) before they know (1) on at least one monad.

> Imagine learning all OOP patterns knowing that every pattern is the same
> concept except for this one thing: bind. That means it's relatively trivial
> to learn these patterns and make new ones. Except they're not OOP patterns,
> it's monads, and no, you can't generalize OOP patterns the same way.

From the OOP perspective, though, monad is a pattern where you only have one
behavior (bind) that you can customize, and you have to do _everything_
through that one behavior. That looks like a straightjacket. Sure, it composes
well, but... why limit yourself like that?

~~~
darkkindness
Thanks!

> From the OOP perspective, though, monad is a pattern where you only have one
> behavior (bind) that you can customize, and you have to do everything
> through that one behavior. That looks like a straightjacket. Sure, it
> composes well, but... why limit yourself like that?

That's an excellent question. Thinking of monad as a pattern itself, with bind
as its API, made me realize that OOP patterns (as a categorical concept)
aren't the best analogy for the different behaviors monads encode, but rather
monad is just one of the patterns. Makes sense -- there are obviously
behaviors not generalized by monads but are in the realm of OOP patterns. For
instance, the visitor pattern is covered by functors.

(At the time of writing I was thinking about how bind can relate seemingly
disparate behaviors: error handling, async, state, etc. What other useful
structures seem disparate? OOP patterns! And so I fell into the black pits of
"Monads are just like <thing>" myself, where thing = OOP patterns.)

As for the question: One could call it a straightjacket but one could also
call it "the law". Limiting yourself is exactly how Straightjacketed Sam can
ensure correctness properties of the program. Monads force Sam to work within
the monad, so they can only write "a depend on b" in a specific and well-
defined way. This is analogous to how singleton pattern would force Sam to
work with this one instance of an object, or how the factory/smart constructor
pattern forces ensures only certain (valid) objects can exist. If any of these
restrictions are too limiting, there's no need to use the patterns, but you'll
also lose the laws (guarantees)!

~~~
AnimalMuppet
Lose the straightjacket, lose the guarantees. That makes sense. I had been
thinking of it as _just_ a straightjacket.

And, as you point out, there are some OO patterns that we can also provide
useful guarantees and constraints.

------
mbdesign
Didn't even know there existed a .christmas domain.

~~~
classified
Only accessible while Santa Claus is visible in the night sky.

------
steven741
This was a little sparse but it was a fun read.

------
mikorym
> A monad is a concept that belongs to a branch of mathematics called category
> theory, where it was introduced in the 1960s.

No. [1]

[1] _General Theory of Natural Equivalences_ , Mac Lane and Eilenberg, 1945.

[https://www.ams.org/journals/tran/1945-058-00/S0002-9947-194...](https://www.ams.org/journals/tran/1945-058-00/S0002-9947-1945-0013131-6/S0002-9947-1945-0013131-6.pdf)

~~~
mikorym
Sorry, I misread; monads were only introduced later. The above paper
introduced the field of category theory itself.

