
Monads as a Programming Pattern - charmonium
https://samgrayson.me/2019-08-06-monads-as-a-programming-pattern/
======
pjc50
I think monads highlight something underappreciated about programming, which
is that different people regard very different things as "intuitive". It
almost seems that modalities of thinking about programming are bigger,
external things than programming itself. Certainly they're barriers to
learning.

Like Lisp, there seems to be about 10% of the programmer population who think
"ah this is obviously the clearest way to do it" and the remaining 90% who go
"huh?", and the 10% are really bad at explaining it in a way the others can
grasp.

The two monad explainers that really resonated with me were:

\- How do you deal with state in a language that would prefer to be stateless?
Answer: wrap _the entire external universe_ and all its messy state up into an
object, then pass that down a chain of functions which can return "universe,
but with some bytes written to the network" (IO monad)

\- If you have a set of objects with the same mutually pluggable connectors on
both ends, you can daisy-chain them in any order like extension cables or toy
train tracks.

(It's a joke, but people need to recognise why "A monad is just a monoid in
the category of endofunctors" is a bad explanation 99% of the time and
understand how to produce better explanations)

~~~
stcredzero
_How do you deal with state in a language that would prefer to be stateless?_

Encapsulation? No one gets direct access to the state. Instead, there are
methods or functions for dealing with the state indirectly, crafted to protect
those outside.

 _Answer: wrap the entire external universe and all its messy state up into an
object, then pass that down a chain of functions which can return "universe,
but with some bytes written to the network" (IO monad)_

Sounds like "Outside the Asylum" from the _Hitchhiker 's Guide to the Galaxy_
universe. Basically, someone decided the world had gone mad, so he constructed
an inside-out house to be an asylum for it.

