<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Functional-Programming on Max Bonnefin</title><link>https://bonnef.in/tags/functional-programming/</link><description>Recent content in Functional-Programming on Max Bonnefin</description><generator>Hugo -- gohugo.io</generator><language>en</language><managingEditor>max@bonnef.in (Max Bonnefin)</managingEditor><webMaster>max@bonnef.in (Max Bonnefin)</webMaster><copyright>Max Bonnefin</copyright><lastBuildDate>Tue, 02 Jun 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://bonnef.in/tags/functional-programming/index.xml" rel="self" type="application/rss+xml"/><item><title>Yet Another Monad Explanation</title><link>https://bonnef.in/posts/monads/</link><pubDate>Tue, 02 Jun 2026 00:00:00 +0000</pubDate><author>max@bonnef.in (Max Bonnefin)</author><guid>https://bonnef.in/posts/monads/</guid><description>&lt;p>I&amp;rsquo;ve been interested in Haskell and functional programming for quite a while now. The concept was first introduced to me at university and I&amp;rsquo;ll admit that most of it sailed over my head. My earliest programming experiences were exclusively imperative (VBScript, Visual Basic 6, Python, C) and even Object Oriented Programming felt like a giant leap of magic when I first encountered Java. I quickly changed my tune on that front, and Java became a mainstay in my toolbelt as an engineer.&lt;/p>
&lt;p>Surprisingly, Java is also where I discovered my love for functional programming. Those Java developers among you may remember the Java 8 release in 2014, when lambdas, streams and &lt;code>Optional&lt;/code> arrived&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> and suddenly facilitated a much more functional style. This led to a phase of perhaps strangely functional Java code being written and considered best practice. That&amp;rsquo;s where I first started stretching my brain in that direction. Of course, if you want to write clean functional code without side effects, you&amp;rsquo;re better off reaching for a language designed around those ideas. And that&amp;rsquo;s where I fell in love with &lt;a href="https://www.haskell.org/" class="external-link" target="_blank" rel="noopener">Haskell&lt;/a> in all its strongly-typed, lazily-evaluated, side-effect free glory.&lt;/p>
&lt;img
src="https://bonnef.in/images/posts/its-all-functions.webp"
alt="Always has been meme - wait its all functions?"
loading="lazy"
width="600"
style="max-width: min(100%, 600px); height: auto; display: block; margin: 0 auto;"
class="responsive-image"
>
&lt;p>&lt;em>&lt;a href="https://www.amazon.co.uk/Learn-You-Haskell-Great-Good/dp/1593272839/" class="external-link" target="_blank" rel="noopener">Learn You a Haskell for Great Good&lt;/a>&lt;/em> by Miran Lipovača was the book I picked up to learn and I&amp;rsquo;d highly recommend it, or alternatively the &lt;a href="https://learnyouahaskell.github.io/" class="external-link" target="_blank" rel="noopener">open source fork&lt;/a> that&amp;rsquo;s been updated with new information in the 15 years since the original was released. After working through it I felt like I had a solid grasp of Haskell and the core FP concepts. Except for monads.&lt;/p>
&lt;img
src="https://bonnef.in/images/posts/monads-monoids.webp"
alt="A monad is just a monoid in the category of endofunctors"
loading="lazy"
width="600"
style="max-width: min(100%, 600px); height: auto; display: block; margin: 0 auto;"
class="responsive-image"
>
&lt;p>It&amp;rsquo;s almost a meme at this point. Beginners hit monads and bounce off, even though the underlying concept is remarkably simple. If you&amp;rsquo;re coming from an OOP background, the closest mental model is something like &lt;a href="https://en.wikipedia.org/wiki/Fluent_interface" class="external-link" target="_blank" rel="noopener">fluent interfaces&lt;/a> or the &lt;a href="https://en.wikipedia.org/wiki/Builder_pattern" class="external-link" target="_blank" rel="noopener">Builder pattern&lt;/a>: you chain operations together, and each step feeds its result into the next while some hidden machinery manages the context around those results.&lt;/p>
&lt;p>You Google &amp;ldquo;what is a monad,&amp;rdquo; find seventeen blog posts (eighteen now, you&amp;rsquo;re welcome) comparing them to burritos, spacesuits or assembly lines, and come away more confused than when you started. The analogies fail because they obscure what&amp;rsquo;s actually a fairly mechanical idea. Monads are a design pattern for chaining operations together when those operations have some kind of context attached to their results. That context might be &amp;ldquo;this could fail,&amp;rdquo; or &amp;ldquo;this produces side effects,&amp;rdquo; or &amp;ldquo;this depends on some state.&amp;rdquo; The monad gives you a structured way to handle that context without drowning in boilerplate.&lt;/p>
&lt;h2 id="start-with-a-problem-not-a-definition">
Start With a Problem, Not a Definition
&lt;a class="heading-link" href="#start-with-a-problem-not-a-definition">
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading">&lt;/i>
&lt;span class="sr-only">Link to heading&lt;/span>
&lt;/a>
&lt;/h2>
&lt;p>Forget Haskell for a moment. Think about a chain of operations in any language where each step might fail.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>user &lt;span style="color:#ff7b72;font-weight:bold">=&lt;/span> get_user(id)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ff7b72">if&lt;/span> user &lt;span style="color:#ff7b72;font-weight:bold">is&lt;/span> &lt;span style="color:#79c0ff">None&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ff7b72">return&lt;/span> &lt;span style="color:#79c0ff">None&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>address &lt;span style="color:#ff7b72;font-weight:bold">=&lt;/span> get_address(user)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ff7b72">if&lt;/span> address &lt;span style="color:#ff7b72;font-weight:bold">is&lt;/span> &lt;span style="color:#79c0ff">None&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ff7b72">return&lt;/span> &lt;span style="color:#79c0ff">None&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>city &lt;span style="color:#ff7b72;font-weight:bold">=&lt;/span> get_city(address)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ff7b72">if&lt;/span> city &lt;span style="color:#ff7b72;font-weight:bold">is&lt;/span> &lt;span style="color:#79c0ff">None&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ff7b72">return&lt;/span> &lt;span style="color:#79c0ff">None&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ff7b72">return&lt;/span> city
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Every step could return &lt;code>None&lt;/code>. You end up with this staircase of null checks that obscures what you&amp;rsquo;re actually trying to do: get a user, then their address, then their city. The pattern you want is: &amp;ldquo;run this sequence of operations, but if any step produces nothing, short-circuit the whole thing.&amp;rdquo; That&amp;rsquo;s exactly what the &lt;code>Maybe&lt;/code> monad does.&lt;/p>
&lt;h2 id="wrapping-values-in-context">
Wrapping Values in Context
&lt;a class="heading-link" href="#wrapping-values-in-context">
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading">&lt;/i>
&lt;span class="sr-only">Link to heading&lt;/span>
&lt;/a>
&lt;/h2>
&lt;p>A monad wraps a value in some context. For &lt;code>Maybe&lt;/code>, that context is: &amp;ldquo;this value might not exist.&amp;rdquo;&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-haskell" data-lang="haskell">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ff7b72">data&lt;/span> &lt;span style="color:#ff7b72">Maybe&lt;/span> a &lt;span style="color:#ff7b72;font-weight:bold">=&lt;/span> &lt;span style="color:#ff7b72">Nothing&lt;/span> &lt;span style="color:#ff7b72;font-weight:bold">|&lt;/span> &lt;span style="color:#ff7b72">Just&lt;/span> a
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>Just 42&lt;/code> means &amp;ldquo;I have a value, it&amp;rsquo;s 42.&amp;rdquo; &lt;code>Nothing&lt;/code> means &amp;ldquo;there&amp;rsquo;s no value here.&amp;rdquo; Simple enough. But the power isn&amp;rsquo;t in the wrapper itself. It&amp;rsquo;s in how you chain operations on wrapped values.&lt;/p>
&lt;h2 id="the-key-operation-bind">
The Key Operation: Bind
&lt;a class="heading-link" href="#the-key-operation-bind">
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading">&lt;/i>
&lt;span class="sr-only">Link to heading&lt;/span>
&lt;/a>
&lt;/h2>
&lt;p>The operation that makes a monad a monad is called &lt;code>bind&lt;/code> (written &lt;code>&amp;gt;&amp;gt;=&lt;/code> in Haskell). It takes a wrapped value and a function that operates on the unwrapped value, then returns a new wrapped value.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-haskell" data-lang="haskell">&lt;span style="display:flex;">&lt;span>(&lt;span style="color:#ff7b72;font-weight:bold">&amp;gt;&amp;gt;=&lt;/span>) &lt;span style="color:#ff7b72;font-weight:bold">::&lt;/span> &lt;span style="color:#ff7b72">Maybe&lt;/span> a &lt;span style="color:#ff7b72;font-weight:bold">-&amp;gt;&lt;/span> (a &lt;span style="color:#ff7b72;font-weight:bold">-&amp;gt;&lt;/span> &lt;span style="color:#ff7b72">Maybe&lt;/span> b) &lt;span style="color:#ff7b72;font-weight:bold">-&amp;gt;&lt;/span> &lt;span style="color:#ff7b72">Maybe&lt;/span> b
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>In English: &amp;ldquo;Give me a &lt;code>Maybe a&lt;/code> and a function from &lt;code>a&lt;/code> to &lt;code>Maybe b&lt;/code>, and I&amp;rsquo;ll give you back a &lt;code>Maybe b&lt;/code>.&amp;rdquo;&lt;/p>
&lt;p>The implementation is dead simple:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-haskell" data-lang="haskell">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ff7b72">Nothing&lt;/span> &lt;span style="color:#ff7b72;font-weight:bold">&amp;gt;&amp;gt;=&lt;/span> f &lt;span style="color:#ff7b72;font-weight:bold">=&lt;/span> &lt;span style="color:#ff7b72">Nothing&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>(&lt;span style="color:#ff7b72">Just&lt;/span> x) &lt;span style="color:#ff7b72;font-weight:bold">&amp;gt;&amp;gt;=&lt;/span> f &lt;span style="color:#ff7b72;font-weight:bold">=&lt;/span> f x
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>If the input is &lt;code>Nothing&lt;/code>, don&amp;rsquo;t bother calling the function. Just propagate &lt;code>Nothing&lt;/code>. If there&amp;rsquo;s a value inside, unwrap it and pass it to the function. Now that ugly Python staircase becomes:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-haskell" data-lang="haskell">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d2a8ff;font-weight:bold">getUser&lt;/span> userId &lt;span style="color:#ff7b72;font-weight:bold">&amp;gt;&amp;gt;=&lt;/span> getAddress &lt;span style="color:#ff7b72;font-weight:bold">&amp;gt;&amp;gt;=&lt;/span> getCity
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>If any of them returns &lt;code>Nothing&lt;/code>, the whole expression evaluates to &lt;code>Nothing&lt;/code>. No null checks. No staircase.&lt;/p>
&lt;h2 id="the-three-laws">
The Three Laws
&lt;a class="heading-link" href="#the-three-laws">
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading">&lt;/i>
&lt;span class="sr-only">Link to heading&lt;/span>
&lt;/a>
&lt;/h2>
&lt;p>For something to be a proper monad, &lt;code>bind&lt;/code> has to behave predictably. There are three laws&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup>:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>Left identity&lt;/strong>: &lt;code>return a &amp;gt;&amp;gt;= f&lt;/code> equals &lt;code>f a&lt;/code>. Wrapping a value and immediately binding it to a function is the same as just calling the function on the value.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Right identity&lt;/strong>: &lt;code>m &amp;gt;&amp;gt;= return&lt;/code> equals &lt;code>m&lt;/code>. Binding a wrapped value to the wrapping function gives you back the same wrapped value.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Associativity&lt;/strong>: &lt;code>(m &amp;gt;&amp;gt;= f) &amp;gt;&amp;gt;= g&lt;/code> equals &lt;code>m &amp;gt;&amp;gt;= (\x -&amp;gt; f x &amp;gt;&amp;gt;= g)&lt;/code>. The order you group your binds doesn&amp;rsquo;t matter.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>These aren&amp;rsquo;t rules you need to memorise. They just guarantee that chaining operations works the way you&amp;rsquo;d expect, with no weird surprises when you compose things together.&lt;/p>
&lt;h2 id="its-not-just-maybe">
It&amp;rsquo;s Not Just Maybe
&lt;a class="heading-link" href="#its-not-just-maybe">
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading">&lt;/i>
&lt;span class="sr-only">Link to heading&lt;/span>
&lt;/a>
&lt;/h2>
&lt;p>The pattern generalises. Different monads handle different kinds of context:&lt;/p>
&lt;p>&lt;strong>Either&lt;/strong> handles operations that can fail with an error message, not just a silent &lt;code>Nothing&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-haskell" data-lang="haskell">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d2a8ff;font-weight:bold">parseJSON&lt;/span> input &lt;span style="color:#ff7b72;font-weight:bold">&amp;gt;&amp;gt;=&lt;/span> validateSchema &lt;span style="color:#ff7b72;font-weight:bold">&amp;gt;&amp;gt;=&lt;/span> extractFields
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>If any step fails, you get a &lt;code>Left &amp;quot;error message&amp;quot;&lt;/code> and the rest is skipped.&lt;/p>
&lt;p>&lt;strong>IO&lt;/strong> sequences operations that interact with the outside world:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-haskell" data-lang="haskell">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d2a8ff;font-weight:bold">getLine&lt;/span> &lt;span style="color:#ff7b72;font-weight:bold">&amp;gt;&amp;gt;=&lt;/span> putStrLn
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Read a line from stdin, then print it. This matters because Haskell is otherwise free to evaluate things in any order it wants.&lt;/p>
&lt;p>&lt;strong>List&lt;/strong> handles non-determinism, where operations produce multiple results:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-haskell" data-lang="haskell">&lt;span style="display:flex;">&lt;span>[&lt;span style="color:#a5d6ff">1&lt;/span>,&lt;span style="color:#a5d6ff">2&lt;/span>,&lt;span style="color:#a5d6ff">3&lt;/span>] &lt;span style="color:#ff7b72;font-weight:bold">&amp;gt;&amp;gt;=&lt;/span> &lt;span style="color:#d2a8ff;font-weight:bold">\&lt;/span>x &lt;span style="color:#ff7b72;font-weight:bold">-&amp;gt;&lt;/span> [x, x&lt;span style="color:#ff7b72;font-weight:bold">*&lt;/span>&lt;span style="color:#a5d6ff">10&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8b949e;font-style:italic">-- Result: [1,10,2,20,3,30]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>State&lt;/strong> threads mutable state through a sequence of pure functions without actually mutating anything.&lt;/p>
&lt;p>The shape is always the same. A wrapped value, a function that produces a new wrapped value, and &lt;code>bind&lt;/code> handling the plumbing between them.&lt;/p>
&lt;h2 id="do-notation">
Do-Notation
&lt;a class="heading-link" href="#do-notation">
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading">&lt;/i>
&lt;span class="sr-only">Link to heading&lt;/span>
&lt;/a>
&lt;/h2>
&lt;p>Haskell provides &lt;code>do&lt;/code>-notation as syntactic sugar to make monadic code read more like imperative code. These two are equivalent:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-haskell" data-lang="haskell">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8b949e;font-style:italic">-- With bind&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d2a8ff;font-weight:bold">getLine&lt;/span> &lt;span style="color:#ff7b72;font-weight:bold">&amp;gt;&amp;gt;=&lt;/span> &lt;span style="color:#d2a8ff;font-weight:bold">\&lt;/span>name &lt;span style="color:#ff7b72;font-weight:bold">-&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d2a8ff;font-weight:bold">putStrLn&lt;/span> (&lt;span style="color:#a5d6ff">&amp;#34;Hello, &amp;#34;&lt;/span> &lt;span style="color:#ff7b72;font-weight:bold">++&lt;/span> name) &lt;span style="color:#ff7b72;font-weight:bold">&amp;gt;&amp;gt;=&lt;/span> &lt;span style="color:#d2a8ff;font-weight:bold">\&lt;/span>&lt;span style="color:#ff7b72">_&lt;/span> &lt;span style="color:#ff7b72;font-weight:bold">-&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d2a8ff;font-weight:bold">return&lt;/span> ()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8b949e;font-style:italic">-- With do-notation&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ff7b72">do&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> name &lt;span style="color:#ff7b72;font-weight:bold">&amp;lt;-&lt;/span> getLine
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> putStrLn (&lt;span style="color:#a5d6ff">&amp;#34;Hello, &amp;#34;&lt;/span> &lt;span style="color:#ff7b72;font-weight:bold">++&lt;/span> name)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> return ()
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The &lt;code>do&lt;/code> version looks like a sequence of statements. Under the hood, it desugars into the same chain of &lt;code>&amp;gt;&amp;gt;=&lt;/code> calls. This is why Haskell can look imperative when it needs to, without abandoning purity.&lt;/p>
&lt;h2 id="why-this-matters-outside-haskell">
Why This Matters Outside Haskell
&lt;a class="heading-link" href="#why-this-matters-outside-haskell">
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading">&lt;/i>
&lt;span class="sr-only">Link to heading&lt;/span>
&lt;/a>
&lt;/h2>
&lt;p>You&amp;rsquo;ve already used monads without knowing it. JavaScript&amp;rsquo;s &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then" class="external-link" target="_blank" rel="noopener">&lt;code>Promise.then()&lt;/code>&lt;/a> is essentially bind for asynchronous computations (it doesn&amp;rsquo;t strictly satisfy the monad laws due to auto-flattening, but the shape is the same). Rust&amp;rsquo;s &lt;a href="https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator" class="external-link" target="_blank" rel="noopener">&lt;code>?&lt;/code> operator&lt;/a> is bind for &lt;code>Result&lt;/code>. C#&amp;rsquo;s &lt;a href="https://learn.microsoft.com/en-us/dotnet/csharp/linq/" class="external-link" target="_blank" rel="noopener">LINQ query syntax&lt;/a> is do-notation for the list monad. Optional chaining (&lt;code>?.&lt;/code>) in Swift, Kotlin and TypeScript is a limited form of Maybe bind.&lt;/p>
&lt;p>Haskell just names the pattern explicitly and builds its entire effect system around it. Other languages use it selectively, often without the vocabulary.&lt;/p>
&lt;h2 id="the-burrito-problem">
The Burrito Problem
&lt;a class="heading-link" href="#the-burrito-problem">
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading">&lt;/i>
&lt;span class="sr-only">Link to heading&lt;/span>
&lt;/a>
&lt;/h2>
&lt;p>Monad tutorials fail because they try to find one physical metaphor that covers all monads. But monads aren&amp;rsquo;t a thing, they&amp;rsquo;re a pattern. Saying &amp;ldquo;a monad is like a burrito&amp;rdquo; is as useful as saying &amp;ldquo;recursion is like looking into a mirror that&amp;rsquo;s facing another mirror.&amp;rdquo; If you already understand recursion, you nod along. If you don&amp;rsquo;t, you&amp;rsquo;re just more confused than before. Monad analogies work the same way: they only click once you no longer need them.&lt;/p>
&lt;p>If you understand &lt;code>Maybe&lt;/code> and how &lt;code>&amp;gt;&amp;gt;=&lt;/code> short-circuits on &lt;code>Nothing&lt;/code>, you understand monads. Everything else is just the same pattern with different plumbing.&lt;/p>
&lt;img
src="https://bonnef.in/images/posts/haskell-makes-sense.gif"
alt="Haskell programmers explaining how the language actually makes sense"
loading="lazy"
width="300"
style="max-width: min(100%, 300px); height: auto; display: block; margin: 0 auto;"
class="responsive-image"
>
&lt;h2 id="further-reading">
Further Reading
&lt;a class="heading-link" href="#further-reading">
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading">&lt;/i>
&lt;span class="sr-only">Link to heading&lt;/span>
&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>&lt;em>Learn You a Haskell for Great Good&lt;/em>&lt;sup id="fnref:3">&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref">3&lt;/a>&lt;/sup> has an excellent chapter that builds intuition gradually&lt;/li>
&lt;li>Typeclassopedia&lt;sup id="fnref:4">&lt;a href="#fn:4" class="footnote-ref" role="doc-noteref">4&lt;/a>&lt;/sup> covers the full typeclass hierarchy (Functor → Applicative → Monad) with rigour&lt;/li>
&lt;li>Philip Wadler&amp;rsquo;s original paper &lt;em>Monads for functional programming&lt;/em>&lt;sup id="fnref:5">&lt;a href="#fn:5" class="footnote-ref" role="doc-noteref">5&lt;/a>&lt;/sup> is surprisingly readable for an academic paper&lt;/li>
&lt;/ul>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>&lt;a href="https://www.oracle.com/java/technologies/javase/8-whats-new.html" class="external-link" target="_blank" rel="noopener">What&amp;rsquo;s New in JDK 8&lt;/a> - Oracle&amp;rsquo;s official release notes for Java SE 8, released March 2014.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>&lt;a href="https://wiki.haskell.org/Monad_laws" class="external-link" target="_blank" rel="noopener">Monad laws&lt;/a> - HaskellWiki&amp;rsquo;s formal specification of the three laws any monad instance must satisfy.&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:3">
&lt;p>&lt;a href="https://learnyouahaskell.github.io/a-fistful-of-monads.html" class="external-link" target="_blank" rel="noopener">Learn You a Haskell - Chapter 12: A Fistful of Monads&lt;/a>&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:4">
&lt;p>&lt;a href="https://wiki.haskell.org/Typeclassopedia" class="external-link" target="_blank" rel="noopener">Typeclassopedia&lt;/a>&amp;#160;&lt;a href="#fnref:4" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:5">
&lt;p>Wadler, Philip. &lt;a href="https://homepages.inf.ed.ac.uk/wadler/papers/marktoberdorf/baastad.pdf" class="external-link" target="_blank" rel="noopener">Monads for functional programming&lt;/a>. 1995.&amp;#160;&lt;a href="#fnref:5" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item></channel></rss>