[http://outside-the-asylum.net/](http://outside-the-asylum.net/)

"A monad is a type that wraps an object of another type. There is no direct
way to get that ‘inside’ object. Instead you ask the monad to act on it for
you." How is a Monad anything different than a particular kind of object
wrapper?

[https://www.infoq.com/presentations/functional-pros-
cons/](https://www.infoq.com/presentations/functional-pros-cons/)

~~~
Quekid5
The person you're replying to is talking about handling _mutable_ state in a
"stateless" way. That's a _big_ distinction.

~~~
stcredzero
_The person you 're replying to is talking about handling mutable state in a
"stateless" way. That's a big distinction._

How so? Why is it such a big distinction? Why isn't that just encapsulation?
"Handling mutable state in a 'stateless' way" is basically just Smalltalk
style Object Oriented programming. (As opposed to Java or C++, which has some
differences.)

~~~
diegoperini
It is encapsulation with the mandatory law stating that an encapsulation of an
encapsulation must be as deep as a single encapsulation.

Note that this informal statement doesn't necessarily mean you have to be
encapsulating data. A behavior, a contract, an assertion, compositions of all
of these etc can also be encapsulated.

Fun ideas (not necessarily true but fun to think about):

* Monads kinda convert nesting to concatenations.

* A monad is the leakiest of the abstractions. You are always a single level of indirection away from the deepest entity encapsulated within.

* What's common among brackets, curly braces and paranthesises(?) is them being monadic if you remove them from their final construction while keeping the commas or semicolons.

Very important note: You should have already stopped reading by now if you got
angry to due these false analogies.

~~~
atombender
Any references that explain the "converts nesting to concatenation" idea? I
find it fascinating, in particular because I write a lot of code that works on
deeply nested data structures -- structs of values (which can be structs) or
lists of values. The distinction between struct, list and value and the need
to treat them differently in code is interesting and annoying, and goes beyond
merely working with functors and applicables. I don't understand lenses at
all, but I understand monads.

~~~
diegoperini
Do ctrl-f for "Nested Operator Expressions" in this piece:
[https://martinfowler.com/articles/collection-
pipeline/](https://martinfowler.com/articles/collection-pipeline/)

Some other references helped me along the way:

* [http://www.lihaoyi.com/post/WhatsFunctionalProgrammingAllAbo...](http://www.lihaoyi.com/post/WhatsFunctionalProgrammingAllAbout.html)

* [http://learnyouahaskell.com/chapters](http://learnyouahaskell.com/chapters)

~~~
atombender
Reading a little more about it, I think the concatenation idea more properly
fits with the join operator, which acts like a flatten function.

------
kybernetikos
I think the programming pattern paradigm is the right way to explain monads
(as you can tell from my own monad explanation:
[https://kybernetikos.com/2012/07/10/design-pattern-
wrapper-w...](https://kybernetikos.com/2012/07/10/design-pattern-wrapper-with-
composable-actions/)) The category theory language around it is off-putting to
working programmers, and many of the ways people explain it is by trying to
introduce yet more terminology rather than just working with the perfectly
adequate terminology that working programmers already have.

I think part of it is that lots of languages don't have sufficient abstraction
ability to encapsulate the monad pattern in their type system, and those that
do tend to be academic focused. That doesn't mean you can't (and do) use
monads in the other languages, it's just that you can't describe the whole
pattern in their type systems.

I was pretty sad that the discussion around javascript promises sidelined the
monad pattern.

~~~
tomstuart
In my experience it’s easiest for people to understand monads when they’re
presented as an abstract data type (e.g. what I wrote at
[https://codon.com/refactoring-ruby-with-monads#abstract-
data...](https://codon.com/refactoring-ruby-with-monads#abstract-data-types))
rather than a programming pattern, because despite having “abstract” in the
name, abstract data types are a relatively concrete thing that programmers
already know how to use.

~~~
keithyjohnson
I watched that talk a while ago and it was great, thank you.

------
noelwelsh
This seems a pretty good introduction to monads.

There is a cliche that no-one can write a good introduction to monads. I don't
think that is true. My opinion is more that monads were so far from the
average programmer's experience they could not grok them. I think as more
people experience particular instances of monads (mostly Futures / Promises)
the mystique will wear off and eventually they will be a widely known part of
the programmer's toolkit. I've seen this happen already with other language
constructs such as first-class functions. ("The future is here just not evenly
distributed.")

~~~
ajnin
"Introduction to monads" articles generally miss the mark because either 1)
they insist on using Haskell syntax throughout, and this is most likely to be
unfamiliar and obtuse to programmers looking for this kind of articles.
Expecting people to learn a new syntax at the same time as a new concept is
bound to be confusing. At least it was for me when I first came across the
idea. Or 2) they go through a bunch of examples with various names and number
of methods, like Maybe and Collection in this article, and the reader is
supposed to infer the common structure themselves. At least this article goes
through the formal definition, but I think that ideally that should come
first, as it is easier to see the structure of the examples once you have
established a mental model.

~~~
dmitriid
> they insist on using Haskell syntax throughout, and this is most likely to
> be unfamiliar and obtuse to programmers looking for this kind of articles.

Indeed, that is a big part of a problem.

I find "Functional Programming Jargon" [1] extremely approachable (if you
already know modern JS) even though it has been pointed out that their
definitions might not be "pure"/correct enough.

[1] [https://github.com/hemanth/functional-programming-
jargon#mon...](https://github.com/hemanth/functional-programming-jargon#monad)

~~~
mlevental
you know of something like this in Python? I know enough js to read that but
I'd prefer python

~~~
dmitriid
Sadly, no :(

------
mbrock
I think for newbies there are two separate aspects to explain: first an intro
to algebraic structures perhaps using groups as an example, then monads in
particular.

It’s important to emphasize that algebraic structures are abstractions or
“interfaces” that let you reason with a small set of axioms, like proving
stuff about all groups and writing functions polymorphic for all monads.

With monads in particular I think the pure/map/join presentation is great.
First explain taking “a” to “m a” and “a -> b” to “m a -> m b” and then “m (m
a)” to “m a”. The examples of IO, Maybe, and [a] are great.

You can also mention how JavaScript promises don’t work as monads because they
have an implicit join semantics as a practical compromise.

~~~
chongli
_groups as an example_

Why not go all the way and teach functors and applicatives before monads? Then
the student can see that monads are just a small addition built on top of the
other two. Functors, in particular, are very easy to grasp despite their
intimidating name. They just generalize _map_ over arbitrary data structures:

    
    
        l_double : List Int -> List Int
        l_double xs = map (* 2) xs
    
        f_double : Functor f => f Int -> f Int
        f_double xs = map (* 2) xs
    

Applicatives are a little bit trickier but once you get them, there's only a
tiny jump to get to monads. Taught this way, people will realize that they
don't need the full power of monads for everything. Then, when people learn
about idiom brackets [1], they start to get really excited! Instead of writing
this:

    
    
        m_add : Maybe Int -> Maybe Int -> Maybe Int
        m_add x y = case x of
                         Nothing => Nothing
                         Just x' => case y of
                                         Nothing => Nothing
                                         Just y' => Just (x' + y')
    

You can write this:

    
    
        m_add' : Maybe Int -> Maybe Int -> Maybe Int
        m_add' x y = [| x + y |]
    

Much better!

[1] [http://docs.idris-
lang.org/en/latest/tutorial/interfaces.htm...](http://docs.idris-
lang.org/en/latest/tutorial/interfaces.html#idiom-brackets)

~~~
noelwelsh
Functors are not useful for much on their own, so they are difficult to
motivate.

The Haskell formulation of applicatives doesn't make much sense outside of
languages where currying is idiomatic---which is most languages. In these
languages you tend to see the product / semigroupal formulation, and here
applicatives become a bit trickier to explain as you need more machinery.

~~~
mrbrowning
Functors enable the Fix functor and, from there, the whole universe of
recursion schemes, so I'm not sure that I agree that they're not useful on
their own.

~~~
UncleMeat
Sure but virtually nobody cares about how to finitize a recursive function
when they are trying to learn a new programming paradigm. Recursion seems to
work just fine in languages that don't have any of these bells and whistles.

"Hey you can implement Fix" is like saying "now you can program in green" for
most readers.

~~~
mrbrowning
Oh, certainly. My assumption was that the GP meant that functors aren't useful
on their own _in general_, rather than in the particular context of someone
just getting into the typed functional paradigm. And, of course, recursion
does work just fine in other languages, but (and I'm saying this more for
posterity than as a retort since I assume you're well aware of this point)
recursion schemes offer a layer of abstraction over direct recursion that
eliminates the need to manually implement various recursive operations for
each of the data structures you have at hand. As with a lot of the higher-
level constructs in languages like Haskell, that level of abstraction may not
have any practical benefits in most domains, but it's nice to have when it
does offer a benefit in a particular domain.

------
toastal
I get the intention but it's even harder to understand with this Java/C#
syntax. I feel like if you're gonna talk about FP you should probably
highlight along the Haskell or Scala code (or similar) and provide OOP stuff
for reference in case it's not clear. It ends up being so verbose that I don't
many people see the 'point'.

~~~
secure
To me, reading examples in a syntax I’m familiar in helps me _much_ more than
reading them in a language where the concept might be elegant to express, but
hard for me to get into.

I think it’d be best to include examples in a number of languages with a
lanugage selector, actually. That way, people who are fluent in functional
languages can read that version, and others can read the one they are more
fluent in.

~~~
toastal
Here's a real life tangential example: I'm learning Thai. When I first started
it was useful to show the Latin alphabet to get a grasp but it's often
difficult or inaccurate to try to express that language without the system
designed to express it. For instance, many romanizations lack a tone marker
for tonal language, or don't show vowel length when it matters. Or for
laughable example of พร, meaning 'blessing' but also a common woman's name,
being traditionally romanized to 'porn' with its silent r when 'pawn' is a
more neutral pronunciation for all English dialects (or /pʰɔːn/). Also, not
being able to read or write the language, you will have a difficult time
effectively engaging with the community and understanding the world around
you.

The point is, functional languages are designed to express these concepts with
much, much less cruft with extra features like currying, immutability-by-
default, and type classes. Yes, use your current language to get oriented, but
if you're going to really learn it, pick up a proper syntax to express it.

~~~
saghm
Sure, but to extend your metaphor, using Haskell to teach non-Haskell
programmers about monads is like using Thai to teach English speakers the
history of Thailand; the language might be better suited for the topic, but
the people you're teaching don't know it, and learning it is orthogonal to the
actual thing you're trying to teach them.

~~~
toastal
That's why I said have both with the emphasis on the one that better expresses
it so people know what you're aiming for. I've written FP blog posts in the
past with Javascript to accompany just in case it wasn't clear because of
syntax. But if you'd just looked at the Javascript, your takeaway will
probably be similar to many FP-in-JS articles of 'why so much ceremony?' The
'other' language is merely a bridge. And if you can only communicate from the
bridge language's perspective, you won't be able to grasp intermediate topics.

------
jerf
This seems pretty good; the only thing on my mental checklist of "common monad
discussion failures" is only a half-point off, because I'd suggest for:

"A monad is a type that wraps an object of another type. There is no direct
way to get that ‘inside’ object. Instead you ask the monad to act on it for
you."

that you want to add some emphasis that the monad interface itself provides no
way to reach in and get the innards out, but that does not prevent _specific_
implementations of the monad interface from providing ways of getting the
insides. Obviously, Maybe X lets you get the value out if there is one, for
instance. This can at least be inferred from the rest of the content in the
post, since it uses types that can clearly be extracted from. It is not a
_requirement_ of implementing the monad interface on a particular
type/class/whatever that there be no way to reach inside and manipulate the
contents.

But otherwise pretty good.

(I think this was commonly screwed up in Haskell discussions because the IO
monad looms so large, and does have that characteristic where you can never
simply extract the inside, give or take unsafe calls. People who end up coming
away from these discussions with the impression that the monads literally
never let you extract the values come away with the question "What's the use
of such a thing then?", to which the correct answer is indeed, yes, that's
pretty useless. However, specific implementations always have some way of
getting values out, be it via IO in the case of IO, direct querying in the
case of List/Maybe/Option/Either, or other fancy things in the fancier
implementations like STM. Controlling the extraction is generally how they
implement their guarantees, if any, like for IO and STM.)

------
pron
I think it's important to separate the issue of what monads are/how they're
used from the question when they _should_ be used at all. While monads are
very useful for working with various streams/sequences even in imperative
languages, they are used in Haskell for what amounts for effects in pure-FP,
and _that_ use ("Primise" in the article) has a much better alternative in
imperative languages. Arguably, it has a better alternative even in pure-FP
languages (linear types).

Here's a recent talk I gave on the subject:
[https://youtu.be/r6P0_FDr53Q](https://youtu.be/r6P0_FDr53Q)

------
goto11
The problem with monads is they are horrible without some form of syntax
sugar. I like the metaphor of "programmable semicolon", but in languages
without some built-in support, the "semicolon" becomes repetitive boilerplate
which is more code than the actual operations happening in the monad.

~~~
fxj
I like the "do" notation in Haskell because it boils down the meaning of
monads to the following:

Monads let you break the functional programming paradigm that a function
should have the same value each time it is called. e.g.

    
    
        do {
        x <- getInput
        y <- getInput
        return x+y }
    

here getInput is called two times and each time it has a different value. When
you now think about how this can happen in a functional language you have to
understand what a monad does.

The heureka moment came when I learned about the flatMap in scala which is
nothing else but the bind function in haskell ("just flatmap that sXXt") and
voila thats how to use monads.

See the following explanation:

[https://medium.com/free-code-camp/demystifying-the-monad-
in-...](https://medium.com/free-code-camp/demystifying-the-monad-in-scala-
cc716bb6f534)

------
namelosw
It's hard to explain 20 years ago, but today if someone has used enough
something like Reactive extension, Promise, LinQ, async/await, Optional, etc.
There's a great chance to make one wonder about the similar pattern behind
this, and then he can understand the abstraction very easily.

------
mikorym
I once googled "functional programming for category theorists" and obviously
got instead to "category theory for programmers" (incidentally I use
Milewski's book in this reverse way).

I still have a rudimentary understanding of functional programming (apart from
the canonical "it's just an implementation of lambda calculus"). And I have to
say that without exercise and training one grabs at wisps and mist. In
mathematics it's also like this, you often have your favorite prototypical
monad, adjunction, group, set, etc. (e.g.: The adjunction Set->Set^op by
powerset is a strong contender.) And I view axiomatic systems in essence as
sort of list of computational rules (e.g.: transitive closure).

I haven't found some idiosyncratic project to code in Haskell yet though...

------
zug_zug
I guess I don't get all this "monad" stuff. This article talks about 3 types
of monad. An optional, a list, and a future.

However an optional is really just a list constrained to size 0 or 1. And a
future is often called "not truly a monad."

So I question the value of explaining this abstraction in great detail over so
many articles when people struggle to come up with more than 1 concrete
example of it (Lists), an example that engineers have already understood since
our first month coding.

Maybe somebody can speak to this more.

~~~
rkido
> However an optional is really just a list constrained to size 0 or 1.

What?

~~~
aeorgnoieang
The sentence you quoted would make more sense if you interpret "is really
just" like a mathematician, i.e. they're 'equivalent' in the sense that you
can 'map' everything important about either in both directions.

More concretely, "an optional" is something that either 'has a value' or 'does
NOT have a value'. So it "is really just a list constrained to size 0 or 1" in
the sense that an optional that 'does NOT have a value' is equivalent to a
list of size 0, i.e. a list with no contents/members, and an optional that
DOES 'have a value' is equivalent to a list of size 1, i.e. it's 'value' is
the single/unique member of the list.

Think of statements like 'is really just' in the sense that an integer between
0 and 255 'is really just' 8 ordered bits – they're 'equivalent' in the sense
that you can map all possible values of those integers to all possible values
of 8 ordered bits, and vice versa, and (importantly in a mathematical sense)
in a way such that every integer is mapped to a single set of 8 ordered bit
values and every set of 8 ordered bit values is mapped to a single integer. In
mathematics that's often described as an 'isomorphism' which is, in working
programmer terminology, just a way to convert back and forth between two sets
of values 'perfectly and losslessly'.

------
hardwaresofton
Another really good functional (as in related to how they work) explanation of
monads:

[http://adit.io/posts/2013-04-17-functors,_applicatives,_and_...](http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html)

It's somewhat more than a monad explanation -- it covers functors and
applicatives, and is somewhat haskell specific, but it was one of the guides
that really clicked for me when I was trying to grok monads

------
l0w
wow nice post. I can also recommend Mark Seemanns take on monads:
[https://blog.ploeh.dk/2019/02/04/how-to-get-the-value-out-
of...](https://blog.ploeh.dk/2019/02/04/how-to-get-the-value-out-of-the-
monad/)

------
jgodbout
This really was excellent. It actually helps with the category theory def.

------
stevefan1999
This recalled me a joke on monads: "A monad is just a monoid in the category
of endofunctors, what's the problem?" [0]

[0]: [http://james-iry.blogspot.com/2009/05/brief-incomplete-
and-m...](http://james-iry.blogspot.com/2009/05/brief-incomplete-and-mostly-
wrong.html), 1990 Haskell entry

