<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"
    xmlns:dc="http://purl.org/dc/elements/1.1/">
    <channel>
        <title>Flavio Corpa's feed</title>
        <link>https://flaviocorpa.com</link>
        <description><![CDATA[Feed for Flavio's website]]></description>
        <atom:link href="https://flaviocorpa.com/rss.xml" rel="self"
                   type="application/rss+xml" />
        <lastBuildDate>Sun, 07 Jun 2026 14:00:00 UT</lastBuildDate>
        <item>
    <title>Haskell for Elm developers: giving names to stuff (Part 8 - IO)</title>
    <link>https://flaviocorpa.com/haskell-for-elm-developers-giving-names-to-stuff-part-8-io.html</link>
    <description><![CDATA[<nav class="my-6 py-2">
  <div class="relative mx-auto md:w-[600px] w-auto px-[1.3125rem] md:px-0" data-nav-wrap>
    <a class="mr-5 absolute left-[-10000px] focus:static focus:left-auto" href="#content"
      >Skip to content</a
    >
    <a class="mr-5" href="/">Home</a>
    <a class="mr-5" href="https://github.com/sponsors/kutyel">Sponsor me</a>
    <a class="mr-5" href="/atom.xml">RSS</a>
  </div>
</nav>


<style>
  bsky-comments {
    --background-color: var(--bgColor);
    --text-color: var(--textColor);
    --link-color: var(--textLinkColor);
    --link-hover-color: var(--textLinkHoverColor);
    --comment-meta-color: #888;
    --error-color: #ff4d4d;
    --reply-border-color: var(--separatorColor);
    --button-background-color: var(--btnBgColor);
    --button-hover-background-color: rgba(var(--btnBgColor), 0.2);
    --author-avatar-border-radius: 50%;
  }
</style>

<main class="flex-1" id="content" tabindex="-1">
  <article class="pb-10">
    <header class="bg-[var(--headerBgColor)] mb-8 px-[1.3125rem] md:px-0 py-4 md:py-8">
      <div class="mx-auto md:w-[600px]">
        <h1 class="text-[1.7rem] md:text-[3rem] m-0 mb-4 font-normal leading-[1.2] text-[var(--h1Color)]">
          Haskell for Elm developers: giving names to stuff (Part 8 - IO)
        </h1>
        <div class="mx-auto md:w-[600px]">
          <small class="italic">07/06/2026</small>
          <small class="italic"> | 10 min read</small>
          
          <div class="mt-2">[ <a title="All pages tagged &#39;haskell&#39;." href="/tags/haskell.html" rel="tag">haskell</a>, <a title="All pages tagged &#39;elm&#39;." href="/tags/elm.html" rel="tag">elm</a>, <a title="All pages tagged &#39;fp&#39;." href="/tags/fp.html" rel="tag">fp</a> ]</div>
        </div>
      </div>
    </header>
    <section class="mx-auto md:w-[600px] px-[1.3125rem] md:px-0"><p><img src="./images/haskell-elm.svg" alt="logo" width="300px"></p>
<p>Welcome back! In my <a href="https://flaviocorpa.com/haskell-for-elm-developers-giving-names-to-stuff-part-7-traversable.html">last post</a>, we explored <code>Traversable</code> and discovered that “the answer is always <code>traverse</code>”. Today we are going to tackle something that scares a LOT of newcomers to Haskell, and yet — surprise, surprise! — you have been doing it in Elm all along: <strong><code>IO</code></strong>! 🎉</p>
<p>Funnily enough, all the way back in <a href="https://flaviocorpa.com/haskell-for-elm-developers-giving-names-to-stuff-part-1-functors.html">Part 1</a> I promised I would eventually write about <code>IO</code>… only took me 8 posts to keep my word! 😅</p>
<p>There is a famous question that every Elm developer eventually asks when they peek over the fence into Haskell: <em>“Wait… if Haskell is pure, how does it print to the screen, read files or make HTTP requests?”</em> 🤔</p>
<p>The answer is <code>IO</code>, and the beautiful thing is that the mental model is <strong>exactly</strong> the one you already have from Elm’s <code>Task</code> and <code>Cmd</code>. Let me prove it to you! 😉</p>
<p>Quick refresher before we dive in, since we will lean on both concepts: in Elm, a <strong><code>Task</code></strong> is a <em>composable description</em> of an effect — you can chain tasks with <code>Task.andThen</code>, map over them, and they carry a typed error channel. A <strong><code>Cmd</code></strong> is the <em>one-shot instruction</em> you actually hand to the Elm runtime from <code>init</code>/<code>update</code>; it is fire-and-forget, and the only way it talks back to you is through a message. The two meet at <code>Task.perform</code>/<code>Task.attempt</code>, which turn a <code>Task</code> into a <code>Cmd</code> — because the runtime only accepts <code>Cmd</code>s. Keep that pipeline (<code>Task</code> ➝ <code>Cmd</code> ➝ runtime) in mind: it maps directly onto what Haskell does with <code>IO</code> (which stands for Input/Output, btw!).</p>
<h2 id="the-big-misconception">The big misconception</h2>
<p>The most common misconception about <code>IO</code> is thinking that an <code>IO a</code> value <em>is</em> the side effect. It is not! An <code>IO a</code> is a <strong>description</strong> of an effectful computation that produces a value of type <code>a</code> when (and only when) it is eventually run.</p>
<p>Does that sound familiar? It should! It is <em>precisely</em> how the Elm docs describe a <a href="https://package.elm-lang.org/packages/elm/core/latest/Task"><code>Task</code></a>:</p>
<blockquote>
<p>A task is a <em>description</em> of something that needs to be done. […] The actual benefit of a task is that it does not do anything until you give it to the runtime.</p>
</blockquote>
<p>Swap the word “task” for “IO action” and you have a perfect definition of <code>IO</code> in Haskell. An <code>IO a</code> value is a <strong>recipe</strong>, not the act of cooking. You can pass it around, store it in a list, combine it with other recipes — and <em>nothing happens</em> until the runtime decides to actually run it. 🍳</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ot">greet ::</span> <span class="dt">IO</span> ()</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>greet <span class="ot">=</span> <span class="fu">putStrLn</span> <span class="st">&quot;Hello, Elm developer!&quot;</span></span></code></pre></div>
<p>Defining <code>greet</code> does <strong>not</strong> print anything. <code>greet</code> is just a value of type <code>IO ()</code> — a description that says “when run, print this line”. Referential transparency is preserved! ✨</p>
<h2 id="io-is-a-monad-of-course-it-is-upside_down_face"><code>IO</code> is a Monad (of course it is 🙃)</h2>
<p>If you have been following the series, you already know everything you need to <em>use</em> <code>IO</code>, because (you guessed it!) <code>IO</code> is a <code>Monad</code>! (Go back and read <a href="https://flaviocorpa.com/haskell-for-elm-developers-giving-names-to-stuff-part-3-monads.html">Part 3 - Monads!</a> if you need a refresher.)</p>
<p>That means it has all the machinery you already love:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="fu">fmap</span><span class="ot">  ::</span> (a <span class="ot">-&gt;</span> b) <span class="ot">-&gt;</span> <span class="dt">IO</span> a <span class="ot">-&gt;</span> <span class="dt">IO</span> b           <span class="co">-- Functor</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="fu">pure</span><span class="ot">  ::</span> a <span class="ot">-&gt;</span> <span class="dt">IO</span> a                          <span class="co">-- Applicative</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="ot">(&gt;&gt;=) ::</span> <span class="dt">IO</span> a <span class="ot">-&gt;</span> (a <span class="ot">-&gt;</span> <span class="dt">IO</span> b) <span class="ot">-&gt;</span> <span class="dt">IO</span> b        <span class="co">-- Monad</span></span></code></pre></div>
<p>And just like with <code>Task</code>, the way you chain effectful steps together is with the monadic bind (<code>&gt;&gt;=</code>), which is the equivalent of Elm’s <code>Task.andThen</code>! Compare them side by side:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="ot">(&gt;&gt;=)        ::</span> <span class="dt">IO</span> a             <span class="ot">-&gt;</span> (a <span class="ot">-&gt;</span> <span class="dt">IO</span> b) <span class="ot">-&gt;</span> <span class="dt">IO</span> b</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>Task.andThen<span class="ot"> ::</span> (a <span class="ot">-&gt;</span> <span class="dt">Task</span> x b)  <span class="ot">-&gt;</span> <span class="dt">Task</span> x a    <span class="ot">-&gt;</span> <span class="dt">Task</span> x b <span class="co">--(args flipped)</span></span></code></pre></div>
<p>So this little program that asks for your name and greets you (Elm runs in the browser, so there are no real console <code>Task</code>s — bear with me and imagine these <code>getLine</code>/<code>putLine</code> exist just to show the <em>shape</em>)…</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Task</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="fu">greetUser</span> : <span class="dt">Task</span> <span class="fu">x</span> ()</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="fu">greetUser</span> <span class="op">=</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>    <span class="fu">getLine</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>        <span class="op">|&gt;</span> <span class="dt">Task</span><span class="op">.</span><span class="fu">andThen</span> (\<span class="fu">name</span> <span class="op">-&gt;</span> <span class="fu">putLine</span> (<span class="st">&quot;Hello, &quot;</span> <span class="op">++</span> <span class="fu">name</span> <span class="op">++</span> <span class="st">&quot;!&quot;</span>))</span></code></pre></div>
<p>…is, in Haskell, basically identical:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="ot">greetUser ::</span> <span class="dt">IO</span> ()</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>greetUser <span class="ot">=</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>  <span class="fu">getLine</span> <span class="op">&gt;&gt;=</span> \name <span class="ot">-&gt;</span> <span class="fu">putStrLn</span> (<span class="st">&quot;Hello, &quot;</span> <span class="op">&lt;&gt;</span> name <span class="op">&lt;&gt;</span> <span class="st">&quot;!&quot;</span>)</span></code></pre></div>
<p>And thanks to <code>do</code> notation (remember Part 3?), we can write it in that lovely imperative-looking style:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="ot">greetUser ::</span> <span class="dt">IO</span> ()</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>greetUser <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>  name <span class="ot">&lt;-</span> <span class="fu">getLine</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>  <span class="fu">putStrLn</span> (<span class="st">&quot;Hello, &quot;</span> <span class="op">&lt;&gt;</span> name <span class="op">&lt;&gt;</span> <span class="st">&quot;!&quot;</span>)</span></code></pre></div>
<p>That <code>name &lt;- getLine</code> is <em>exactly</em> the <code>do</code> notation desugaring of <code>&gt;&gt;=</code> we saw for <code>Task</code>. Same <code>Monad</code>, same intuition, different effect. 💜</p>
<h2 id="so-where-is-the-cmd-enter-main">So where is the <code>Cmd</code>? Enter <code>main</code></h2>
<p>Here is where the most interesting comparison lives. In Elm, you can build a <code>Task</code> all day long, but <strong>a <code>Task</code> never runs on its own</strong>. To actually make something happen, you have to hand it to the runtime by turning it into a <code>Cmd</code>:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Task</span><span class="op">.</span><span class="fu">perform</span> : (<span class="fu">a</span> <span class="op">-&gt;</span> <span class="fu">msg</span>) <span class="op">-&gt;</span> <span class="dt">Task</span> <span class="dt">Never</span> <span class="fu">a</span> <span class="op">-&gt;</span> <span class="dt">Cmd</span> <span class="fu">msg</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Task</span><span class="op">.</span><span class="fu">attempt</span> : (<span class="dt">Result</span> <span class="fu">x</span> <span class="fu">a</span> <span class="op">-&gt;</span> <span class="fu">msg</span>) <span class="op">-&gt;</span> <span class="dt">Task</span> <span class="fu">x</span> <span class="fu">a</span> <span class="op">-&gt;</span> <span class="dt">Cmd</span> <span class="fu">msg</span></span></code></pre></div>
<p>A <code>Cmd</code> is the Elm Architecture’s way of saying <em>“hey runtime, please go run this effect and send me a message back when you are done”</em>. <strong>You</strong> never run the effect — the Elm runtime does, at the boundary of your program. Your <code>update</code> function stays beautifully pure: it just <em>returns</em> <code>Cmd</code>s as data. 📨</p>
<p>Haskell works <strong>exactly</strong> the same way, except the “boundary” has a name you already know:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="ot">main ::</span> <span class="dt">IO</span> ()</span></code></pre></div>
<p><code>main</code> is the single <code>IO</code> action that the Haskell runtime (the RTS) actually executes when your program starts. Everything you build is just data — descriptions of effects — until it becomes part of <code>main</code>. In other words:</p>
<blockquote>
<p><strong><code>main</code> is to Haskell what the Elm runtime is to Elm.</strong> It is the <em>one place</em> where descriptions of effects finally get run.</p>
</blockquote>
<div class="sourceCode" id="cb9"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="ot">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>  <span class="fu">putStrLn</span> <span class="st">&quot;What is your name?&quot;</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>  name <span class="ot">&lt;-</span> <span class="fu">getLine</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>  <span class="fu">putStrLn</span> (<span class="st">&quot;Hello, &quot;</span> <span class="op">&lt;&gt;</span> name <span class="op">&lt;&gt;</span> <span class="st">&quot;!&quot;</span>)</span></code></pre></div>
<p>The mapping is gorgeous once you see it:</p>
<pre><code>Elm                                Haskell
------------------------------     ------------------------------
Task x a  (a description)          IO a  (a description)
Task.andThen / Task.map            &gt;&gt;= / fmap  (it is a Monad)
Cmd msg   (handed to the runtime)  being part of main
the Elm runtime runs your Cmds     the RTS runs main</code></pre>
<p>In Elm, the runtime is <em>hidden</em> and you talk to it through <code>Cmd</code>. In Haskell, the runtime is <em>explicit</em> and you talk to it through <code>main</code>. That is really the whole difference! 🤯</p>
<p>So when Haskellers tell you <code>IO</code> is the way you “describe effects as data and let the runtime run them at the boundary”… drum rolls 🥁🥁🥁 … that is <strong>the Elm Architecture</strong>! YOU HAVE BEEN DOING <code>IO</code> ALL ALONG™️!!! 🎉</p>
<h2 id="but-elms-task-has-an-error-type-and-io-doesnt-monocle_face">“But Elm’s <code>Task</code> has an error type and <code>IO</code> doesn’t!” 🧐</h2>
<p>Sharp eye! This is the most important practical difference, so let us address it head on.</p>
<p>Elm’s <code>Task</code> has <strong>two</strong> type parameters:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Task</span> <span class="fu">error</span> <span class="fu">value</span></span></code></pre></div>
<p>The <code>error</code> channel is part of the type, which is why you have <code>Task.attempt : (Result x a -&gt; msg) -&gt; Task x a -&gt; Cmd msg</code> — when the runtime finishes, it hands you back a <code>Result</code> so you are <em>forced</em> to handle the failure case. Lovely and safe! 👏🏻</p>
<p>Haskell’s <code>IO</code>, on the other hand, has only <strong>one</strong> type parameter:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="dt">IO</span> a</span></code></pre></div>
<p>There is no error channel in the type. So what happens when things go wrong? Haskell’s <code>IO</code> actions can throw <strong>runtime exceptions</strong> — and to be precise (because “IO” and “exceptions” both get overloaded a lot), these come in two flavours:</p>
<ul>
<li><strong>Exceptions from the outside world</strong>: reading a file that does not exist, a network connection dropping, the disk being full… Operations like <code>readFile</code> signal failure by <em>throwing</em> instead of returning an <code>Either</code>. This is closer to JavaScript’s <code>throw</code> than to Elm’s principled <code>Result</code>.</li>
<li><strong>Exceptions from pure code</strong>: things like <code>head []</code>, <code>error "boom"</code> or an incomplete pattern match. These lurk inside lazily evaluated <em>pure</em> values and only blow up when something (ultimately <code>main</code>) forces them.</li>
</ul>
<p>That second flavour is the one with no Elm equivalent at all — in Elm, pure code simply <em>cannot</em> throw — and it is honestly one of the few places where Elm is <em>stricter and safer</em> than vanilla Haskell. 😅</p>
<p>To be fair though, exceptions are not inherently evil! Some situations really <em>are</em> exceptional, and insisting that every function must be total has its own costs: Elm keeps division total by deciding that <code>1 / 0 == Infinity</code> (and <code>1 // 0 == 0</code>! 🙈), which is <a href="https://github.com/elm/core/issues/1072">arguably weirder</a> than just failing loudly. And real-world input/output is <em>so</em> full of failure cases (permission denied! connection reset!) that having a mechanism to propagate them without threading <code>Either</code> through every single function can be a perfectly reasonable design.</p>
<p>Still, when the failure is part of your <em>domain</em> (the user typed an invalid age, the JSON did not parse), disciplined Haskellers reach for the same trick you know and love from Elm’s <code>Result</code>: <strong>make the error a value</strong> by returning an <code>Either</code> explicitly:</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Text.Read</span> (readMaybe)</span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a><span class="ot">readAge ::</span> <span class="dt">IO</span> (<span class="dt">Either</span> <span class="dt">String</span> <span class="dt">Int</span>)</span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>readAge <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a>  line <span class="ot">&lt;-</span> <span class="fu">getLine</span></span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a>  <span class="fu">pure</span> <span class="op">$</span> <span class="kw">case</span> readMaybe line <span class="kw">of</span></span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Just</span> n  <span class="ot">-&gt;</span> <span class="dt">Right</span> n</span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Nothing</span> <span class="ot">-&gt;</span> <span class="dt">Left</span> (<span class="st">&quot;Not a number: &quot;</span> <span class="op">&lt;&gt;</span> line)</span></code></pre></div>
<p>That <code>IO (Either String Int)</code> is morally <em>exactly</em> Elm’s <code>Task String Int</code>! The effect on the outside (<code>IO</code> / <code>Task</code>), the success-or-failure on the inside (<code>Either</code> / the two type params). ✨</p>
<h2 id="a-real-worldtm-example-fetching-and-parsing">A REAL WORLD™️ example: fetching and parsing</h2>
<p>Let’s make this concrete with something you actually do every day: fetch some data and parse it. In Elm you would compose <code>Task</code>s and hand the result to the runtime as a <code>Cmd</code>:</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Http</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Task</span></span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a><span class="fu">fetchUser</span> : <span class="dt">String</span> <span class="op">-&gt;</span> <span class="dt">Task</span> <span class="dt">Http</span><span class="op">.</span><span class="dt">Error</span> <span class="dt">User</span></span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a><span class="fu">fetchUser</span> <span class="fu">id</span> <span class="op">=</span></span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Http</span><span class="op">.</span><span class="fu">task</span> { <span class="co">{- ... -}</span> }</span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a>        <span class="op">|&gt;</span> <span class="dt">Task</span><span class="op">.</span><span class="fu">andThen</span> <span class="fu">decodeUser</span></span>
<span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a><span class="fu">loadUser</span> : <span class="dt">String</span> <span class="op">-&gt;</span> <span class="dt">Cmd</span> <span class="dt">Msg</span></span>
<span id="cb14-10"><a href="#cb14-10" aria-hidden="true" tabindex="-1"></a><span class="fu">loadUser</span> <span class="fu">id</span> <span class="op">=</span></span>
<span id="cb14-11"><a href="#cb14-11" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Task</span><span class="op">.</span><span class="fu">attempt</span> <span class="dt">GotUser</span> (<span class="fu">fetchUser</span> <span class="fu">id</span>)</span></code></pre></div>
<p>In Haskell, the same shape, built from <code>IO</code> actions and finally plugged into <code>main</code>:</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="ot">fetchUser ::</span> <span class="dt">Text</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> (<span class="dt">Either</span> <span class="dt">Error</span> <span class="dt">User</span>)</span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>fetchUser userId <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a>  response <span class="ot">&lt;-</span> httpGet (<span class="st">&quot;/users/&quot;</span> <span class="op">&lt;&gt;</span> userId) <span class="co">-- IO action</span></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a>  <span class="fu">pure</span> (decodeUser response)                <span class="co">-- pure parsing</span></span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a><span class="ot">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a>  result <span class="ot">&lt;-</span> fetchUser <span class="st">&quot;kutyel&quot;</span></span>
<span id="cb15-9"><a href="#cb15-9" aria-hidden="true" tabindex="-1"></a>  <span class="kw">case</span> result <span class="kw">of</span></span>
<span id="cb15-10"><a href="#cb15-10" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Left</span> err   <span class="ot">-&gt;</span> <span class="fu">putStrLn</span> (<span class="st">&quot;Something went wrong: &quot;</span> <span class="op">&lt;&gt;</span> <span class="fu">show</span> err)</span>
<span id="cb15-11"><a href="#cb15-11" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Right</span> user <span class="ot">-&gt;</span> <span class="fu">putStrLn</span> (<span class="st">&quot;Welcome, &quot;</span> <span class="op">&lt;&gt;</span> userName user <span class="op">&lt;&gt;</span> <span class="st">&quot;!&quot;</span>)</span></code></pre></div>
<p>Notice the same healthy separation Elm encourages: the <strong>effectful</strong> part (<code>httpGet</code>) lives in <code>IO</code>, the <strong>pure</strong> part (<code>decodeUser</code>) is just a normal function <code>a -&gt; Either Error User</code>. The <code>case</code> at the end is doing <em>by hand</em> what <code>Task.attempt</code>’s <code>GotUser</code> message + your <code>update</code> branch do for you in Elm. Same discipline, different syntax! 🎯</p>
<h2 id="why-this-design-is-the-same-good-idea-in-both-languages">Why this design is the same good idea in both languages</h2>
<p>Both Elm and Haskell are built on the same foundational insight:</p>
<blockquote>
<p><strong>Keep effects as inert data for as long as possible, and run them only at a single, well-defined boundary.</strong></p>
</blockquote>
<p>In Elm, that boundary is the runtime, and the “inert data” is <code>Cmd</code> (built from <code>Task</code>). In Haskell, that boundary is <code>main</code>, and the inert data is <code>IO</code>. The payoff is identical in both: the vast majority of your program stays <strong>pure</strong>, <strong>testable</strong> and <strong>easy to reason about</strong>, because building an <code>IO</code>/<code>Task</code> value has <em>no observable effect</em> — only the runtime running it does. 🧠</p>
<p>This is why you can do delightful things like keep a <code>[IO ()]</code> — a plain list of effects you have not run yet — and then run them all at once with our old friend from last post, <code>traverse_</code> (the <code>Foldable</code>/<code>Traversable</code> cousin that discards results):</p>
<div class="sourceCode" id="cb16"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="ot">greetings ::</span> [<span class="dt">IO</span> ()]</span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a>greetings <span class="ot">=</span> <span class="fu">map</span></span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a>  (\name <span class="ot">-&gt;</span> <span class="fu">putStrLn</span> (<span class="st">&quot;Hello, &quot;</span> <span class="op">&lt;&gt;</span> name))</span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a>  [<span class="st">&quot;Evan&quot;</span>, <span class="st">&quot;Simon&quot;</span>, <span class="st">&quot;Flavio&quot;</span>]</span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a><span class="ot">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb16-7"><a href="#cb16-7" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> <span class="fu">sequence_</span> greetings <span class="co">-- runs them one after another, top to bottom</span></span></code></pre></div>
<p><code>sequence_</code> here is doing for <code>IO</code> <em>exactly</em> what <a href="https://package.elm-lang.org/packages/elm/core/latest/Task#sequence"><code>Task.sequence</code></a> does for <code>Task</code>! It is <code>Traversable</code> and <code>Monad</code> all the way down — the same names, giving structure to the same ideas. 🥁</p>
<h2 id="wrapping-up">Wrapping up</h2>
<p>So, the next time someone tells you <code>IO</code> is some scary, magical, impure escape hatch, you can smile knowingly and say:</p>
<blockquote>
<p>“Oh, you mean a <code>Task</code> that the runtime runs at <code>main</code> instead of at <code>Cmd</code>? Yeah, I have been doing that in Elm for years.” 😏</p>
</blockquote>
<p>Let’s recap the mental model:</p>
<ul>
<li>An <code>IO a</code> is a <strong>description</strong> of an effect, just like a <code>Task</code> — building it does nothing.</li>
<li>It is a <strong><code>Monad</code></strong>, so you compose it with <code>&gt;&gt;=</code> / <code>do</code> notation, exactly like <code>Task.andThen</code>.</li>
<li>It runs <strong>only</strong> when it becomes part of <code>main</code>, just like a <code>Task</code> runs only when the runtime gets it as a <code>Cmd</code>.</li>
<li>Vanilla <code>IO</code> lacks Elm’s typed error channel, but for the failures that belong to your domain, <code>IO (Either e a)</code> recovers the exact shape of <code>Task e a</code>.</li>
</ul>
<p>Purity is not the absence of effects — it is the discipline of treating effects as <strong>values</strong>. Elm taught you that lesson with <code>Task</code> and <code>Cmd</code>; Haskell just calls it <code>IO</code>. ✨</p>
<h2 id="acknowledgements">Acknowledgements</h2>
<p>As always, the goal of this series is to show that the scary-sounding Haskell concepts are things you <em>already know</em> from Elm — we are just giving them their proper names. 😉</p>
<p>Special thanks as always to <a href="https://github.com/cekrem">Christian Ekrem</a> and to <a href="https://github.com/ludat">Lucas David Traverso</a> for technical proofreading the draft version of this blogpost and adding their valuable feedback to it! 🙏🏻</p>
<p>Hope <code>IO</code> finally clicked for you and that you now see it for what it really is: your trusty old <code>Task</code>/<code>Cmd</code> duo wearing a Haskell hat! 🎩 If you found joy in this blogpost and would like me to continue the series, please consider <a href="https://github.com/sponsors/kutyel">sponsoring my work</a>, share it in your social networks and <strong>follow me on <a href="https://twitter.com/FlavioCorpa">Twitter</a>/<a href="https://bsky.app/profile/flaviocorpa.com">BlueSky!</a> 🦋</strong> 🙌🏻</p></section>
  </article>
</main>


<bsky-comments post="at://did:plc:dvrocvv5szl2evqiafsx4iyw/app.bsky.feed.post/3mnz52xzd3k2e"></bsky-comments>
 <footer class="py-14 bg-[var(--footerBgColor)] shrink-0">
  <div class="relative mx-auto md:w-[600px] w-auto px-[1.3125rem]">
    <ul class="flex justify-center list-none" role="list">
      <li class="mx-3" role="listitem">
        <a href="/">Home</a>
      </li>
      <li class="mx-3" role="listitem">
        <a href="https://github.com/sponsors/kutyel/">Sponsor me</a>
      </li>
      <li class="mx-3" role="listitem">
        <a href="/atom.xml">RSS</a>
      </li>
    </ul>
  </div>
</footer>


<script src="https://gistcdn.githack.com/kutyel/41d12e099484fd390fb67168271fcdd9/raw/9be26e500525a2e4edacc53d3a8006aaddec0e15/bsky-comments.js"></script>
]]></description>
    <pubDate>Sun, 07 Jun 2026 14:00:00 UT</pubDate>
    <guid>https://flaviocorpa.com/haskell-for-elm-developers-giving-names-to-stuff-part-8-io.html</guid>
    <dc:creator>Flavio Corpa</dc:creator>
</item>
<item>
    <title>Haskell for Elm developers: giving names to stuff (Part 7 - Traversable)</title>
    <link>https://flaviocorpa.com/haskell-for-elm-developers-giving-names-to-stuff-part-7-traversable.html</link>
    <description><![CDATA[<nav class="my-6 py-2">
  <div class="relative mx-auto md:w-[600px] w-auto px-[1.3125rem] md:px-0" data-nav-wrap>
    <a class="mr-5 absolute left-[-10000px] focus:static focus:left-auto" href="#content"
      >Skip to content</a
    >
    <a class="mr-5" href="/">Home</a>
    <a class="mr-5" href="https://github.com/sponsors/kutyel">Sponsor me</a>
    <a class="mr-5" href="/atom.xml">RSS</a>
  </div>
</nav>


<style>
  bsky-comments {
    --background-color: var(--bgColor);
    --text-color: var(--textColor);
    --link-color: var(--textLinkColor);
    --link-hover-color: var(--textLinkHoverColor);
    --comment-meta-color: #888;
    --error-color: #ff4d4d;
    --reply-border-color: var(--separatorColor);
    --button-background-color: var(--btnBgColor);
    --button-hover-background-color: rgba(var(--btnBgColor), 0.2);
    --author-avatar-border-radius: 50%;
  }
</style>

<main class="flex-1" id="content" tabindex="-1">
  <article class="pb-10">
    <header class="bg-[var(--headerBgColor)] mb-8 px-[1.3125rem] md:px-0 py-4 md:py-8">
      <div class="mx-auto md:w-[600px]">
        <h1 class="text-[1.7rem] md:text-[3rem] m-0 mb-4 font-normal leading-[1.2] text-[var(--h1Color)]">
          Haskell for Elm developers: giving names to stuff (Part 7 - Traversable)
        </h1>
        <div class="mx-auto md:w-[600px]">
          <small class="italic">26/03/2026</small>
          <small class="italic"> | 8 min read</small>
          
          <div class="mt-2">[ <a title="All pages tagged &#39;haskell&#39;." href="/tags/haskell.html" rel="tag">haskell</a>, <a title="All pages tagged &#39;elm&#39;." href="/tags/elm.html" rel="tag">elm</a>, <a title="All pages tagged &#39;fp&#39;." href="/tags/fp.html" rel="tag">fp</a> ]</div>
        </div>
      </div>
    </header>
    <section class="mx-auto md:w-[600px] px-[1.3125rem] md:px-0"><p><img src="./images/haskell-elm.svg" alt="logo" width="300px"></p>
<p>Welcome back! In my <a href="https://flaviocorpa.com/haskell-for-elm-developers-giving-names-to-stuff-part-6-foldable.html">last post</a>, we explored the <code>Foldable</code> typeclass and how it showed up everywhere in Elm. And if you were paying attention, I teased at the very end that the next topic would be… <code>Traversable</code>! 🎉</p>
<p>Today’s topic is one of my personal favourites and — spoiler alert ⚠️ — it is something you have absolutely been using in Elm all along!</p>
<h2 id="a-familiar-pattern">A familiar pattern</h2>
<p>Before we dive into the typeclass definition, let me show you some Elm code that might look familiar. Have you ever used the <a href="https://package.elm-lang.org/packages/elmcraft/core-extra/latest/Maybe-Extra#combine"><code>elmcraft/core-extra</code></a> package? It has a pair of very handy functions:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="co">{-| Combine a list of maybes into a single maybe (holding a list).</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="co">-}</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="fu">combine</span> : <span class="dt">List</span> (<span class="dt">Maybe</span> <span class="fu">a</span>) <span class="op">-&gt;</span> <span class="dt">Maybe</span> (<span class="dt">List</span> <span class="fu">a</span>)</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="co">{-| Map a function producing maybes on a list</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="co">and combine those into a single maybe (holding a list).</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="co">Also known as `traverse` on lists.</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="co">    combineMap f xs == combine (List.map f xs)</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a><span class="co">-}</span></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a><span class="fu">combineMap</span> : (<span class="fu">a</span> <span class="op">-&gt;</span> <span class="dt">Maybe</span> <span class="fu">b</span>) <span class="op">-&gt;</span> <span class="dt">List</span> <span class="fu">a</span> <span class="op">-&gt;</span> <span class="dt">Maybe</span> (<span class="dt">List</span> <span class="fu">b</span>)</span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a><span class="fu">combineMap</span> <span class="fu">f</span> <span class="op">=</span></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a>    <span class="fu">combine</span> <span class="op">&lt;&lt;</span> <span class="dt">List</span><span class="op">.</span><span class="fu">map</span> <span class="fu">f</span></span></code></pre></div>
<p>The idea is simple but incredibly powerful: you have a <strong>list of inputs</strong>, a <strong>function that processes each input individually into a <code>Maybe</code></strong>, and you want to get back a <strong>single <code>Maybe</code> holding a list</strong> — or <code>Nothing</code> if anything goes wrong along the way.</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="fu">combineMap</span> <span class="dt">String</span><span class="op">.</span><span class="fu">toInt</span> [ <span class="st">&quot;1&quot;</span><span class="op">,</span> <span class="st">&quot;2&quot;</span><span class="op">,</span> <span class="st">&quot;3&quot;</span> ]</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- &gt; Just [1, 2, 3]</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="fu">combineMap</span> <span class="dt">String</span><span class="op">.</span><span class="fu">toInt</span> [ <span class="st">&quot;1&quot;</span><span class="op">,</span> <span class="st">&quot;oops&quot;</span><span class="op">,</span> <span class="st">&quot;3&quot;</span> ]</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="co">-- &gt; Nothing</span></span></code></pre></div>
<p>Well, this pattern of exchanging the positions of two type constructors has a name, and that name is <strong><code>traverse</code></strong>! 🤓</p>
<h2 id="what-is-traversable">What is <code>Traversable</code>?</h2>
<p>Here is how the <code>Traversable</code> typeclass is defined in Haskell:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> (<span class="dt">Functor</span> t, <span class="dt">Foldable</span> t) <span class="ot">=&gt;</span> <span class="dt">Traversable</span> t <span class="kw">where</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>  <span class="ot">{-# MINIMAL traverse | sequenceA #-}</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="ot">  traverse ::</span> <span class="dt">Applicative</span> f <span class="ot">=&gt;</span> (a <span class="ot">-&gt;</span> f b) <span class="ot">-&gt;</span> t a <span class="ot">-&gt;</span> f (t b)</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>  <span class="fu">traverse</span> f <span class="ot">=</span> <span class="fu">sequenceA</span> <span class="op">.</span> <span class="fu">fmap</span> f</span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a><span class="ot">  sequenceA ::</span> <span class="dt">Applicative</span> f <span class="ot">=&gt;</span> t (f a) <span class="ot">-&gt;</span> f (t a)</span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>  <span class="fu">sequenceA</span> <span class="ot">=</span> <span class="fu">traverse</span> <span class="fu">id</span></span></code></pre></div>
<p>There is quite a lot to unpack here, so let us go through it step by step.</p>
<p>First, notice the typeclass constraints: <code>Functor t, Foldable t</code>. The <code>Functor</code> one is easy to spot — <code>traverse f = sequenceA . fmap f</code> uses <code>fmap</code> directly. But why <code>Foldable</code>? Because every <code>Traversable</code> is automatically a <code>Foldable</code>: if you can traverse a structure running effects, you can certainly fold it too — just use an applicative that ignores the “shape-preserving” part and only accumulates values. In fact, <code>foldMap</code> is always derivable from <code>traverse</code>, which is why Haskell requires <code>Foldable</code> as a superclass: to make that relationship explicit rather than leaving it implicit. 🧩</p>
<p>You can think of <code>Traversable</code> as the typeclass that lets you visit every element of a structure, run an effect on each one, and get back the same structure with all the results — but with the effect <em>pulled out to the top</em>. 🏗️</p>
<p>Second, notice the <code>MINIMAL</code> pragma: you only need to implement <strong>either</strong> <code>traverse</code> or <code>sequenceA</code>, and you get the other for free, since they are defined in terms of each other!</p>
<p>Now let us look at <code>traverse</code> more closely:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="fu">traverse</span><span class="ot"> ::</span> (<span class="dt">Traversable</span> t, <span class="dt">Applicative</span> f) <span class="ot">=&gt;</span> (a <span class="ot">-&gt;</span> f b) <span class="ot">-&gt;</span> t a <span class="ot">-&gt;</span> f (t b)</span></code></pre></div>
<p>Does that type signature look familiar? Compare it with our Elm <code>combineMap</code>:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="fu">traverse</span><span class="ot">  ::</span> <span class="dt">Applicative</span> f <span class="ot">=&gt;</span> (a <span class="ot">-&gt;</span> f b)      <span class="ot">-&gt;</span> t a    <span class="ot">-&gt;</span> f (t b)</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>combineMap <span class="op">:</span>                  (a <span class="ot">-&gt;</span> <span class="dt">Maybe</span> b)   <span class="ot">-&gt;</span> <span class="dt">List</span> a <span class="ot">-&gt;</span> <span class="dt">Maybe</span> (<span class="dt">List</span> b)</span></code></pre></div>
<p><code>combineMap</code> is just <code>traverse</code> specialised to <code>List</code> as the container (<code>t</code>) and <code>Maybe</code> as the applicative effect (<code>f</code>)! 🤯🤯🤯</p>
<h2 id="sequencea--sequence-flipping-the-types"><code>sequenceA</code> / <code>sequence</code>: flipping the types</h2>
<p>Now let us talk about <code>sequenceA</code>, and its older sibling <a href="https://hackage.haskell.org/package/base-4.21.0.0/docs/Prelude.html#v:sequence"><code>sequence</code></a> from the Haskell Prelude:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="fu">sequenceA</span><span class="ot"> ::</span> (<span class="dt">Traversable</span> t, <span class="dt">Applicative</span> f) <span class="ot">=&gt;</span> t (f a) <span class="ot">-&gt;</span> f (t a)</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="fu">sequence</span><span class="ot">  ::</span> (<span class="dt">Traversable</span> t, <span class="dt">Monad</span> m)       <span class="ot">=&gt;</span> t (m a) <span class="ot">-&gt;</span> m (t a)</span></code></pre></div>
<p>The intuition here is beautiful: <code>sequenceA</code> <em>flips</em> the types around, turning <code>t (f a)</code> into <code>f (t a)</code>. In plain words: it takes “a list of Results” and turns it into “a Result of a list”:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="fu">sequenceA</span> [<span class="dt">Just</span> <span class="dv">1</span>, <span class="dt">Just</span> <span class="dv">2</span>, <span class="dt">Just</span> <span class="dv">3</span>]</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="fu">sequenceA</span> [<span class="dt">Just</span> <span class="dv">1</span>, <span class="dt">Nothing</span>, <span class="dt">Just</span> <span class="dv">3</span>]</span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Nothing</span></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="fu">sequenceA</span> [<span class="dt">Right</span> <span class="dv">1</span>, <span class="dt">Right</span> <span class="dv">2</span>, <span class="dt">Right</span> <span class="dv">3</span>]</span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a><span class="dt">Right</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="fu">sequenceA</span> [<span class="dt">Right</span> <span class="dv">1</span>, <span class="dt">Left</span> <span class="st">&quot;oops&quot;</span>, <span class="dt">Right</span> <span class="dv">3</span>]</span>
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a><span class="dt">Left</span> <span class="st">&quot;oops&quot;</span></span></code></pre></div>
<p>And notice how <code>combine</code> from Elm’s <code>core-extra</code> is <em>exactly</em> this, specialised to <code>Maybe</code>:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="fu">sequenceA</span><span class="ot"> ::</span> <span class="dt">Applicative</span> f <span class="ot">=&gt;</span> [f a]          <span class="ot">-&gt;</span> f [a]</span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>combine   <span class="op">:</span>                   <span class="dt">List</span> (<span class="dt">Maybe</span> a) <span class="ot">-&gt;</span> <span class="dt">Maybe</span> (<span class="dt">List</span> a)</span></code></pre></div>
<p>YOU HAVE BEEN USING <code>sequenceA</code> ALL ALONG! 🥁🥁🥁</p>
<p>Now, <code>sequence</code> (the Monad variant) is what you see in the Elm <a href="https://package.elm-lang.org/packages/elm/core/1.0.5/Task#sequence"><code>Task.sequence</code></a> documentation:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="fu">sequence</span> : <span class="dt">List</span> (<span class="dt">Task</span> <span class="fu">x</span> <span class="fu">a</span>) <span class="op">-&gt;</span> <span class="dt">Task</span> <span class="fu">x</span> (<span class="dt">List</span> <span class="fu">a</span>)</span></code></pre></div>
<p>This is exactly <code>sequence</code> from Haskell, specialised to <code>Task</code>! You give it a list of tasks, and it runs them one by one, collecting all the results into a single <code>Task</code> wrapping a list. If any task fails, the whole thing short-circuits. The relationship is exactly the same as between <code>combine</code> and <code>combineMap</code>:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="fu">traverse</span> f  <span class="ot">=</span> <span class="fu">sequenceA</span> <span class="op">.</span> <span class="fu">fmap</span> f   <span class="co">-- like: combineMap f = combine &lt;&lt; List.map f</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="fu">sequenceA</span>   <span class="ot">=</span> <span class="fu">traverse</span> <span class="fu">id</span>          <span class="co">-- like: combine = combineMap identity</span></span></code></pre></div>
<p>Same pattern, just finally given its proper name. ✨</p>
<h2 id="a-real-world-elm-example">A real-world Elm example</h2>
<p>A great practical example of where <code>traverse</code> shows up in the wild is in <a href="https://package.elm-lang.org/packages/jfmengels/elm-review/latest/">elm-review</a>. Imagine you have a list of fixes to apply to source code, where each fix can either succeed or fail:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="fu">compileFixes</span> : <span class="dt">List</span> <span class="dt">Fix</span> <span class="op">-&gt;</span> <span class="dt">Result</span> <span class="dt">Error</span> (<span class="dt">List</span> <span class="dt">CompiledFix</span>)</span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="fu">compileFixes</span> <span class="fu">fixes</span> <span class="op">=</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Result</span><span class="op">.</span><span class="dt">Extra</span><span class="op">.</span><span class="fu">combineMap</span> <span class="fu">compileFix</span> <span class="fu">fixes</span></span></code></pre></div>
<p>The pattern is precisely: <strong>list of inputs + function that processes each input individually into a result → result holding a list, or an error if it happened anywhere</strong>. <code>traverse</code> in a nutshell! 🎯</p>
<h2 id="implementing-traversable-for-a-custom-type">Implementing <code>Traversable</code> for a custom type</h2>
<p>Let’s see how easy it is to implement <code>Traversable</code> for a custom Haskell type. Recall our binary tree from the previous post:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Tree</span> a</span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>  <span class="ot">=</span> <span class="dt">Leaf</span></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">Node</span> (<span class="dt">Tree</span> a) a (<span class="dt">Tree</span> a)</span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Functor</span>, <span class="dt">Foldable</span>)</span></code></pre></div>
<p>Adding a <code>Traversable</code> instance is beautifully simple:</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Traversable</span> <span class="dt">Tree</span> <span class="kw">where</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>  <span class="fu">traverse</span> _ <span class="dt">Leaf</span>         <span class="ot">=</span> <span class="fu">pure</span> <span class="dt">Leaf</span></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a>  <span class="fu">traverse</span> f (<span class="dt">Node</span> l x r) <span class="ot">=</span> <span class="dt">Node</span> <span class="op">&lt;$&gt;</span> <span class="fu">traverse</span> f l <span class="op">&lt;*&gt;</span> f x <span class="op">&lt;*&gt;</span> <span class="fu">traverse</span> f r</span></code></pre></div>
<p>Look at that! We are using <code>&lt;$&gt;</code> (<code>fmap</code>) and <code>&lt;*&gt;</code> (from <code>Applicative</code>). That is why <code>Traversable</code> requires <code>Functor</code>: we need to lift the <code>Node</code> constructor into the applicative context and then apply it to each traversed branch. 🧠</p>
<p>Or, if we enable the language extensions, we can derive everything automatically:</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# language DeriveFunctor, DeriveFoldable, DeriveTraversable #-}</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Tree</span> a</span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a>  <span class="ot">=</span> <span class="dt">Leaf</span></span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">Node</span> (<span class="dt">Tree</span> a) a (<span class="dt">Tree</span> a)</span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Functor</span>, <span class="dt">Foldable</span>, <span class="dt">Traversable</span>)</span></code></pre></div>
<p>And now we can <code>traverse</code> over trees with any <code>Applicative</code> effect:</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="fu">traverse</span> (\x <span class="ot">-&gt;</span> <span class="kw">if</span> x <span class="op">&gt;</span> <span class="dv">0</span> <span class="kw">then</span> <span class="dt">Just</span> x <span class="kw">else</span> <span class="dt">Nothing</span>) (<span class="dt">Node</span> (<span class="dt">Node</span> <span class="dt">Leaf</span> <span class="dv">1</span> <span class="dt">Leaf</span>) <span class="dv">2</span> (<span class="dt">Node</span> <span class="dt">Leaf</span> <span class="dv">3</span> <span class="dt">Leaf</span>))</span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> (<span class="dt">Node</span> (<span class="dt">Node</span> <span class="dt">Leaf</span> <span class="dv">1</span> <span class="dt">Leaf</span>) <span class="dv">2</span> (<span class="dt">Node</span> <span class="dt">Leaf</span> <span class="dv">3</span> <span class="dt">Leaf</span>))</span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="fu">traverse</span> (\x <span class="ot">-&gt;</span> <span class="kw">if</span> x <span class="op">&gt;</span> <span class="dv">0</span> <span class="kw">then</span> <span class="dt">Just</span> x <span class="kw">else</span> <span class="dt">Nothing</span>) (<span class="dt">Node</span> (<span class="dt">Node</span> <span class="dt">Leaf</span> (<span class="op">-</span><span class="dv">1</span>) <span class="dt">Leaf</span>) <span class="dv">2</span> (<span class="dt">Node</span> <span class="dt">Leaf</span> <span class="dv">3</span> <span class="dt">Leaf</span>))</span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Nothing</span></span></code></pre></div>
<h2 id="a-useful-derived-function-for">A useful derived function: <code>for</code></h2>
<p>Haskell also provides a convenience function called <code>for</code>, which is just <code>traverse</code> with its arguments flipped:</p>
<div class="sourceCode" id="cb16"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="ot">for ::</span> (<span class="dt">Traversable</span> t, <span class="dt">Applicative</span> f) <span class="ot">=&gt;</span> t a <span class="ot">-&gt;</span> (a <span class="ot">-&gt;</span> f b) <span class="ot">-&gt;</span> f (t b)</span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a>for <span class="ot">=</span> <span class="fu">flip</span> <span class="fu">traverse</span></span></code></pre></div>
<p>This is handy when you want to write the data first and the function second, which sometimes reads more naturally:</p>
<div class="sourceCode" id="cb17"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- traverse: function first, data second</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a><span class="fu">traverse</span> validatePositive [<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>]</span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a><span class="co">-- for: data first, function second (feels more like Elm&#39;s `|&gt;`!)</span></span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a>for [<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>] validatePositive</span></code></pre></div>
<p>And of course, there are also <code>forM</code> (the Monad version), <code>mapM</code> and others — but they are all just specialised or flipped variants of the same idea. 😊</p>
<h2 id="bonus-collecting-all-errors-gift">Bonus: collecting ALL errors 🎁</h2>
<p>At this point, a very curious reader might ask: <em>“What if I want to collect ALL the errors, not just the first one? Like, end up with <code>Result (List err) (List ok)</code>?”</em></p>
<p>This is a fantastic question! With plain <code>Result</code> / <code>Either</code>, <code>traverse</code> short-circuits on the very first error and does not process the rest. This is because <code>Either</code> is a <code>Monad</code>, and the sequential nature of monads means they <em>cannot</em> accumulate errors.</p>
<p>To collect all errors, we need a different type. In Haskell, that type is <a href="https://hackage.haskell.org/package/validation-1.1.3/docs/Data-Validation.html"><code>Validation</code></a> from the <code>validation</code> package:</p>
<div class="sourceCode" id="cb18"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Validation</span> e a</span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a>  <span class="ot">=</span> <span class="dt">Failure</span> e</span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">Success</span> a</span></code></pre></div>
<p>The key insight is: <code>Validation</code> is an <strong><code>Applicative</code></strong> but <strong>NOT a <code>Monad</code></strong>! And that is precisely what enables error accumulation. Since <code>traverse</code> only requires an <code>Applicative</code> constraint (not a <code>Monad</code> one), you can plug <code>Validation</code> in and watch it collect all failures:</p>
<div class="sourceCode" id="cb19"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Validation</span></span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a><span class="ot">validatePositive ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Validation</span> [<span class="dt">String</span>] <span class="dt">Int</span></span>
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a>validatePositive x</span>
<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> x <span class="op">&gt;</span> <span class="dv">0</span>    <span class="ot">=</span> <span class="dt">Success</span> x</span>
<span id="cb19-6"><a href="#cb19-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="dt">Failure</span> [<span class="st">&quot;Expected a positive number, got: &quot;</span> <span class="op">&lt;&gt;</span> <span class="fu">show</span> x]</span>
<span id="cb19-7"><a href="#cb19-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-8"><a href="#cb19-8" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="fu">traverse</span> validatePositive [<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>]</span>
<span id="cb19-9"><a href="#cb19-9" aria-hidden="true" tabindex="-1"></a><span class="dt">Success</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span>
<span id="cb19-10"><a href="#cb19-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-11"><a href="#cb19-11" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="fu">traverse</span> validatePositive [<span class="dv">1</span>, <span class="op">-</span><span class="dv">2</span>, <span class="dv">3</span>, <span class="op">-</span><span class="dv">4</span>]</span>
<span id="cb19-12"><a href="#cb19-12" aria-hidden="true" tabindex="-1"></a><span class="dt">Failure</span> [<span class="st">&quot;Expected a positive number, got: -2&quot;</span>,<span class="st">&quot;Expected a positive number, got: -4&quot;</span>]</span></code></pre></div>
<p>ALL errors are accumulated! 🎉</p>
<p>This is one of those beautiful insights that emerge from the typeclass hierarchy: <strong>whether you short-circuit or accumulate errors is not a property of <code>traverse</code> itself, but of the <code>Applicative</code> you use with it</strong>! ✨</p>
<p>In Elm, <code>Result</code> always short-circuits (it behaves like a <code>Monad</code>), so to accumulate errors you would need a custom type similar to <code>Validation</code>. Some community packages take this approach for form validation. But this also reveals <em>why</em> such a type does not exist in <code>elm/core</code> — it is a fundamentally different beast from <code>Result</code>, since it cannot support <code>andThen</code> / monadic chaining.</p>
<h2 id="the-typeclass-hierarchy">The typeclass hierarchy</h2>
<p>Let us take a moment to appreciate how <code>Traversable</code> fits into the bigger picture:</p>
<pre><code>            Functor                      Foldable
        (can map over structure)   (can collapse structure, forgetting shape)
                |                            |
                +------------+---------------+
                             |
                       Traversable  (can traverse with effects, preserving shape)</code></pre>
<p><code>Traversable</code> sits right at the intersection of <code>Functor</code> and <code>Foldable</code>, but adds something neither of them can do alone: <strong>running effects while preserving the container shape</strong>. If <code>Foldable</code> says <em>“I can visit all elements and forget the structure”</em>, <code>Traversable</code> says <em>“I can visit all elements, run an effect on each, and remember the structure”</em>. The extra power comes from the <code>Applicative</code> constraint on <code>f</code>. 🏆</p>
<h2 id="it-is-always-traverse-male_detective">It is always <code>traverse</code>! 🕵️‍♂️</h2>
<p>There is an old Haskell saying: <em>“The answer is always monads.”</em> But in my experience, once you have learned <code>traverse</code>, a new truth reveals itself: <strong>the answer is always <code>traverse</code></strong>! 😄</p>
<p>JSON decoders? <code>traverse</code>. Form validation? <code>traverse</code>. Running a list of tasks? That is <code>sequence</code>, which is just <code>traverse id</code>. Applying a list of fixes? Also <code>traverse</code>. Even the humble <code>combineMap</code> you have been writing in Elm? <code>traverse</code>.</p>
<p>Once you see it, you cannot unsee it. You are welcome. 🙃</p>
<h2 id="acknowledgements">Acknowledgements</h2>
<p>Many thanks to <a href="https://twitter.com/jfmengels">@jfmengels</a> for the real-world elm-review inspiration, and to <a href="https://twitter.com/janiczek">@janiczek</a> for asking the excellent question about collecting all errors — both made this post much richer! 🙏🏻</p>
<p>Special thanks as always to <a href="https://twitter.com/trupill">@serras</a> for technical proofreading. 🙏🏻</p>
<p>Hope you enjoyed learning about <code>Traversable</code> — it is one of those typeclasses that once you see it, you start noticing it <em>everywhere</em>! 😄 If you found joy in this blogpost and would like me to continue the series, please consider <a href="https://github.com/sponsors/kutyel">sponsoring my work</a>, share it in your social networks and <strong>follow me on <a href="https://twitter.com/FlavioCorpa">Twitter</a>/<a href="https://bsky.app/profile/flaviocorpa.com">BlueSky!</a> 🦋</strong> 🙌🏻</p></section>
  </article>
</main>

 <footer class="py-14 bg-[var(--footerBgColor)] shrink-0">
  <div class="relative mx-auto md:w-[600px] w-auto px-[1.3125rem]">
    <ul class="flex justify-center list-none" role="list">
      <li class="mx-3" role="listitem">
        <a href="/">Home</a>
      </li>
      <li class="mx-3" role="listitem">
        <a href="https://github.com/sponsors/kutyel/">Sponsor me</a>
      </li>
      <li class="mx-3" role="listitem">
        <a href="/atom.xml">RSS</a>
      </li>
    </ul>
  </div>
</footer>


<script src="https://gistcdn.githack.com/kutyel/41d12e099484fd390fb67168271fcdd9/raw/9be26e500525a2e4edacc53d3a8006aaddec0e15/bsky-comments.js"></script>
]]></description>
    <pubDate>Thu, 26 Mar 2026 14:00:00 UT</pubDate>
    <guid>https://flaviocorpa.com/haskell-for-elm-developers-giving-names-to-stuff-part-7-traversable.html</guid>
    <dc:creator>Flavio Corpa</dc:creator>
</item>
<item>
    <title>Haskell for Elm developers: giving names to stuff (Part 6 - Foldable)</title>
    <link>https://flaviocorpa.com/haskell-for-elm-developers-giving-names-to-stuff-part-6-foldable.html</link>
    <description><![CDATA[<nav class="my-6 py-2">
  <div class="relative mx-auto md:w-[600px] w-auto px-[1.3125rem] md:px-0" data-nav-wrap>
    <a class="mr-5 absolute left-[-10000px] focus:static focus:left-auto" href="#content"
      >Skip to content</a
    >
    <a class="mr-5" href="/">Home</a>
    <a class="mr-5" href="https://github.com/sponsors/kutyel">Sponsor me</a>
    <a class="mr-5" href="/atom.xml">RSS</a>
  </div>
</nav>


<style>
  bsky-comments {
    --background-color: var(--bgColor);
    --text-color: var(--textColor);
    --link-color: var(--textLinkColor);
    --link-hover-color: var(--textLinkHoverColor);
    --comment-meta-color: #888;
    --error-color: #ff4d4d;
    --reply-border-color: var(--separatorColor);
    --button-background-color: var(--btnBgColor);
    --button-hover-background-color: rgba(var(--btnBgColor), 0.2);
    --author-avatar-border-radius: 50%;
  }
</style>

<main class="flex-1" id="content" tabindex="-1">
  <article class="pb-10">
    <header class="bg-[var(--headerBgColor)] mb-8 px-[1.3125rem] md:px-0 py-4 md:py-8">
      <div class="mx-auto md:w-[600px]">
        <h1 class="text-[1.7rem] md:text-[3rem] m-0 mb-4 font-normal leading-[1.2] text-[var(--h1Color)]">
          Haskell for Elm developers: giving names to stuff (Part 6 - Foldable)
        </h1>
        <div class="mx-auto md:w-[600px]">
          <small class="italic">13/02/2026</small>
          <small class="italic"> | 6 min read</small>
          
          <div class="mt-2">[ <a title="All pages tagged &#39;haskell&#39;." href="/tags/haskell.html" rel="tag">haskell</a>, <a title="All pages tagged &#39;elm&#39;." href="/tags/elm.html" rel="tag">elm</a>, <a title="All pages tagged &#39;fp&#39;." href="/tags/fp.html" rel="tag">fp</a> ]</div>
        </div>
      </div>
    </header>
    <section class="mx-auto md:w-[600px] px-[1.3125rem] md:px-0"><p><img src="./images/haskell-elm.svg" alt="logo" width="300px"></p>
<p>Welcome back! In my <a href="https://flaviocorpa.com/haskell-for-elm-developers-giving-names-to-stuff-part-5-semigroups-and-monoids.html">last post</a>, we talked about Semigroups and Monoids, and we even discovered the deep relationship between folds and Monoids. But we left something out: the <code>Foldable</code> typeclass itself! So today, let’s give it the attention it deserves. 😊</p>
<h2 id="what-is-foldable">What is Foldable?</h2>
<p>If you recall from the previous post, we used <code>foldr</code> and <code>foldl</code> on lists as if it were the most natural thing in the world. But in Haskell, folding is not limited to lists! The <code>Foldable</code> typeclass generalises the concept of folding to <em>any</em> data structure that can be collapsed into a summary value.</p>
<p>Here is the (simplified) definition:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Foldable</span> t <span class="kw">where</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>  <span class="ot">{-# MINIMAL foldMap | foldr #-}</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="ot">  foldr  ::</span> (a <span class="ot">-&gt;</span> b <span class="ot">-&gt;</span> b) <span class="ot">-&gt;</span> b <span class="ot">-&gt;</span> t a <span class="ot">-&gt;</span> b</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="ot">  foldl  ::</span> (b <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> b) <span class="ot">-&gt;</span> b <span class="ot">-&gt;</span> t a <span class="ot">-&gt;</span> b</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="ot">  foldMap ::</span> <span class="dt">Monoid</span> m <span class="ot">=&gt;</span> (a <span class="ot">-&gt;</span> m) <span class="ot">-&gt;</span> t a <span class="ot">-&gt;</span> m</span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>  <span class="fu">foldMap</span> f <span class="ot">=</span> <span class="fu">foldr</span> (<span class="fu">mappend</span> <span class="op">.</span> f) <span class="fu">mempty</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="ot">  fold ::</span> <span class="dt">Monoid</span> m <span class="ot">=&gt;</span> t m <span class="ot">-&gt;</span> m</span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>  fold <span class="ot">=</span> <span class="fu">foldMap</span> <span class="fu">id</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a><span class="ot">  length  ::</span> t a <span class="ot">-&gt;</span> <span class="dt">Int</span></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a><span class="ot">  null    ::</span> t a <span class="ot">-&gt;</span> <span class="dt">Bool</span></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a><span class="ot">  elem    ::</span> <span class="dt">Eq</span> a <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> t a <span class="ot">-&gt;</span> <span class="dt">Bool</span></span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a><span class="ot">  maximum ::</span> <span class="dt">Ord</span> a <span class="ot">=&gt;</span> t a <span class="ot">-&gt;</span> a</span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a><span class="ot">  minimum ::</span> <span class="dt">Ord</span> a <span class="ot">=&gt;</span> t a <span class="ot">-&gt;</span> a</span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a><span class="ot">  sum     ::</span> <span class="dt">Num</span> a <span class="ot">=&gt;</span> t a <span class="ot">-&gt;</span> a</span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a><span class="ot">  product ::</span> <span class="dt">Num</span> a <span class="ot">=&gt;</span> t a <span class="ot">-&gt;</span> a</span>
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a><span class="ot">  toList  ::</span> t a <span class="ot">-&gt;</span> [a]</span></code></pre></div>
<p>That is a LOT of stuff for free! And the beautiful thing is: you only need to implement <strong>either</strong> <code>foldr</code> or <code>foldMap</code> to get all of these functions automatically 🤯 (as indicated by the MINIMAL pragma).</p>
<h2 id="foldable-in-elm-sort-of">Foldable in Elm (sort of)</h2>
<p>Now, Elm does not have typeclasses (well, not user-definable ones, as we discussed in <a href="https://flaviocorpa.com/haskell-for-elm-developers-giving-names-to-stuff-part-1-functors.html">Part 1</a>), so there is no <code>Foldable</code> typeclass. But that does not mean you have not been using foldable things all along!</p>
<p>Let’s see what we have in <code>elm/core</code>:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="dt">List</span><span class="op">.</span><span class="fu">foldr</span>   : (<span class="fu">a</span> <span class="op">-&gt;</span> <span class="fu">b</span> <span class="op">-&gt;</span> <span class="fu">b</span>) <span class="op">-&gt;</span> <span class="fu">b</span> <span class="op">-&gt;</span> <span class="dt">List</span> <span class="fu">a</span> <span class="op">-&gt;</span> <span class="fu">b</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="dt">List</span><span class="op">.</span><span class="fu">foldl</span>   : (<span class="fu">a</span> <span class="op">-&gt;</span> <span class="fu">b</span> <span class="op">-&gt;</span> <span class="fu">b</span>) <span class="op">-&gt;</span> <span class="fu">b</span> <span class="op">-&gt;</span> <span class="dt">List</span> <span class="fu">a</span> <span class="op">-&gt;</span> <span class="fu">b</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Array</span><span class="op">.</span><span class="fu">foldr</span>  : (<span class="fu">a</span> <span class="op">-&gt;</span> <span class="fu">b</span> <span class="op">-&gt;</span> <span class="fu">b</span>) <span class="op">-&gt;</span> <span class="fu">b</span> <span class="op">-&gt;</span> <span class="dt">Array</span> <span class="fu">a</span> <span class="op">-&gt;</span> <span class="fu">b</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Array</span><span class="op">.</span><span class="fu">foldl</span>  : (<span class="fu">a</span> <span class="op">-&gt;</span> <span class="fu">b</span> <span class="op">-&gt;</span> <span class="fu">b</span>) <span class="op">-&gt;</span> <span class="fu">b</span> <span class="op">-&gt;</span> <span class="dt">Array</span> <span class="fu">a</span> <span class="op">-&gt;</span> <span class="fu">b</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Dict</span><span class="op">.</span><span class="fu">foldr</span>   : (<span class="fu">k</span> <span class="op">-&gt;</span> <span class="fu">v</span> <span class="op">-&gt;</span> <span class="fu">b</span> <span class="op">-&gt;</span> <span class="fu">b</span>) <span class="op">-&gt;</span> <span class="fu">b</span> <span class="op">-&gt;</span> <span class="dt">Dict</span> <span class="fu">k</span> <span class="fu">v</span> <span class="op">-&gt;</span> <span class="fu">b</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="dt">Dict</span><span class="op">.</span><span class="fu">foldl</span>   : (<span class="fu">k</span> <span class="op">-&gt;</span> <span class="fu">v</span> <span class="op">-&gt;</span> <span class="fu">b</span> <span class="op">-&gt;</span> <span class="fu">b</span>) <span class="op">-&gt;</span> <span class="fu">b</span> <span class="op">-&gt;</span> <span class="dt">Dict</span> <span class="fu">k</span> <span class="fu">v</span> <span class="op">-&gt;</span> <span class="fu">b</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a><span class="dt">Set</span><span class="op">.</span><span class="fu">foldr</span>    : (<span class="fu">a</span> <span class="op">-&gt;</span> <span class="fu">b</span> <span class="op">-&gt;</span> <span class="fu">b</span>) <span class="op">-&gt;</span> <span class="fu">b</span> <span class="op">-&gt;</span> <span class="dt">Set</span> <span class="fu">a</span> <span class="op">-&gt;</span> <span class="fu">b</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a><span class="dt">Set</span><span class="op">.</span><span class="fu">foldl</span>    : (<span class="fu">a</span> <span class="op">-&gt;</span> <span class="fu">b</span> <span class="op">-&gt;</span> <span class="fu">b</span>) <span class="op">-&gt;</span> <span class="fu">b</span> <span class="op">-&gt;</span> <span class="dt">Set</span> <span class="fu">a</span> <span class="op">-&gt;</span> <span class="fu">b</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a><span class="dt">String</span><span class="op">.</span><span class="fu">foldr</span> : (<span class="dt">Char</span> <span class="op">-&gt;</span> <span class="fu">b</span> <span class="op">-&gt;</span> <span class="fu">b</span>) <span class="op">-&gt;</span> <span class="fu">b</span> <span class="op">-&gt;</span> <span class="dt">String</span> <span class="op">-&gt;</span> <span class="fu">b</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a><span class="dt">String</span><span class="op">.</span><span class="fu">foldl</span> : (<span class="dt">Char</span> <span class="op">-&gt;</span> <span class="fu">b</span> <span class="op">-&gt;</span> <span class="fu">b</span>) <span class="op">-&gt;</span> <span class="fu">b</span> <span class="op">-&gt;</span> <span class="dt">String</span> <span class="op">-&gt;</span> <span class="fu">b</span></span></code></pre></div>
<p>Do you see the pattern? <code>List</code>, <code>Array</code>, <code>Dict</code>, <code>Set</code> and <code>String</code> all have <code>foldr</code> and <code>foldl</code>. In Haskell, they would all be instances of <code>Foldable</code>, and you could write <strong>one</strong> generic function that works on all of them. In Elm, you have to pick the specific module each time… but the concept is the same! ✨</p>
<p>And then there are all the derived functions: <code>List.length</code>, <code>List.isEmpty</code>, <code>List.member</code>, <code>List.sum</code>, <code>List.product</code>, <code>List.maximum</code>, <code>List.minimum</code>… do they look familiar? They are <em>exactly</em> the functions that <code>Foldable</code> gives you for free in Haskell! 😉</p>
<h2 id="how-easy-is-it-to-implement-foldable">How easy is it to implement Foldable?</h2>
<p>Here is one of my favourite things about <code>Foldable</code>: implementing it is almost trivially easy. Suppose we have a simple binary tree type in Haskell:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Tree</span> a</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>  <span class="ot">=</span> <span class="dt">Leaf</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">Node</span> (<span class="dt">Tree</span> a) a (<span class="dt">Tree</span> a)</span></code></pre></div>
<p>Making it <code>Foldable</code> is just this:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Foldable</span> <span class="dt">Tree</span> <span class="kw">where</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>  <span class="fu">foldMap</span> _ <span class="dt">Leaf</span>         <span class="ot">=</span> <span class="fu">mempty</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>  <span class="fu">foldMap</span> f (<span class="dt">Node</span> l x r) <span class="ot">=</span> <span class="fu">foldMap</span> f l <span class="op">&lt;&gt;</span> f x <span class="op">&lt;&gt;</span> <span class="fu">foldMap</span> f r</span></code></pre></div>
<p>That’s it! Three lines. And now we get <code>foldr</code>, <code>foldl</code>, <code>length</code>, <code>sum</code>, <code>product</code>, <code>toList</code>, <code>elem</code>, <code>null</code>, <code>maximum</code>, <code>minimum</code> and more… all for free! 🎁</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="kw">let</span> tree <span class="ot">=</span> <span class="dt">Node</span> (<span class="dt">Node</span> <span class="dt">Leaf</span> <span class="dv">1</span> <span class="dt">Leaf</span>) <span class="dv">2</span> (<span class="dt">Node</span> <span class="dt">Leaf</span> <span class="dv">3</span> <span class="dt">Leaf</span>)</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> toList tree</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>[<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="fu">sum</span> tree</span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a><span class="dv">6</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="fu">product</span> tree</span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a><span class="dv">6</span></span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="fu">length</span> tree</span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a><span class="dv">3</span></span>
<span id="cb5-14"><a href="#cb5-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-15"><a href="#cb5-15" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="fu">elem</span> <span class="dv">2</span> tree</span>
<span id="cb5-16"><a href="#cb5-16" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span></span>
<span id="cb5-17"><a href="#cb5-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-18"><a href="#cb5-18" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="fu">null</span> tree</span>
<span id="cb5-19"><a href="#cb5-19" aria-hidden="true" tabindex="-1"></a><span class="dt">False</span></span>
<span id="cb5-20"><a href="#cb5-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-21"><a href="#cb5-21" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="fu">maximum</span> tree</span>
<span id="cb5-22"><a href="#cb5-22" aria-hidden="true" tabindex="-1"></a><span class="dv">3</span></span></code></pre></div>
<p>If you use the <code>DeriveFoldable</code> language extension, you don’t even need to write the instance by hand:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# language DeriveFoldable #-}</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Tree</span> a</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>  <span class="ot">=</span> <span class="dt">Leaf</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">Node</span> (<span class="dt">Tree</span> a) a (<span class="dt">Tree</span> a)</span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Foldable</span>)</span></code></pre></div>
<p>And boom, you are done! Haskell literally writes the <code>Foldable</code> instance for you. 🪄</p>
<h2 id="the-power-of-scanl">The power of <code>scanl</code></h2>
<p>Now, there’s a function closely related to folds that I find incredibly useful and want to highlight: <code>scanl</code>. If <code>foldl</code> reduces a structure down to a single value, <code>scanl</code> is like <code>foldl</code> but it <em>keeps all the intermediate results</em>:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="fu">scanl</span><span class="ot"> ::</span> <span class="dt">Foldable</span> f <span class="ot">=&gt;</span> (b <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> b) <span class="ot">-&gt;</span> b <span class="ot">-&gt;</span> f a <span class="ot">-&gt;</span> <span class="dt">NonEmpty</span> b</span></code></pre></div>
<p>Notice how <code>scanl</code> in Haskell takes any <code>Foldable</code> (not just a <code>List</code>!) and returns a <code>NonEmpty</code> list, because there will always be at least one element (the initial accumulator). Let’s see it in action:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="kw">import</span> <span class="dt">Data.List.NonEmpty</span> (scanl)</span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="fu">scanl</span> (<span class="op">+</span>) <span class="dv">0</span> [<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>, <span class="dv">4</span>]</span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="dv">0</span> <span class="op">:|</span> [<span class="dv">1</span>,<span class="dv">3</span>,<span class="dv">6</span>,<span class="dv">10</span>]</span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="fu">scanl</span> (<span class="op">*</span>) <span class="dv">1</span> [<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>, <span class="dv">4</span>]</span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a><span class="dv">1</span> <span class="op">:|</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">6</span>,<span class="dv">24</span>]</span></code></pre></div>
<p>See how the last element of <code>scanl (+) 0 [1, 2, 3, 4]</code> is <code>10</code>, which is exactly what <code>foldl (+) 0 [1, 2, 3, 4]</code> would return? The <code>scanl</code> function gives you the <em>entire journey</em>, not just the destination! 🗺️</p>
<p>There is also <code>scanl1</code>, which uses the first element as the starting value:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="kw">import</span> <span class="dt">Data.List.NonEmpty</span> (scanl1)</span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="fu">scanl1</span> (<span class="op">+</span>) (<span class="dv">1</span> <span class="op">:|</span> [<span class="dv">2</span>, <span class="dv">3</span>, <span class="dv">4</span>])</span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a><span class="dv">1</span> <span class="op">:|</span> [<span class="dv">3</span>,<span class="dv">6</span>,<span class="dv">10</span>]</span></code></pre></div>
<p>And of course, there are right-to-left variants too: <code>scanr</code> and <code>scanr1</code>.</p>
<h2 id="scanl-in-elm"><code>scanl</code> in Elm!</h2>
<p>Here is the nice surprise: even though Elm does not have a built-in <code>scanl</code>, the community has got you covered! The excellent <a href="https://package.elm-lang.org/packages/elmcraft/core-extra/latest/List-Extra#scanl"><code>elmcraft/core-extra</code></a> package provides: <code>scanl</code>, <code>scanl1</code>, <code>scanr</code> and <code>scanr1</code>:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">List</span><span class="op">.</span><span class="dt">Extra</span> <span class="kw">exposing</span> (<span class="fu">scanl</span><span class="op">,</span> <span class="fu">scanl1</span><span class="op">,</span> <span class="fu">scanr</span><span class="op">,</span> <span class="fu">scanr1</span>)</span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a><span class="fu">scanl</span> (<span class="op">+</span>) <span class="dv">0</span> [ <span class="dv">1</span><span class="op">,</span> <span class="dv">2</span><span class="op">,</span> <span class="dv">3</span><span class="op">,</span> <span class="dv">4</span> ]</span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a><span class="co">--&gt; [ 0, 1, 3, 6, 10 ]</span></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a><span class="fu">scanl1</span> (<span class="op">+</span>) [ <span class="dv">1</span><span class="op">,</span> <span class="dv">2</span><span class="op">,</span> <span class="dv">3</span> ]</span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a><span class="co">--&gt; [ 1, 3, 6 ]</span></span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a><span class="fu">scanr</span> (<span class="op">+</span>) <span class="dv">0</span> [ <span class="dv">1</span><span class="op">,</span> <span class="dv">2</span><span class="op">,</span> <span class="dv">3</span> ]</span>
<span id="cb10-10"><a href="#cb10-10" aria-hidden="true" tabindex="-1"></a><span class="co">--&gt; [ 6, 5, 3, 0 ]</span></span>
<span id="cb10-11"><a href="#cb10-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-12"><a href="#cb10-12" aria-hidden="true" tabindex="-1"></a><span class="fu">scanr1</span> (<span class="op">+</span>) [ <span class="dv">1</span><span class="op">,</span> <span class="dv">2</span><span class="op">,</span> <span class="dv">3</span> ]</span>
<span id="cb10-13"><a href="#cb10-13" aria-hidden="true" tabindex="-1"></a><span class="co">--&gt; [ 6, 5, 3 ]</span></span></code></pre></div>
<p>The type signatures are exactly what you would expect:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="fu">scanl</span>  : (<span class="fu">a</span> <span class="op">-&gt;</span> <span class="fu">b</span> <span class="op">-&gt;</span> <span class="fu">b</span>) <span class="op">-&gt;</span> <span class="fu">b</span> <span class="op">-&gt;</span> <span class="dt">List</span> <span class="fu">a</span> <span class="op">-&gt;</span> <span class="dt">List</span> <span class="fu">b</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="fu">scanl1</span> : (<span class="fu">a</span> <span class="op">-&gt;</span> <span class="fu">a</span> <span class="op">-&gt;</span> <span class="fu">a</span>) <span class="op">-&gt;</span> <span class="dt">List</span> <span class="fu">a</span> <span class="op">-&gt;</span> <span class="dt">List</span> <span class="fu">a</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a><span class="fu">scanr</span>  : (<span class="fu">a</span> <span class="op">-&gt;</span> <span class="fu">b</span> <span class="op">-&gt;</span> <span class="fu">b</span>) <span class="op">-&gt;</span> <span class="fu">b</span> <span class="op">-&gt;</span> <span class="dt">List</span> <span class="fu">a</span> <span class="op">-&gt;</span> <span class="dt">List</span> <span class="fu">b</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a><span class="fu">scanr1</span> : (<span class="fu">a</span> <span class="op">-&gt;</span> <span class="fu">a</span> <span class="op">-&gt;</span> <span class="fu">a</span>) <span class="op">-&gt;</span> <span class="dt">List</span> <span class="fu">a</span> <span class="op">-&gt;</span> <span class="dt">List</span> <span class="fu">a</span></span></code></pre></div>
<h2 id="when-is-scanl-useful">When is <code>scanl</code> useful?</h2>
<p>You might be wondering: ok that’s nice, but when would I actually <em>use</em> this? Here are some practical examples:</p>
<p><strong>Running totals</strong> (think of a bank account balance):</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="fu">transactions</span> <span class="op">=</span> [ <span class="dv">100</span><span class="op">,</span> <span class="op">-</span><span class="dv">50</span><span class="op">,</span> <span class="dv">200</span><span class="op">,</span> <span class="op">-</span><span class="dv">30</span><span class="op">,</span> <span class="op">-</span><span class="dv">80</span> ]</span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a><span class="fu">scanl</span> (<span class="op">+</span>) <span class="dv">1000</span> <span class="fu">transactions</span></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a><span class="co">--&gt; [ 1000, 1100, 1050, 1250, 1220, 1140 ]</span></span></code></pre></div>
<p><strong>Tracking state over time</strong> (building up a history):</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="fu">scanl</span> (<span class="fu">flip</span> (<span class="op">:</span>)) [] [<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>]</span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>[] <span class="op">:|</span> [[<span class="dv">1</span>],[<span class="dv">2</span>,<span class="dv">1</span>],[<span class="dv">3</span>,<span class="dv">2</span>,<span class="dv">1</span>]]</span></code></pre></div>
<p><strong>Computing prefix maximums</strong>:</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="fu">scanl1</span> <span class="fu">max</span> [ <span class="dv">3</span><span class="op">,</span> <span class="dv">1</span><span class="op">,</span> <span class="dv">4</span><span class="op">,</span> <span class="dv">1</span><span class="op">,</span> <span class="dv">5</span><span class="op">,</span> <span class="dv">9</span><span class="op">,</span> <span class="dv">2</span><span class="op">,</span> <span class="dv">6</span> ]</span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="co">--&gt; [ 3, 3, 4, 4, 5, 9, 9, 9 ]</span></span></code></pre></div>
<p>Anytime you need a fold but also care about the intermediate steps, <code>scanl</code> is your friend! 🤝</p>
<h2 id="foldable--monoid--heart">Foldable + Monoid = ❤️</h2>
<p>Before we wrap up, I want to circle back to the beautiful connection between <code>Foldable</code> and <code>Monoid</code> that we explored in the previous post. Remember <code>foldMap</code>?</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="fu">foldMap</span><span class="ot"> ::</span> (<span class="dt">Foldable</span> t, <span class="dt">Monoid</span> m) <span class="ot">=&gt;</span> (a <span class="ot">-&gt;</span> m) <span class="ot">-&gt;</span> t a <span class="ot">-&gt;</span> m</span></code></pre></div>
<p>This is the heart of <code>Foldable</code>. It says: “give me a way to turn each element into a Monoid, and I will combine them all for you”. And since <code>foldMap</code> alone is enough to define a complete <code>Foldable</code> instance, we can confidently say:</p>
<blockquote>
<p><strong>Foldable is just the typeclass that lets you <code>foldMap</code> over a structure!</strong></p>
</blockquote>
<p>Which, if you think about it, is just a fancy way of saying: “I can visit all the elements and combine them”. Simple, powerful, and beautiful. ✨</p>
<h2 id="acknowledgements">Acknowledgements</h2>
<p>Hope you learned something about <code>Foldable</code> and <code>scanl</code> today! As usual, these concepts are things you already use in Elm every day, we are just giving them a proper name. 😉</p>
<p>If you found joy in this blogpost and would like me to continue the series (next up would be… <code>Traversable</code>!), please consider <a href="https://github.com/sponsors/kutyel">sponsoring my work</a>, share it in your social networks and <strong>follow me on <a href="https://twitter.com/FlavioCorpa">Twitter</a>/<a href="https://bsky.app/profile/flaviocorpa.com">BlueSky!</a> 🦋</strong> 🙌🏻</p></section>
  </article>
</main>

 <footer class="py-14 bg-[var(--footerBgColor)] shrink-0">
  <div class="relative mx-auto md:w-[600px] w-auto px-[1.3125rem]">
    <ul class="flex justify-center list-none" role="list">
      <li class="mx-3" role="listitem">
        <a href="/">Home</a>
      </li>
      <li class="mx-3" role="listitem">
        <a href="https://github.com/sponsors/kutyel/">Sponsor me</a>
      </li>
      <li class="mx-3" role="listitem">
        <a href="/atom.xml">RSS</a>
      </li>
    </ul>
  </div>
</footer>


<script src="https://gistcdn.githack.com/kutyel/41d12e099484fd390fb67168271fcdd9/raw/9be26e500525a2e4edacc53d3a8006aaddec0e15/bsky-comments.js"></script>
]]></description>
    <pubDate>Fri, 13 Feb 2026 14:00:00 UT</pubDate>
    <guid>https://flaviocorpa.com/haskell-for-elm-developers-giving-names-to-stuff-part-6-foldable.html</guid>
    <dc:creator>Flavio Corpa</dc:creator>
</item>
<item>
    <title>Japan Prefectures Quiz: building a browser memory game with Elm</title>
    <link>https://flaviocorpa.com/japan-prefectures-quiz-building-a-browser-memory-game-with-elm.html</link>
    <description><![CDATA[<nav class="my-6 py-2">
  <div class="relative mx-auto md:w-[600px] w-auto px-[1.3125rem] md:px-0" data-nav-wrap>
    <a class="mr-5 absolute left-[-10000px] focus:static focus:left-auto" href="#content"
      >Skip to content</a
    >
    <a class="mr-5" href="/">Home</a>
    <a class="mr-5" href="https://github.com/sponsors/kutyel">Sponsor me</a>
    <a class="mr-5" href="/atom.xml">RSS</a>
  </div>
</nav>


<style>
  bsky-comments {
    --background-color: var(--bgColor);
    --text-color: var(--textColor);
    --link-color: var(--textLinkColor);
    --link-hover-color: var(--textLinkHoverColor);
    --comment-meta-color: #888;
    --error-color: #ff4d4d;
    --reply-border-color: var(--separatorColor);
    --button-background-color: var(--btnBgColor);
    --button-hover-background-color: rgba(var(--btnBgColor), 0.2);
    --author-avatar-border-radius: 50%;
  }
</style>

<main class="flex-1" id="content" tabindex="-1">
  <article class="pb-10">
    <header class="bg-[var(--headerBgColor)] mb-8 px-[1.3125rem] md:px-0 py-4 md:py-8">
      <div class="mx-auto md:w-[600px]">
        <h1 class="text-[1.7rem] md:text-[3rem] m-0 mb-4 font-normal leading-[1.2] text-[var(--h1Color)]">
          Japan Prefectures Quiz: building a browser memory game with Elm
        </h1>
        <div class="mx-auto md:w-[600px]">
          <small class="italic">05/11/2025</small>
          <small class="italic"> | 6 min read</small>
          
          <small class="italic"> (updated: 16/12/2025 15:10)</small>
          
          <div class="mt-2">[ <a title="All pages tagged &#39;games&#39;." href="/tags/games.html" rel="tag">games</a>, <a title="All pages tagged &#39;elm&#39;." href="/tags/elm.html" rel="tag">elm</a>, <a title="All pages tagged &#39;fp&#39;." href="/tags/fp.html" rel="tag">fp</a>, <a title="All pages tagged &#39;web&#39;." href="/tags/web.html" rel="tag">web</a>, <a title="All pages tagged &#39;frontend&#39;." href="/tags/frontend.html" rel="tag">frontend</a> ]</div>
        </div>
      </div>
    </header>
    <section class="mx-auto md:w-[600px] px-[1.3125rem] md:px-0"><p><img src="./images/japan.png" alt="logo" width="500px"></p>
<p>After going on a holiday with my wife’s cousin and her sons, I decided to build a few games to memorize things I’ve always wanted to know by heart, namely: the <a href="https://elm-countries-quiz.netlify.app/">flags of the world</a>, the prefectures of <a href="https://elm-japan.netlify.app/">Japan</a>, and the provinces of <a href="https://elm-spain.vercel.app/">Spain</a>. So I decided to build a game with Elm and what I learnt along the way is what I’ll be describing in this blogpost, although all games follow a very similar structure.</p>
<h2 id="the-types">The Types</h2>
<p>The whole code for the Japan prefectures game can be found <a href="https://github.com/kutyel/elm-japan-prefectures-quiz">here</a>, it’s completely Open Source! The first thing I wanted to do is define the model of the game:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">Model</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>    <span class="op">=</span> <span class="dt">Idle</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>    <span class="op">|</span> <span class="dt">Playing</span> <span class="dt">GameState</span> (<span class="dt">Toast</span><span class="op">.</span><span class="dt">Tray</span> <span class="dt">Toast</span>)</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">|</span> <span class="dt">Finished</span> <span class="dt">Score</span> (<span class="dt">Toast</span><span class="op">.</span><span class="dt">Tray</span> <span class="dt">Toast</span>)</span></code></pre></div>
<p>One benefit of working with <strong>Algebraic Data Types</strong> (ADT for short), is that you can define really nicely the minimal representation of data you want to have for your whole domain. In the above type, the game only has 3 phases: idle (the initial screen, where you select the game mode you want to play), the game state while you are actually playing and the finished state, where you just want to show the score to the user and maybe, the last toast message telling them wether their last guess was right or wrong.</p>
<p>Let me introduce you now to the <code>Msg</code> type of the game:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">Msg</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>    <span class="op">=</span> <span class="dt">Start</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>    <span class="op">|</span> <span class="dt">Restart</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">|</span> <span class="dt">ToastMsg</span> <span class="dt">Toast</span><span class="op">.</span><span class="dt">Msg</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">|</span> <span class="dt">OnInput</span> <span class="dt">GameState</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">|</span> <span class="dt">CheckAnswer</span> <span class="dt">GameState</span> (<span class="dt">Toast</span><span class="op">.</span><span class="dt">Tray</span> <span class="dt">Toast</span>)</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">|</span> <span class="dt">RandomPrefecture</span> <span class="dt">Score</span> (<span class="dt">List</span> <span class="dt">Prefecture</span>)</span></code></pre></div>
<p>This represents all the possible actions that can happen in your app, as you can see, there is one message that we need to display toast messages (<code>ToastMsg</code>), two others that need the <code>GameState</code> (<code>OnInput</code> and <code>CheckAnswer</code>) and the most important one of them: the one I use to generate the random list of prefectures to ask in the game: <code>RandomPrefecture</code>.</p>
<p>For reference, the important <code>GameState</code> type is defined as follows:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="kw">alias</span> <span class="dt">GameState</span> <span class="op">=</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>    { <span class="fu">currentPrefecture</span> : <span class="dt">Prefecture</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>    <span class="op">,</span> <span class="fu">remainingPrefectures</span> : <span class="dt">List</span> <span class="dt">Prefecture</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">,</span> <span class="fu">guessedPrefectures</span> : <span class="dt">List</span> <span class="dt">Prefecture</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">,</span> <span class="fu">score</span> : <span class="dt">Score</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">,</span> <span class="fu">guess</span> : <span class="dt">String</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>    }</span></code></pre></div>
<p>This was only the initial design, later we will discuss how it was greatly improved using a different data structure!</p>
<h2 id="dealing-with-randomness">Dealing with Randomness</h2>
<p>As you already know, dealing with random values is a side effect, and Elm, being a purely functional programming language, does not like those, but we have our way of purely handling that, this was my first implementation:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Start</span> <span class="op">-&gt;</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>        <span class="fu">prefectureGenerator</span> : <span class="dt">Random</span><span class="op">.</span><span class="dt">Generator</span> ( <span class="dt">Maybe</span> <span class="dt">Prefecture</span><span class="op">,</span> <span class="dt">List</span> <span class="dt">Prefecture</span> )</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>        <span class="fu">prefectureGenerator</span> <span class="op">=</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>            <span class="dt">Random</span><span class="op">.</span><span class="dt">List</span><span class="op">.</span><span class="fu">choose</span> <span class="fu">allPrefectures</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">in</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>    ( <span class="fu">model</span><span class="op">,</span> <span class="dt">Random</span><span class="op">.</span><span class="fu">generate</span> (<span class="dt">RandomPrefecture</span> (<span class="dt">Score</span> <span class="dv">0</span> <span class="dv">0</span>)) <span class="fu">prefectureGenerator</span> )</span></code></pre></div>
<p>I used the <a href="https://package.elm-lang.org/packages/elm-community/random-extra/latest/Random-List#choose"><code>choose</code></a> function from the <code>random-extra</code> package, which has the following signature:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="fu">choose</span> : <span class="dt">List</span> <span class="fu">a</span> <span class="op">-&gt;</span> <span class="dt">Generator</span> ( <span class="dt">Maybe</span> <span class="fu">a</span><span class="op">,</span> <span class="dt">List</span> <span class="fu">a</span> )</span></code></pre></div>
<p>And the logic was quite simple: every time I ask a user for a prefecture, I would just <em>choose</em> it from the list, and this function already extracts it from the remaining of the list. The Maybe in the first half of the tuple <code>( Maybe Prefecture , List Prefecture )</code> means that if the chosen option is a <code>Nothing</code>, you run out of options and you can finish the game. What was the downside of this approach? I needed to perform <strong>N number of side effects</strong>, where N is the length of the list of things I want to memorize in the game. Is there a cleaner way?</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Start</span> <span class="op">-&gt;</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>        <span class="fu">prefectureGenerator</span> : <span class="dt">Random</span><span class="op">.</span><span class="dt">Generator</span> (<span class="dt">List</span> <span class="dt">Prefecture</span>)</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>        <span class="fu">prefectureGenerator</span> <span class="op">=</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>            <span class="co">-- the whole game revolves around this!</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>            <span class="dt">Random</span><span class="op">.</span><span class="dt">List</span><span class="op">.</span><span class="fu">shuffle</span> <span class="fu">allPrefectures</span></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">in</span></span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a>    ( <span class="fu">model</span><span class="op">,</span> <span class="dt">Random</span><span class="op">.</span><span class="fu">generate</span> (<span class="dt">RandomPrefecture</span> (<span class="dt">Score</span> <span class="dv">0</span> <span class="dv">0</span>)) <span class="fu">prefectureGenerator</span> )</span></code></pre></div>
<p>Yes, following the game logic, I just need to scrumble the list <strong>once</strong>! And therefore, I can just use the <a href="https://package.elm-lang.org/packages/elm-community/random-extra/latest/Random-List#shuffle"><code>shuffle</code></a> function from the same package and, since a List in Elm is simply a Linked List, I can <code>List.head</code> every item from the remaining list of prefectures in the game until I run out of options, a nice improvement!</p>
<h2 id="enter-the-zipper-zipper_mouth_face">Enter the Zipper! 🤐</h2>
<p>Conceptually, you might have noticed that the above <code>GameState</code> type seems a bit redundant: if we need to keep track of a list of guessed, not yet guessed, and current asked prefecture, do we have a better data structure that represents that? 🤔</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">Zipper</span> <span class="fu">a</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>    <span class="op">=</span> <span class="dt">Zipper</span> (<span class="dt">List</span> <span class="fu">a</span>) <span class="fu">a</span> (<span class="dt">List</span> <span class="fu">a</span>)</span></code></pre></div>
<p>Indeed, the structure I really want is a <a href="https://package.elm-lang.org/packages/wernerdegroot/listzipper/4.0.0/">Zipper</a>! A zipper always has a focused item, a List before and after that, so this represents really nicely what I wanted to acomplish:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="kw">alias</span> <span class="dt">GameState</span> <span class="op">=</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>    { <span class="fu">prefectures</span> : <span class="dt">Zipper</span> <span class="dt">Prefecture</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>    <span class="op">,</span> <span class="fu">score</span> : <span class="dt">Score</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">,</span> <span class="fu">guess</span> : <span class="dt">String</span></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a>    }</span></code></pre></div>
<p>A few changes I had to do to the logic of the game were, first in the way I initialize the game state:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="dt">RandomPrefecture</span> <span class="fu">score</span> (<span class="fu">p</span> <span class="op">::</span> <span class="fu">ps</span>) <span class="op">-&gt;</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>    ( <span class="dt">Playing</span> (<span class="dt">GameState</span> (<span class="dt">Zipper</span><span class="op">.</span><span class="fu">fromCons</span> <span class="fu">p</span> <span class="fu">ps</span>) <span class="fu">score</span> <span class="st">&quot;&quot;</span>) <span class="fu">emptyTray</span><span class="op">,</span> <span class="dt">Cmd</span><span class="op">.</span><span class="fu">none</span> )</span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a><span class="dt">RandomPrefecture</span> <span class="fu">score</span> [] <span class="op">-&gt;</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>    ( <span class="dt">Finished</span> <span class="fu">score</span> <span class="fu">emptyTray</span><span class="op">,</span> <span class="dt">Cmd</span><span class="op">.</span><span class="fu">none</span> )</span></code></pre></div>
<p>As you can see, since <strong>pattern matching</strong> is the way we do everything in Elm, I can construct nicely my first zipper when I come back from the random shuffle function by just using <code>Zipper.fromCons</code>.</p>
<p>And then the update function after we guess every prefecture in the game:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a>( <span class="cf">case</span> <span class="dt">Zipper</span><span class="op">.</span><span class="fu">next</span> <span class="fu">updatedCurrentPrefecture</span> <span class="cf">of</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Just</span> <span class="fu">remainingPrefectures</span> <span class="op">-&gt;</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Playing</span> (<span class="dt">GameState</span> <span class="fu">remainingPrefectures</span> <span class="fu">updatedGameScore</span> <span class="st">&quot;&quot;</span>) <span class="fu">tray</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Nothing</span> <span class="op">-&gt;</span></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a>        <span class="co">-- if there is no Zipper.next, the game is over!</span></span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Finished</span> <span class="fu">updatedGameScore</span> <span class="fu">tray</span></span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a><span class="op">,</span> <span class="dt">Cmd</span><span class="op">.</span><span class="fu">none</span> )</span></code></pre></div>
<p>Every time we guess a prefecture, we move to the <code>next</code>, and if that operation fails, it means we have finished the game!</p>
<h2 id="separation-of-concerns">Separation of concerns</h2>
<p>I added a few unit tests to my game, and I ended up with the following code:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="fu">all</span> : <span class="dt">Test</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="fu">all</span> <span class="op">=</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>    <span class="fu">describe</span> <span class="st">&quot;getPrefectureStatus tests&quot;</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>        [ <span class="fu">test</span> <span class="st">&quot;current prefecture is focused -&gt; color Focused&quot;</span> <span class="op">&lt;|</span></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>            \<span class="fu">_</span> <span class="op">-&gt;</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>                <span class="kw">let</span></span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a>                    <span class="fu">zipper</span> : <span class="dt">Zipper</span> <span class="dt">Prefecture</span></span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a>                    <span class="fu">zipper</span> <span class="op">=</span></span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a>                        <span class="dt">Zipper</span><span class="op">.</span><span class="fu">singleton</span> <span class="fu">aomori</span></span>
<span id="cb11-10"><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-11"><a href="#cb11-11" aria-hidden="true" tabindex="-1"></a>                    <span class="fu">expectedStyles</span> : <span class="dt">List</span> (<span class="dt">Svg</span><span class="op">.</span><span class="dt">Attribute</span> <span class="fu">msg</span>)</span>
<span id="cb11-12"><a href="#cb11-12" aria-hidden="true" tabindex="-1"></a>                    <span class="fu">expectedStyles</span> <span class="op">=</span></span>
<span id="cb11-13"><a href="#cb11-13" aria-hidden="true" tabindex="-1"></a>                        <span class="co">-- this is bad!! 🤢</span></span>
<span id="cb11-14"><a href="#cb11-14" aria-hidden="true" tabindex="-1"></a>                        [ <span class="dt">SvgAttr</span><span class="op">.</span><span class="fu">fill</span> <span class="st">&quot;#422ad5&quot;</span></span>
<span id="cb11-15"><a href="#cb11-15" aria-hidden="true" tabindex="-1"></a>                        <span class="op">,</span> <span class="dt">SvgAttr</span><span class="op">.</span><span class="fu">class</span> <span class="st">&quot;animate-pulse&quot;</span></span>
<span id="cb11-16"><a href="#cb11-16" aria-hidden="true" tabindex="-1"></a>                        ]</span>
<span id="cb11-17"><a href="#cb11-17" aria-hidden="true" tabindex="-1"></a>                <span class="kw">in</span></span>
<span id="cb11-18"><a href="#cb11-18" aria-hidden="true" tabindex="-1"></a>                <span class="dt">Expect</span><span class="op">.</span><span class="fu">equal</span> <span class="fu">expectedStyles</span> (<span class="fu">getPrefectureStatus</span> <span class="dv">2</span> <span class="fu">zipper</span>)</span>
<span id="cb11-19"><a href="#cb11-19" aria-hidden="true" tabindex="-1"></a>        <span class="op">,</span> <span class="fu">test</span> <span class="st">&quot;prefecture not yet asked -&gt; color NotAsked&quot;</span> <span class="op">&lt;|</span></span>
<span id="cb11-20"><a href="#cb11-20" aria-hidden="true" tabindex="-1"></a>        <span class="co">-- ... more tests</span></span>
<span id="cb11-21"><a href="#cb11-21" aria-hidden="true" tabindex="-1"></a>        ]</span></code></pre></div>
<p>What was wrong with this code? Well, I was <strong>mixing</strong> visual representation of the game with the actual game logic, so, I needed to rewrite my functions to make my life easier for myself:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="fu">fillColor</span> : <span class="dt">Int</span> <span class="op">-&gt;</span> <span class="dt">Zipper</span> <span class="dt">Prefecture</span> <span class="op">-&gt;</span> <span class="dt">List</span> (<span class="dt">Svg</span><span class="op">.</span><span class="dt">Attribute</span> <span class="fu">msg</span>)</span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a><span class="fu">fillColor</span> <span class="fu">id</span> <span class="op">=</span></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>    <span class="fu">getPrefectureStatus</span> <span class="fu">id</span> <span class="op">&gt;&gt;</span> <span class="fu">statusToColor</span></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a><span class="fu">getPrefectureStatus</span> : <span class="dt">Int</span> <span class="op">-&gt;</span> <span class="dt">Zipper</span> <span class="dt">Prefecture</span> <span class="op">-&gt;</span> <span class="dt">Status</span></span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a><span class="fu">getPrefectureStatus</span> <span class="fu">id</span> <span class="fu">zipper</span> <span class="op">=</span></span>
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- implementation of this function is not relevant now...</span></span></code></pre></div>
<p>And the nicer resulting code looks now like this:</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="fu">all</span> : <span class="dt">Test</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="fu">all</span> <span class="op">=</span></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a>    <span class="fu">describe</span> <span class="st">&quot;getPrefectureStatus tests&quot;</span></span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>        [ <span class="fu">test</span> <span class="st">&quot;current prefecture is focused -&gt; Focused state&quot;</span> <span class="op">&lt;|</span></span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a>            \<span class="fu">_</span> <span class="op">-&gt;</span></span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a>                <span class="kw">let</span></span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a>                    <span class="fu">zipper</span> : <span class="dt">Zipper</span> <span class="dt">Prefecture</span></span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a>                    <span class="fu">zipper</span> <span class="op">=</span></span>
<span id="cb13-9"><a href="#cb13-9" aria-hidden="true" tabindex="-1"></a>                        <span class="dt">Zipper</span><span class="op">.</span><span class="fu">singleton</span> <span class="fu">aomori</span></span>
<span id="cb13-10"><a href="#cb13-10" aria-hidden="true" tabindex="-1"></a>                <span class="kw">in</span></span>
<span id="cb13-11"><a href="#cb13-11" aria-hidden="true" tabindex="-1"></a>                <span class="dt">Expect</span><span class="op">.</span><span class="fu">equal</span> <span class="dt">Focused</span> (<span class="fu">getPrefectureStatus</span> <span class="dv">2</span> <span class="fu">zipper</span>)</span>
<span id="cb13-12"><a href="#cb13-12" aria-hidden="true" tabindex="-1"></a>        <span class="op">,</span> <span class="fu">test</span> <span class="st">&quot;prefecture not yet asked -&gt; NotAsked state&quot;</span> <span class="op">&lt;|</span></span>
<span id="cb13-13"><a href="#cb13-13" aria-hidden="true" tabindex="-1"></a>        <span class="co">-- ... more tests</span></span>
<span id="cb13-14"><a href="#cb13-14" aria-hidden="true" tabindex="-1"></a>        ]</span></code></pre></div>
<p>One nice implication of using functional languages, is that all the functions are pure, which means for every input I can <strong>always</strong> guarantee the same output, and that makes unit testing a breeze! ✨</p>
<h2 id="the-ci-setup">The CI Setup</h2>
<p>I have been learning Nix ❄️ recently for my Haskell development, so I wanted to use Nix too for my Elm needs. I updated my <a href="https://github.com/kutyel/elm-parcel-template">elm-parcel-template</a> to now use Nix and, as a nice side effect, I have a <strong>FREE, ZERO CONFIG CI</strong> thanks to <a href="https://nix-ci.com/">nix-ci.com</a> (it figures out automagically what it needs to do based on your <code>flake.nix</code> file, no extra config needed! ✨), check it out if you are interested, it is a really nice project!</p>
<h2 id="acknowledgements">Acknowledgements</h2>
<p>I would like to thank a few people who helped me improve a few things in these games, namely:</p>
<ul>
<li><a href="https://github.com/AitorSoto">Aitor Soto</a> for making the game actually <a href="https://github.com/kutyel/elm-countries-quiz/pull/1">playable</a> and nice! 🙇🏼‍♂️</li>
<li><a href="https://github.com/r-k-b">Robert K. Bell</a> from the Elm Slack for his help <a href="https://github.com/kutyel/elm-japan-prefectures-quiz/pull/1">setting up Nix</a> + Elm 🌳❤️</li>
<li><a href="https://x.com/kerckhove_ts">Tom Sydney Kerckhove</a>, for creating the awesome Nix CI! 🙌🏻</li>
</ul>
<p>If you liked this blogpost and would like me to continue writing technical content, please consider <a href="https://github.com/sponsors/kutyel">sponsoring my work</a>, share it in your social networks and <strong>follow me on <a href="https://twitter.com/FlavioCorpa">Twitter</a> and <a href="https://bsky.app/profile/flaviocorpa.com">BlueSky 🦋</a>!</strong> 🙌🏻</p></section>
  </article>
</main>


<bsky-comments post="at://did:plc:dvrocvv5szl2evqiafsx4iyw/app.bsky.feed.post/3m4j72dng6k2u"></bsky-comments>
 <footer class="py-14 bg-[var(--footerBgColor)] shrink-0">
  <div class="relative mx-auto md:w-[600px] w-auto px-[1.3125rem]">
    <ul class="flex justify-center list-none" role="list">
      <li class="mx-3" role="listitem">
        <a href="/">Home</a>
      </li>
      <li class="mx-3" role="listitem">
        <a href="https://github.com/sponsors/kutyel/">Sponsor me</a>
      </li>
      <li class="mx-3" role="listitem">
        <a href="/atom.xml">RSS</a>
      </li>
    </ul>
  </div>
</footer>


<script src="https://gistcdn.githack.com/kutyel/41d12e099484fd390fb67168271fcdd9/raw/9be26e500525a2e4edacc53d3a8006aaddec0e15/bsky-comments.js"></script>
]]></description>
    <pubDate>Wed, 05 Nov 2025 15:00:00 UT</pubDate>
    <guid>https://flaviocorpa.com/japan-prefectures-quiz-building-a-browser-memory-game-with-elm.html</guid>
    <dc:creator>Flavio Corpa</dc:creator>
</item>
<item>
    <title>How to add estimated reading time to your Hakyll blog</title>
    <link>https://flaviocorpa.com/how-to-add-estimated-reading-time-to-your-hakyll-blog.html</link>
    <description><![CDATA[<nav class="my-6 py-2">
  <div class="relative mx-auto md:w-[600px] w-auto px-[1.3125rem] md:px-0" data-nav-wrap>
    <a class="mr-5 absolute left-[-10000px] focus:static focus:left-auto" href="#content"
      >Skip to content</a
    >
    <a class="mr-5" href="/">Home</a>
    <a class="mr-5" href="https://github.com/sponsors/kutyel">Sponsor me</a>
    <a class="mr-5" href="/atom.xml">RSS</a>
  </div>
</nav>


<style>
  bsky-comments {
    --background-color: var(--bgColor);
    --text-color: var(--textColor);
    --link-color: var(--textLinkColor);
    --link-hover-color: var(--textLinkHoverColor);
    --comment-meta-color: #888;
    --error-color: #ff4d4d;
    --reply-border-color: var(--separatorColor);
    --button-background-color: var(--btnBgColor);
    --button-hover-background-color: rgba(var(--btnBgColor), 0.2);
    --author-avatar-border-radius: 50%;
  }
</style>

<main class="flex-1" id="content" tabindex="-1">
  <article class="pb-10">
    <header class="bg-[var(--headerBgColor)] mb-8 px-[1.3125rem] md:px-0 py-4 md:py-8">
      <div class="mx-auto md:w-[600px]">
        <h1 class="text-[1.7rem] md:text-[3rem] m-0 mb-4 font-normal leading-[1.2] text-[var(--h1Color)]">
          How to add estimated reading time to your Hakyll blog
        </h1>
        <div class="mx-auto md:w-[600px]">
          <small class="italic">16/09/2025</small>
          <small class="italic"> | 1 min read</small>
          
          <div class="mt-2">[ <a title="All pages tagged &#39;haskell&#39;." href="/tags/haskell.html" rel="tag">haskell</a>, <a title="All pages tagged &#39;fp&#39;." href="/tags/fp.html" rel="tag">fp</a>, <a title="All pages tagged &#39;hakyll&#39;." href="/tags/hakyll.html" rel="tag">hakyll</a>, <a title="All pages tagged &#39;web&#39;." href="/tags/web.html" rel="tag">web</a> ]</div>
        </div>
      </div>
    </header>
    <section class="mx-auto md:w-[600px] px-[1.3125rem] md:px-0"><p>A while ago, I decided it was time to start blogging again, and I used <a href="https://robertwpearce.com/">Robert Pearce</a>’s excellent <a href="https://robertwpearce.com/the-hakyll-nix-template-tutorial.html">hakyll-nix-template</a> to bootstrap this blog and as a way to learn <a href="https://jaspervdj.be/hakyll/">Hakyll</a> and <a href="https://nix.dev/tutorials/nix-language.html">Nix</a> a little bit better. If it is your personal blog after all, you can use whatever you want, right? 😉</p>
<p>If you also use Hakyll, you might have wondered how can we calculate the estimated reading time for each post in a simple way, so here is the Haskell code:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ot">readingTimeField ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Context</span> <span class="dt">String</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>readingTimeField key <span class="ot">=</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>  field key calculate</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="ot">    calculate ::</span> <span class="dt">Item</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Compiler</span> <span class="dt">String</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>    calculate <span class="ot">=</span> <span class="fu">pure</span> <span class="op">.</span> withTagList acc <span class="op">.</span> itemBody</span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>    acc ts <span class="ot">=</span> [<span class="dt">TagText</span> <span class="op">.</span> <span class="fu">show</span> <span class="op">$</span> time ts]</span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- M. Brysbaert, Journal of Memory and Language (2009) vol 109.</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- DOI: 10.1016/j.jml.2019.104047</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>    time ts <span class="ot">=</span> <span class="fu">foldr</span> count <span class="dv">0</span> ts <span class="ot">`div`</span> <span class="dv">238</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>    count (<span class="dt">TagText</span> s) n <span class="ot">=</span> n <span class="op">+</span> <span class="fu">length</span> (<span class="fu">words</span> s)</span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a>    count _ n <span class="ot">=</span> n</span></code></pre></div>
<p>What’s funny about the above implementation is that I found an actual research <a href="https://www.sciencedirect.com/science/article/abs/pii/S0749596X19300786">paper</a> that tells us the average reading speed for adults and non-fiction, so I did not have to guess it!</p>
<blockquote>
<p>This is the actual code I’m using in my blog, you can have a look at the whole codebase <a href="https://github.com/kutyel/kutyel-hakyll">here</a>, its Open Source! 🕊️</p>
</blockquote>
<p>After creating the <code>readingTimeField</code> function, you can use it in your <code>postCtx</code> like this:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="ot">postCtx ::</span> <span class="dt">Context</span> <span class="dt">String</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>postCtx <span class="ot">=</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>  constField <span class="st">&quot;root&quot;</span> mySiteRoot</span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">&lt;&gt;</span> constField <span class="st">&quot;siteName&quot;</span> mySiteName</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">&lt;&gt;</span> dateField <span class="st">&quot;date&quot;</span> <span class="st">&quot;%d/%m/%Y&quot;</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">&lt;&gt;</span> readingTimeField <span class="st">&quot;readingtime&quot;</span> <span class="co">-- this is the new addition</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">&lt;&gt;</span> defaultContext</span></code></pre></div>
<p>And finally, you can use it in your templates like this:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode html"><code class="sourceCode html"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="dt">&lt;</span><span class="kw">div</span><span class="ot"> class</span><span class="op">=</span><span class="st">&quot;info&quot;</span><span class="dt">&gt;</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>  <span class="dt">&lt;</span><span class="kw">small</span><span class="ot"> class</span><span class="op">=</span><span class="st">&quot;italic&quot;</span><span class="dt">&gt;</span>$date$<span class="dt">&lt;/</span><span class="kw">small</span><span class="dt">&gt;</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>  <span class="dt">&lt;</span><span class="kw">small</span><span class="ot"> class</span><span class="op">=</span><span class="st">&quot;italic&quot;</span><span class="dt">&gt;</span> | $readingtime$ min read<span class="dt">&lt;/</span><span class="kw">small</span><span class="dt">&gt;</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>  <span class="co">&lt;!-- ... --&gt;</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="dt">&lt;/</span><span class="kw">div</span><span class="dt">&gt;</span></span></code></pre></div>
<p>It is as simple as it gets, the end result looks like this:</p>
<p><img src="./images/ert.png" alt="My frist Elm and Haskell blogpost showing an estimate of 6 min read" width="500px"></p>
<p>Hope this was useful for you too! If you have any questions, feel free to reach out to me on <a href="https://twitter.com/FlavioCorpa">Twitter</a> or <a href="https://bsky.app/profile/flaviocorpa.com">BlueSky</a> 🦋.</p></section>
  </article>
</main>

 <footer class="py-14 bg-[var(--footerBgColor)] shrink-0">
  <div class="relative mx-auto md:w-[600px] w-auto px-[1.3125rem]">
    <ul class="flex justify-center list-none" role="list">
      <li class="mx-3" role="listitem">
        <a href="/">Home</a>
      </li>
      <li class="mx-3" role="listitem">
        <a href="https://github.com/sponsors/kutyel/">Sponsor me</a>
      </li>
      <li class="mx-3" role="listitem">
        <a href="/atom.xml">RSS</a>
      </li>
    </ul>
  </div>
</footer>


<script src="https://gistcdn.githack.com/kutyel/41d12e099484fd390fb67168271fcdd9/raw/9be26e500525a2e4edacc53d3a8006aaddec0e15/bsky-comments.js"></script>
]]></description>
    <pubDate>Tue, 16 Sep 2025 15:01:00 UT</pubDate>
    <guid>https://flaviocorpa.com/how-to-add-estimated-reading-time-to-your-hakyll-blog.html</guid>
    <dc:creator>Flavio Corpa</dc:creator>
</item>
<item>
    <title>Building a non-trivial app with Elm and with Svelte</title>
    <link>https://flaviocorpa.com/building-a-non-trivial-app-with-elm-and-with-svelte.html</link>
    <description><![CDATA[<nav class="my-6 py-2">
  <div class="relative mx-auto md:w-[600px] w-auto px-[1.3125rem] md:px-0" data-nav-wrap>
    <a class="mr-5 absolute left-[-10000px] focus:static focus:left-auto" href="#content"
      >Skip to content</a
    >
    <a class="mr-5" href="/">Home</a>
    <a class="mr-5" href="https://github.com/sponsors/kutyel">Sponsor me</a>
    <a class="mr-5" href="/atom.xml">RSS</a>
  </div>
</nav>


<style>
  bsky-comments {
    --background-color: var(--bgColor);
    --text-color: var(--textColor);
    --link-color: var(--textLinkColor);
    --link-hover-color: var(--textLinkHoverColor);
    --comment-meta-color: #888;
    --error-color: #ff4d4d;
    --reply-border-color: var(--separatorColor);
    --button-background-color: var(--btnBgColor);
    --button-hover-background-color: rgba(var(--btnBgColor), 0.2);
    --author-avatar-border-radius: 50%;
  }
</style>

<main class="flex-1" id="content" tabindex="-1">
  <article class="pb-10">
    <header class="bg-[var(--headerBgColor)] mb-8 px-[1.3125rem] md:px-0 py-4 md:py-8">
      <div class="mx-auto md:w-[600px]">
        <h1 class="text-[1.7rem] md:text-[3rem] m-0 mb-4 font-normal leading-[1.2] text-[var(--h1Color)]">
          Building a non-trivial app with Elm and with Svelte
        </h1>
        <div class="mx-auto md:w-[600px]">
          <small class="italic">04/06/2025</small>
          <small class="italic"> | 11 min read</small>
          
          <div class="mt-2">[ <a title="All pages tagged &#39;frontend&#39;." href="/tags/frontend.html" rel="tag">frontend</a>, <a title="All pages tagged &#39;svelte&#39;." href="/tags/svelte.html" rel="tag">svelte</a>, <a title="All pages tagged &#39;elm&#39;." href="/tags/elm.html" rel="tag">elm</a>, <a title="All pages tagged &#39;fp&#39;." href="/tags/fp.html" rel="tag">fp</a>, <a title="All pages tagged &#39;web&#39;." href="/tags/web.html" rel="tag">web</a> ]</div>
        </div>
      </div>
    </header>
    <section class="mx-auto md:w-[600px] px-[1.3125rem] md:px-0"><p><img src="./images/elm-vs-svelte.png" alt="elm-vs-svelte" width="500px"></p>
<h2 id="motivation">Motivation</h2>
<p>I recently started to volunteer by contributing to a Svelte + TypeScript codebase, and since I’m completely new to Svelte, I wanted to build something in my spare time with Svelte 5 to test it out and see how it differs from my previous frontend experiences. On my dev job I do mostly Haskell backend code nowadays but I’ve been a frontend engineer for years, and used everything in production: Backbone, React, Angular, Vue and Elm, which I’ve been happily using for the last +5 years! 🌳</p>
<h2 id="first-impressions">First impressions</h2>
<p>I think Svelte lives up to its hype, I started to learn it by just using their tutorial in the <a href="https://svelte.dev/tutorial/svelte/welcome-to-svelte">Svelte website</a>, and in a matter of only <strong>10 hours of work</strong>, I was able to reproduce a fully fledged Svelte app, with Firebase and authentication just like the one I built in Elm for my personal use 3 years ago!</p>
<p>This means two things:</p>
<ol>
<li>Svelte is incredibly easy to learn! 💃🏻</li>
<li>Svelte feels like just building HTML apps, but with magical bits ✨</li>
</ol>
<blockquote>
<p>I can’t state how happy I am of not having to type <code>className</code> ever again! 😅</p>
</blockquote>
<p>For comparison, the Elm app currently has ~900 LOC, whereas the Svelte app has <em>exactly</em> 187 LOC 🤯, divided into 120 LOC of TypeScript and 67 LOC of template (Svelte HTML). This feels amazing, but is it really a fair comparison? No, and that is why in the following sections of the blogpost I am going to describe the pros and cons of both implementations!</p>
<h2 id="firebase">Firebase</h2>
<p>My original app was just a simple calendar view in which I could mark how many chapters of a book I read a single day, so that I could build a habit to read every day. I wanted my app to live on the Cloud and to be purely frontend based. I also did not want to handle authentication, etc, so I decided to use Firebase and also try out its realtime databases.</p>
<p>For Elm, I used the <a href="https://package.elm-lang.org/packages/IzumiSy/elm-firestore/latest/Firestore">elm-firestore</a> library, which is just amazing and let’s me write completely TYPE SAFE Elm queries to interact with Firestore, here is an example of such a query:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>    <span class="fu">query</span> : <span class="dt">Query</span><span class="op">.</span><span class="dt">Query</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>    <span class="fu">query</span> <span class="op">=</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Query</span><span class="op">.</span><span class="fu">new</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>            <span class="op">|&gt;</span> <span class="dt">Query</span><span class="op">.</span><span class="fu">collection</span> <span class="st">&quot;readings&quot;</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>            <span class="op">|&gt;</span> <span class="dt">Query</span><span class="op">.</span><span class="fu">orderBy</span> <span class="st">&quot;date&quot;</span> <span class="dt">Query</span><span class="op">.</span><span class="dt">Descending</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>            <span class="op">|&gt;</span> <span class="dt">Query</span><span class="op">.</span><span class="fu">where_</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>                (<span class="dt">Query</span><span class="op">.</span><span class="fu">compositeFilter</span> <span class="dt">Query</span><span class="op">.</span><span class="dt">And</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>                    (<span class="dt">Query</span><span class="op">.</span><span class="fu">fieldFilter</span> <span class="st">&quot;date&quot;</span> <span class="dt">Query</span><span class="op">.</span><span class="dt">GreaterThanOrEqual</span> (<span class="dt">Query</span><span class="op">.</span><span class="fu">timestamp</span> <span class="op">&lt;|</span> <span class="fu">firstDayOfYear</span> <span class="fu">model</span><span class="op">.</span><span class="fu">displayYear</span>))</span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>                    [ <span class="dt">Query</span><span class="op">.</span><span class="fu">fieldFilter</span> <span class="st">&quot;date&quot;</span> <span class="dt">Query</span><span class="op">.</span><span class="dt">LessThanOrEqual</span> (<span class="dt">Query</span><span class="op">.</span><span class="fu">timestamp</span> <span class="op">&lt;|</span> <span class="fu">lastDayOfYear</span> <span class="fu">model</span><span class="op">.</span><span class="fu">displayYear</span>) ]</span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>                )</span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a><span class="kw">in</span></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a><span class="fu">model</span><span class="op">.</span><span class="fu">firestore</span></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a>    <span class="op">|&gt;</span> <span class="dt">Firestore</span><span class="op">.</span><span class="fu">root</span></span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a>    <span class="op">|&gt;</span> <span class="dt">Firestore</span><span class="op">.</span><span class="fu">collection</span> <span class="st">&quot;users&quot;</span></span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a>    <span class="op">|&gt;</span> <span class="dt">Firestore</span><span class="op">.</span><span class="fu">document</span> <span class="fu">uid</span></span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a>    <span class="op">|&gt;</span> <span class="dt">Firestore</span><span class="op">.</span><span class="fu">build</span></span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a>    <span class="op">|&gt;</span> <span class="dt">Result</span><span class="op">.</span><span class="fu">toTask</span></span>
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a>    <span class="op">|&gt;</span> <span class="dt">Task</span><span class="op">.</span><span class="fu">andThen</span> (<span class="dt">Firestore</span><span class="op">.</span><span class="fu">runQuery</span> <span class="fu">decoder</span> <span class="fu">query</span>)</span>
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a>    <span class="op">|&gt;</span> <span class="dt">Task</span><span class="op">.</span><span class="fu">attempt</span> <span class="dt">FetchChapters</span></span></code></pre></div>
<p>Working with this library is amazing and using all the power of Elm and its famous compiler error messages, it was a delight to interact with Firestore (Firebase’s document storage) in such a way. A huge part of those extra FEW hundred lines of code was needed to Decode and Encode data from/to JSON, this is a price we have to pay in Elm to be completely <strong>pure and type safe</strong> but I believe in the long run it is completely worth it.</p>
<p>However, the sad part is that since this library uses Firestore RESTful API, which is officially said to be out of support for realtime update, I could not leverage this functionality in my Elm application. 😢</p>
<p>For Svelte, I used the <a href="https://svelte-firebase-state.vercel.app/firestore/collection-state">svelte-firebase-state</a> package, and I was really impressed with it. Have a look at exactly the same query I showed you above, but in Svelte:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode typescript"><code class="sourceCode typescript"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> readings <span class="op">=</span> <span class="kw">new</span> <span class="fu">CollectionState</span><span class="op">&lt;</span>DocumentData<span class="op">,</span> Reading<span class="op">&gt;</span>({</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>  auth<span class="op">,</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>  firestore<span class="op">,</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>  listen<span class="op">:</span> <span class="kw">true</span><span class="op">,</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>  query<span class="op">:</span> () <span class="kw">=&gt;</span> [</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>    <span class="fu">where</span>(<span class="st">&#39;date&#39;</span><span class="op">,</span> <span class="st">&#39;&lt;=&#39;</span><span class="op">,</span> <span class="fu">subHours</span>(<span class="kw">new</span> <span class="fu">UTCDate</span>(selectedYear <span class="op">+</span> <span class="dv">1</span><span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">1</span>)<span class="op">,</span> <span class="dv">1</span>))<span class="op">,</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>    <span class="fu">where</span>(<span class="st">&#39;date&#39;</span><span class="op">,</span> <span class="st">&#39;&gt;=&#39;</span><span class="op">,</span> <span class="kw">new</span> <span class="fu">UTCDate</span>(selectedYear<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">1</span>))<span class="op">,</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>  ]<span class="op">,</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>  path<span class="op">:</span> (currentUser) <span class="kw">=&gt;</span> <span class="vs">`users/</span><span class="sc">${</span>currentUser<span class="op">?.</span><span class="at">uid</span><span class="sc">}</span><span class="vs">/readings`</span><span class="op">,</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>})</span></code></pre></div>
<p>What is amazing about this is that it brings with it a new reactivity model that you need to get used to, it feels intuitive and easy but you need to be aware of some footguns. For example, if I wanted to use the last read chapter as a selection for the <code>&lt;select&gt;</code> elements I had on the page, I needed to use the new <code>$effect</code> rune from Svelte 5:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode typescript"><code class="sourceCode typescript"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="fu">$effect</span>(() <span class="kw">=&gt;</span> {</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> lastRead <span class="op">=</span> readings<span class="op">?.</span><span class="at">data</span><span class="op">?.</span><span class="fu">at</span>(<span class="op">-</span><span class="dv">1</span>)</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> (lastRead) {</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>    selectedBook <span class="op">=</span> lastRead<span class="op">.</span><span class="at">book</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>    selectedChapter <span class="op">=</span> lastRead<span class="op">.</span><span class="at">chapter</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>  }</span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>})</span></code></pre></div>
<p>This is not bad per se but I know that state and derived state can go out of hand REALLY quickly, that is why I value <strong>The Elm Architecture</strong> (TEA, for short) so much, because it makes you reason about you application code and your data in a simpler, completely different way!</p>
<h2 id="elm-ui-vs-tailwindcss">elm-ui vs. Tailwindcss</h2>
<p>This section is a bit offtopic, because I love Tailwind CSS, but I also love <a href="https://package.elm-lang.org/packages/mdgriffith/elm-ui/latest/"><strong>elm-ui</strong></a>. In both applications, <em>I did not write a single line of CSS</em>, and both look great!</p>
<p>If you don’t know about <code>elm-ui</code>, I created an <a href="https://egghead.io/courses/declarative-uis-without-css-with-elm-ui-93bd?af=e68v38">Egghead tutorial</a> about it, it is an incredible way to create styles in a declarative and idiomatic way within Elm, but that it does not force you to know/understand all the ins and outs of CSS. I thoroughly recommend it! 💅🏻</p>
<p>For example, here is how simple it was to have a responsive view with elm-ui:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="cf">case</span> ( <span class="fu">device</span><span class="op">.</span><span class="fu">class</span><span class="op">,</span> <span class="fu">device</span><span class="op">.</span><span class="fu">orientation</span> ) <span class="cf">of</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>    ( <span class="dt">Phone</span><span class="op">,</span> <span class="dt">Portrait</span> ) <span class="op">-&gt;</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>        <span class="fu">column</span> [ <span class="fu">width</span> <span class="fu">fill</span><span class="op">,</span> <span class="fu">centerY</span><span class="op">,</span> <span class="fu">spacing</span> <span class="dv">10</span> ]</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>            [ <span class="fu">row</span> [ <span class="fu">spacing</span> <span class="dv">10</span><span class="op">,</span> <span class="fu">centerX</span> ] [ <span class="fu">small</span> <span class="fu">userEmail</span><span class="op">,</span> <span class="fu">viewYears</span><span class="op">,</span> <span class="fu">logOut</span> ]</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>            <span class="op">,</span> <span class="fu">row</span> [ <span class="fu">spacing</span> <span class="dv">10</span><span class="op">,</span> <span class="fu">centerX</span> ] [ <span class="fu">viewBookSelect</span><span class="op">,</span> <span class="fu">viewChapterSelect</span> ]</span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>            <span class="op">,</span> <span class="fu">row</span> [ <span class="fu">spacing</span> <span class="dv">10</span><span class="op">,</span> <span class="fu">centerX</span> ] [ <span class="fu">viewDatePicker</span><span class="op">,</span> <span class="fu">viewBtn</span> ]</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>            <span class="op">,</span> <span class="fu">el</span> [ <span class="fu">centerX</span><span class="op">,</span> <span class="fu">width</span> (<span class="fu">px</span> <span class="dv">400</span>)<span class="op">,</span> <span class="fu">height</span> (<span class="fu">px</span> <span class="dv">200</span>)<span class="op">,</span> <span class="fu">scrollbarX</span> ] <span class="fu">node</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>            ]</span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>    <span class="fu">_</span> <span class="op">-&gt;</span> <span class="co">-- other views</span></span></code></pre></div>
<p>At work, we use Tailwind CSS with Elm, and for this Svelte app, I decided to use <a href="https://svelte.dev/tutorial/kit/introducing-sveltekit">SvelteKit</a>, since it seems to be the standard for building Svelte apps, and its Tailwind CSS support is amazing, I had to do very little tweaking to have it working, JavaScript tooling has really improved in the last years! 🙌🏻</p>
<h2 id="elm-charts-vs-google-web-components">elm-charts vs. google-web-components</h2>
<p>The crown jewel of this small application is, without a doubt, it’s calendar component. On its original version, I also decided to use the <a href="https://www.webcomponents.org/element/@google-web-components/google-chart">Google Calendar web component</a> for simplicity, since I wanted to see little squares for each day I read, just like we do in our Github contributions graph. Here’s how it looks:</p>
<p><img src="./images/google-chart.png" alt="google-chart" width="650px"></p>
<p>Even though Svelte has excellent support for Web Components, I stumbled upon a very weird and not very well documented issue, you need this code to make pretty much any Web Component to work within Svelte:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode typescript"><code class="sourceCode typescript"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="fu">onMount</span>(<span class="kw">async</span> () <span class="kw">=&gt;</span> {</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>  <span class="cf">await</span> <span class="im">import</span>(<span class="st">&#39;@google-web-components/google-chart&#39;</span>)</span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>})</span></code></pre></div>
<p>That took a shameful amount of time to figure out and I felt really stupid. 😢</p>
<p>Elm <em>also</em> has excellent support for Web Components, but after Google breaking its library a few times while updating dependencies (I know, right 😅), I decided for the Elm app to get rid of it and try out <a href="https://www.elm-charts.org/">elm-charts</a> instead.</p>
<p>This is also not a fair comparison, and a few extra hundred of lines of Elm code come by building the calendar chart by hand, similar to a heatmap. <a href="https://www.elm-charts.org/">elm-charts</a> is like the analog of D3.js but for Elm, it is a beautiful library and very potent! 🚀</p>
<p>Here is what the end result looked like:</p>
<p><img src="./images/elm-chart.png" alt="elm-chart" width="650px"></p>
<p>As you can see, it looks pretty similar, but you have <em>fine grained</em> control about everything, for example, I was able to display the days of the week <strong>from Monday to Sunday</strong>, something currently the Google Calendar chart does not allow you to do. 📆</p>
<p>The simplicity of the Svelte code here is very nice:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode jsx"><code class="sourceCode javascriptreact"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a>  {#if readings<span class="op">.</span><span class="at">loading</span>}</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>    <span class="fu">&lt;Loading</span> <span class="fu">/&gt;</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>  {<span class="op">:</span><span class="cf">else</span>}</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">&lt;div</span> <span class="ot">class</span><span class="op">=</span><span class="st">&quot;flex flex-row flex-nowrap overflow-x-scroll&quot;</span><span class="kw">&gt;</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>      <span class="fu">&lt;google-chart</span> <span class="ot">type</span><span class="op">=</span><span class="st">&quot;calendar&quot;</span> <span class="va">{</span>options<span class="va">}</span> <span class="va">{</span>data<span class="va">}</span><span class="fu">&gt;&lt;/google-chart&gt;</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">&lt;/div&gt;</span></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a>  {<span class="ss">/if}</span></span></code></pre></div>
<p>Although I’m not a big fan of templating (I still have nightmares with Angular 🤮), I have to recognise that Svelte seems to have picked up the best parts of Vue, React and other frontend frameworks and it feels really simple and elegant to build your views like this (as opposed to JSX, which also took its time to be loved 💔).</p>
<h2 id="javascripts-standard-library">JavaScript’s “standard” library</h2>
<p>It has been a while ago since the last time I had to write new JavaScript or TypeScript code, so I was really hoping some problems with the language itself would be a thing of the past, for example, here is how I conditionally render the chapter selector each time you pick a book in the UI in Elm:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="fu">select</span> [ <span class="fu">onInput</span> <span class="op">&lt;|</span> <span class="dt">SelectChapter</span> <span class="op">&lt;&lt;</span> <span class="dt">Maybe</span><span class="op">.</span><span class="fu">withDefault</span> <span class="dv">0</span> <span class="op">&lt;&lt;</span> <span class="dt">String</span><span class="op">.</span><span class="fu">toInt</span> ] <span class="op">&lt;|</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>    <span class="dt">List</span><span class="op">.</span><span class="fu">map</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>        (\<span class="fu">chapter</span> <span class="op">-&gt;</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>            <span class="fu">option</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>              [ <span class="dt">Html</span><span class="op">.</span><span class="dt">Attrs</span><span class="op">.</span><span class="fu">selected</span> <span class="op">&lt;|</span> <span class="fu">chapter</span> <span class="op">==</span> <span class="fu">selectedChapter</span> ]</span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>              [ <span class="dt">Html</span><span class="op">.</span><span class="fu">text</span> <span class="op">&lt;|</span> <span class="fu">fromInt</span> <span class="fu">chapter</span> ]</span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a>        )</span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a>        (<span class="dt">List</span><span class="op">.</span><span class="fu">range</span> <span class="dv">1</span> <span class="op">&lt;|</span> <span class="fu">getNumChapters</span> <span class="fu">selectedBook</span>)</span></code></pre></div>
<p>You might not be very familiar with this syntax, but once you get used to it, it is quite straightforward. Did you notice the use of <code>List.range</code>? 👀</p>
<p>When translating this code to TypeScript, I COULD NOT BELIEVE it is 2025 already and JavaScript still <strong>does not have</strong> a built in <code>range</code> function… I mean… come on! Yes, we have some sort of proposal to bring <a href="https://github.com/tc39/proposal-iterator.range"><code>Iterator.range</code> in Stage 2</a>, but very far away from being able to use it natively! 🥹 I had to use <code>core-js</code> and <em>manually patch TypeScript</em> 💀 to be able to use it in the Svelte app, and the result was not pretty…</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode jsx"><code class="sourceCode javascriptreact"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="fu">&lt;Select</span> <span class="ot">labelText</span><span class="op">=</span><span class="st">&quot;Year&quot;</span> <span class="ot">bind:selected</span><span class="op">=</span><span class="va">{</span>selectedYear<span class="va">}</span> <span class="ot">onchange</span><span class="op">=</span><span class="va">{</span>onChangeYear<span class="va">}</span><span class="fu">&gt;</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>  <span class="va">{</span>#each Iterator<span class="op">.</span><span class="fu">range</span>(<span class="dv">2020</span><span class="op">,</span> <span class="kw">new</span> <span class="fu">UTCDate</span>()<span class="op">.</span><span class="fu">getFullYear</span>()<span class="op">,</span> { <span class="dt">inclusive</span><span class="op">:</span> <span class="kw">true</span> }) <span class="im">as</span> value<span class="va">}</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>    <span class="fu">&lt;SelectItem</span> <span class="va">{</span>value<span class="va">}</span> <span class="fu">/&gt;</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>  <span class="va">{</span><span class="ss">/each}</span></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a><span class="ss">&lt;/Select</span><span class="op">&gt;</span></span></code></pre></div>
<p>The API is far from perfect, but it was not as annoying as having to deal with <strong>Dates</strong> in JavaScript again… In Elm, all dates are <code>UTC</code>, and since it is a language that compiles down to JS, its API for working with <code>Date</code> and time is much nicer than JavaScript’s, have a look at the Svelte code:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode typescript"><code class="sourceCode typescript"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> readingsData <span class="op">=</span> <span class="fu">$derived</span>(</span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>  readings<span class="op">?.</span><span class="at">data</span><span class="op">?.</span><span class="fu">map</span>(({ date<span class="op">,</span> book<span class="op">,</span> chapter }) <span class="kw">=&gt;</span> {</span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">const</span> d <span class="op">=</span> <span class="fu">toDate</span>(date<span class="op">.</span><span class="fu">toDate</span>()<span class="op">,</span> utc) <span class="co">// convert to UTC</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> [</span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>      d<span class="op">,</span></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a>      <span class="dv">1</span><span class="op">,</span> <span class="co">// the below snippet builds the tooltip for the calendar chart</span></span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a>      <span class="vs">`&lt;div style=&quot;font-size: 1rem;padding: 0.75rem;&quot;&gt;</span></span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a><span class="vs">        </span><span class="sc">${</span><span class="fu">format</span>(d<span class="op">,</span> <span class="st">&#39;MMMM d, yyyy&#39;</span>)<span class="sc">}</span><span class="vs">: &lt;strong&gt;</span><span class="sc">${</span>book<span class="sc">}</span><span class="vs"> </span><span class="sc">${</span>chapter<span class="sc">}</span><span class="vs">&lt;/strong&gt;</span></span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a><span class="vs">      &lt;/div&gt;`</span><span class="op">,</span></span>
<span id="cb9-10"><a href="#cb9-10" aria-hidden="true" tabindex="-1"></a>    ]</span>
<span id="cb9-11"><a href="#cb9-11" aria-hidden="true" tabindex="-1"></a>  })</span>
<span id="cb9-12"><a href="#cb9-12" aria-hidden="true" tabindex="-1"></a>)</span></code></pre></div>
<p>I had to rely on not one, but <strong>TWO JS libraries</strong> to format the dates properly and also maintain the coherence of the UTC dates, the two being the indispensable <code>date-fns</code> and also in this case <code>@date-fns/utc</code>.</p>
<p>I know there is a brighter future ahead with the <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal">Temporal API</a> and such, but I wish we had improved more here on the JavaScript side…</p>
<h2 id="type-safety">Type safety</h2>
<p>Ok so, Svelte is pretty great… but, what is my main complaint? <strong>TypeScript</strong> 😁 (please bear with me haha). The following code in the application is valid and it actually works:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode typescript"><code class="sourceCode typescript"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="kw">async</span> <span class="kw">function</span> <span class="fu">handleRead</span>() {</span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>  readingId <span class="op">=</span> <span class="cf">await</span> readings<span class="op">.</span><span class="fu">add</span>({</span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>    book<span class="op">:</span> selectedBook<span class="op">,</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>    chapter<span class="op">:</span> selectedChapter<span class="op">,</span></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>    date<span class="op">:</span> Timestamp<span class="op">.</span><span class="fu">fromDate</span>(selectedDate)<span class="op">,</span></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a>  })</span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p>Besides having to mutate <code>$state</code> data etc, which I can bear, where is the error handling? <strong>Nothing</strong> prevented me from writing (and shipping to production!) such code, because it is on YOU, the developer, the responsibility for error handling and making sure things don’t break. For example, wrapping async code in <code>try { ... } catch { ... } finally { ... }</code> blocks, etc…</p>
<p>Besides, even when TypeScript is able to infer correctly sometimes the types in the application, it can be completely overriden by the developer with <code>as</code> manual castings, etc. Such escape hatches simply DO NOT EXIST in Elm. Elm is a language with <a href="https://www.epicweb.dev/talks/hindley-and-milner-walk-into-a-bar">Hindley-Milner type inference</a> and as such, is far superior to TypeScript. Bear in mind that the <a href="https://softwareengineering.stackexchange.com/questions/337295/what-is-the-benefit-of-having-no-runtime-errors-like-elm-claims">“no runtime errors” philosophy</a> of Elm is for me still one of its strongest selling points. 💪🏻</p>
<p>Have a look at the following Elm code from the app:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="cf">case</span> <span class="fu">readings</span> <span class="cf">of</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>    <span class="dt">NotAsked</span> <span class="op">-&gt;</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>        <span class="fu">el</span> [ <span class="fu">centerY</span><span class="op">,</span> <span class="fu">centerX</span> ] <span class="op">&lt;|</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>            <span class="fu">button</span> <span class="fu">btns</span> { <span class="fu">label</span> <span class="op">=</span> <span class="fu">text</span> <span class="st">&quot;GOOGLE SIGN IN&quot;</span><span class="op">,</span> <span class="fu">onPress</span> <span class="op">=</span> <span class="dt">Just</span> <span class="dt">LogIn</span> }</span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Failure</span> <span class="fu">message</span> <span class="op">-&gt;</span></span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a>        <span class="fu">el</span> [ <span class="fu">centerY</span><span class="op">,</span> <span class="fu">centerX</span><span class="op">,</span> <span class="dt">Font</span><span class="op">.</span><span class="fu">color</span> <span class="op">&lt;|</span> <span class="fu">rgb255</span> <span class="dv">255</span> <span class="dv">0</span> <span class="dv">0</span> ] <span class="op">&lt;|</span></span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a>            <span class="fu">text</span> (<span class="fu">httpErrorToString</span> <span class="fu">message</span>)</span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-10"><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Loading</span> <span class="op">-&gt;</span></span>
<span id="cb11-11"><a href="#cb11-11" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Loading</span><span class="op">.</span><span class="fu">render</span> <span class="dt">Spinner</span></span>
<span id="cb11-12"><a href="#cb11-12" aria-hidden="true" tabindex="-1"></a>        <span class="co">-- rest of the code</span></span></code></pre></div>
<p>Besides having awesome pattern-matching super powers, every single type that is returned from an Elm library, is going to be a <code>Maybe</code>, a <code>Result</code> type, or some other type that we are going to forcefully have to UNWRAP ourselves to make sure it works, <strong>error handling is enforced by the compiler!</strong> 🤖</p>
<p>The Model-View-Update followed by TEA needs some time to wrap our head around it, but basically, when I get back from my <code>ReadChapter</code> message, I need to pattern match on it:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="dt">ReadChapter</span> (<span class="dt">Ok</span> <span class="fu">chapter</span>) <span class="op">-&gt;</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- if we succeed reading a chapter we just append it to the beginning of the list</span></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>    ( { <span class="fu">model</span> <span class="op">|</span> <span class="fu">readings</span> <span class="op">=</span> <span class="dt">RemoteData</span><span class="op">.</span><span class="fu">map</span> ((<span class="op">::</span>) <span class="fu">chapter</span>) <span class="fu">model</span><span class="op">.</span><span class="fu">readings</span> }<span class="op">,</span> <span class="dt">Cmd</span><span class="op">.</span><span class="fu">none</span> )</span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a><span class="dt">ReadChapter</span> (<span class="dt">Err</span> <span class="fu">_</span>) <span class="op">-&gt;</span></span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- in this particular case, I know a failure is due to trying to record the same reading twice</span></span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a>    ( { <span class="fu">model</span> <span class="op">|</span> <span class="fu">readings</span> <span class="op">=</span> <span class="dt">Failure</span> <span class="op">&lt;|</span> <span class="dt">BadBody</span> <span class="st">&quot;You tried recording the same reading twice, refresh the page!&quot;</span> }<span class="op">,</span> <span class="dt">Cmd</span><span class="op">.</span><span class="fu">none</span> )</span></code></pre></div>
<p>And therefore I always need to handle explicity what happens, not only in the happy path (as shown in the TypeScript/Svelte snippet above), but also <strong>ALL possible states/scenarios when things go wrong.</strong></p>
<blockquote>
<p>Elm’s philosophy truly helps you make impossible states actually impossible!</p>
</blockquote>
<h2 id="conclusion">Conclusion</h2>
<p>I have to say, Svelte has sparkled back in me the excitement for web development, this is very important for me and it has been years since the last time I felt this joy, probably the last time I felt it was when learning Elm a few years ago. 🎉</p>
<p>If I had to choose a JavaScript/TypeScript frontend framework for my next app, I would <strong>probably never use React again</strong> (and this is huge!) and pick Svelte instead. However, as mentioned in the previous section, TypeScript is still MILES behind from the type safety of Elm. Therefore, even despite the verbosity of the code, if I REALLY cared about the correctness and maintainability of the application I am going to write, and I want to sleep well at night rest assured that nothing is going to blow up, <strong>I would still pick Elm for my frontend development</strong>.</p>
<p>Obviously, both Elm and Svelte have their tradeoffs (for example, Elm’s foreign function interface with JavaScript is <em>very</em> limited) but I hope I have presented them objectively enough in this post and that you enjoyed it!</p>
<p>If you found joy in this blogpost, share it in your social networks and <strong>follow me on <a href="https://twitter.com/FlavioCorpa">Twitter</a></strong> and <a href="https://bsky.app/profile/flaviocorpa.com">BlueSky</a>! 🦋</p></section>
  </article>
</main>


<bsky-comments post="at://did:plc:dvrocvv5szl2evqiafsx4iyw/app.bsky.feed.post/3lpuiptgukc2m"></bsky-comments>
 <footer class="py-14 bg-[var(--footerBgColor)] shrink-0">
  <div class="relative mx-auto md:w-[600px] w-auto px-[1.3125rem]">
    <ul class="flex justify-center list-none" role="list">
      <li class="mx-3" role="listitem">
        <a href="/">Home</a>
      </li>
      <li class="mx-3" role="listitem">
        <a href="https://github.com/sponsors/kutyel/">Sponsor me</a>
      </li>
      <li class="mx-3" role="listitem">
        <a href="/atom.xml">RSS</a>
      </li>
    </ul>
  </div>
</footer>


<script src="https://gistcdn.githack.com/kutyel/41d12e099484fd390fb67168271fcdd9/raw/9be26e500525a2e4edacc53d3a8006aaddec0e15/bsky-comments.js"></script>
]]></description>
    <pubDate>Wed, 04 Jun 2025 15:00:00 UT</pubDate>
    <guid>https://flaviocorpa.com/building-a-non-trivial-app-with-elm-and-with-svelte.html</guid>
    <dc:creator>Flavio Corpa</dc:creator>
</item>
<item>
    <title>The wish of the cat</title>
    <link>https://flaviocorpa.com/the-wish-of-the-cat.html</link>
    <description><![CDATA[<nav class="my-6 py-2">
  <div class="relative mx-auto md:w-[600px] w-auto px-[1.3125rem] md:px-0" data-nav-wrap>
    <a class="mr-5 absolute left-[-10000px] focus:static focus:left-auto" href="#content"
      >Skip to content</a
    >
    <a class="mr-5" href="/">Home</a>
    <a class="mr-5" href="https://github.com/sponsors/kutyel">Sponsor me</a>
    <a class="mr-5" href="/atom.xml">RSS</a>
  </div>
</nav>


<style>
  bsky-comments {
    --background-color: var(--bgColor);
    --text-color: var(--textColor);
    --link-color: var(--textLinkColor);
    --link-hover-color: var(--textLinkHoverColor);
    --comment-meta-color: #888;
    --error-color: #ff4d4d;
    --reply-border-color: var(--separatorColor);
    --button-background-color: var(--btnBgColor);
    --button-hover-background-color: rgba(var(--btnBgColor), 0.2);
    --author-avatar-border-radius: 50%;
  }
</style>

<main class="flex-1" id="content" tabindex="-1">
  <article class="pb-10">
    <header class="bg-[var(--headerBgColor)] mb-8 px-[1.3125rem] md:px-0 py-4 md:py-8">
      <div class="mx-auto md:w-[600px]">
        <h1 class="text-[1.7rem] md:text-[3rem] m-0 mb-4 font-normal leading-[1.2] text-[var(--h1Color)]">
          The wish of the cat
        </h1>
        <div class="mx-auto md:w-[600px]">
          <small class="italic">03/04/2025</small>
          <small class="italic"> | 1 min read</small>
          
          <div class="mt-2">[ <a title="All pages tagged &#39;languages&#39;." href="/tags/languages.html" rel="tag">languages</a>, <a title="All pages tagged &#39;japanese&#39;." href="/tags/japanese.html" rel="tag">japanese</a> ]</div>
        </div>
      </div>
    </header>
    <section class="mx-auto md:w-[600px] px-[1.3125rem] md:px-0"><h1 id="猫の望み">猫の望み</h1>
<p><img src="./images/nozomi.png" alt="An illustration of a buddhist monk playing the shamisen and a djinn orange cat coming out of it" width="700px"></p>
<p><ruby>遥<rt>はる</rt></ruby>か<ruby>昔<rt>むかし</rt></ruby>、<ruby>江戸時代<rt>えどじだい</rt></ruby>、<ruby>宮島<rt>みやじま</rt></ruby>のとある<ruby>丘<rt>おか</rt></ruby>で…</p>
<p><ruby>桐島<rt>きりしま</rt></ruby>というお<ruby>坊<rt>ぼう</rt></ruby>さんがいて、<ruby>彼<rt>かれ</rt></ruby>はいつも<ruby>日没後<rt>にちぼつご</rt></ruby>、<ruby>夜遅<rt>よるおそ</rt></ruby>くまで<ruby>三味線<rt>しゃみせん</rt></ruby>の<ruby>練習<rt>れんしゅう</rt></ruby>をしていたんだ。その<ruby>夜<rt>よる</rt></ruby>は<ruby>特<rt>とく</rt></ruby>に<ruby>静<rt>しず</rt></ruby>かで、<ruby>風<rt>かぜ</rt></ruby>の<ruby>音<rt>おと</rt></ruby>さえ<ruby>聞<rt>き</rt></ruby>こえず、<ruby>木々<rt>きぎ</rt></ruby>の<ruby>葉<rt>は</rt></ruby>が<ruby>動<rt>うご</rt></ruby>くのも<ruby>聞<rt>き</rt></ruby>こえなかった…</p>
<p><ruby>満月<rt>まんげつ</rt></ruby>の<ruby>夜更<rt>よふ</rt></ruby>け、<ruby>弦楽器<rt>げんがっき</rt></ruby>を<ruby>弾<rt>ひ</rt></ruby>き<ruby>始<rt>はじ</rt></ruby>めた<ruby>彼<rt>かれ</rt></ruby>の<ruby>前<rt>まえ</rt></ruby>に<ruby>突然<rt>とつぜん</rt></ruby>、ジン・<ruby>茶<rt>チャ</rt></ruby>トラの<ruby>猫<rt>ネコ</rt></ruby>の<ruby>姿<rt>すがた</rt></ruby>が<ruby>現<rt>あらわ</rt></ruby>れた。</p>
<p>『<ruby>痛<rt>いた</rt></ruby>い、<ruby>痛<rt>いた</rt></ruby>い、<ruby>痛<rt>いた</rt></ruby>い！』</p>
<p>『どこが<ruby>痛<rt>いた</rt></ruby>いいのか？』</p>
<p>『そんな<ruby>不器用<rt>ぶきよう</rt></ruby>なやり<ruby>方<rt>かた</rt></ruby>で<ruby>私<rt>わたし</rt></ruby>の<ruby>肌<rt>はだ</rt></ruby>をもてあそぶのはやめてくれにゃん！』</p>
<p>『あなたの<ruby>皮<rt>かわ</rt></ruby>？』</p>
<p>『そう、その<ruby>三味線<rt>しゃみせん</rt></ruby>は私の<ruby>皮<rt>かわ</rt></ruby>の<ruby>残骸<rt>ざんがい</rt></ruby>から<ruby>作<rt>つく</rt></ruby>られたもので、あなたが私を<ruby>呼<rt>よ</rt></ruby>び<ruby>出<rt>だ</rt></ruby>した<ruby>以上<rt>いじょう</rt></ruby>、3 つの<ruby>願<rt>ねが</rt></ruby>いを<ruby>叶<rt>かな</rt></ruby>えるのが私の<ruby>務<rt>つと</rt></ruby>めだにゃん』</p>
<p>『へーー。。。そうですか？』</p>
<p>『そうにゃん、でも<ruby>警告<rt>けいこく</rt></ruby>しておきますが、あなたが<ruby>求<rt>もと</rt></ruby>める<ruby>願<rt>ねが</rt></ruby>いは、あなたが<ruby>望<rt>のぞ</rt></ruby>む<ruby>効果<rt>こうか</rt></ruby>をもたらさないかもしれません。』</p>
<p>『なるほど……<ruby>少<rt>すこし</rt></ruby>し<ruby>考<rt>かんが</rt></ruby>えさせてください…』</p>
<p><ruby>桐島<rt>きりしま</rt></ruby>は<ruby>苦悶<rt>くもん</rt></ruby>の<ruby>表情<rt>ひょうじょう</rt></ruby>を<ruby>浮<rt>う</rt></ruby>かべた。</p>
<p>『にゃーん、お<ruby>腹<rt>なか</rt></ruby>がぺこぺこにゃん。。。』と<ruby>猫<rt>ねこ</rt></ruby>が<ruby>言<rt>い</rt></ruby>った。</p>
<p>『私は<ruby>決心<rt>けっしん</rt></ruby>した。私の<ruby>最初<rt>さいしょ</rt></ruby>の<ruby>願<rt>ねが</rt></ruby>いは、<ruby>三味線<rt>しゃみせん</rt></ruby>の<ruby>最高<rt>さいこう</rt></ruby>の<ruby>音楽家<rt>おんがくか</rt></ruby>として<ruby>記憶<rt>きおく</rt></ruby>されることだ。』</p>
<p>『<ruby>願<rt>ねが</rt></ruby>いが<ruby>叶<rt>かな</rt></ruby>ったにゃん！』</p>
<p>『私の 2 つ<ruby>目<rt>め</rt></ruby>の<ruby>願<rt>ねが</rt></ruby>いは、私が<ruby>死<rt>し</rt></ruby>んだ<ruby>後<rt>あと</rt></ruby>、<ruby>家族<rt>かぞく</rt></ruby>に<ruby>大切<rt>たいせつ</rt></ruby>なものが<ruby>何<rt>なに</rt></ruby>も<ruby>足<rt>た</rt></ruby>りないものがないようにすることだ。』</p>
<p>『<ruby>面白<rt>おもしろ</rt></ruby>いにゃん！<ruby>完成<rt>かんせい</rt></ruby>です。』</p>
<p>『<ruby>最後<rt>さいご</rt></ruby>に、3 つ<ruby>目<rt>め</rt></ruby>の<ruby>願<rt>ねが</rt></ruby>いは、あなたの<ruby>魂<rt>たましい</rt></ruby>が<ruby>安<rt>やす</rt></ruby>らかに<ruby>眠<rt>ねむ</rt></ruby>れるようにということです。』</p>
<p>『あー！ワクワクします、どうもーにゃん！』</p>
<p>その<ruby>後<rt>あと</rt></ruby>、だんだん<ruby>猫<rt>ねこ</rt></ruby>も<ruby>三味線<rt>しゃみせん</rt></ruby>も<ruby>消<rt>き</rt></ruby>えていった。</p>
<p>それから<ruby>数<rt>すう</rt></ruby><ruby>世紀<rt>せいき</rt></ruby><ruby>後<rt>ご</rt></ruby>、この<ruby>僧<rt>そう</rt></ruby>は<ruby>古代<rt>こだい</rt></ruby><ruby>最高<rt>さいこう</rt></ruby>の<ruby>三味線<rt>しゃみせん</rt></ruby><ruby>奏者<rt>そうしゃ</rt></ruby>として<ruby>記憶<rt>きおく</rt></ruby>されるようになったが、<ruby>彼<rt>かれ</rt></ruby>の<ruby>家<rt>うち</rt></ruby>は<ruby>破産<rt>はさん</rt></ruby>し、<ruby>富<rt>とみ</rt></ruby>と<ruby>名声<rt>めいせい</rt></ruby>をすべて<ruby>台無<rt>だいな</rt></ruby>しにしてしまった。</p></section>
  </article>
</main>


<bsky-comments post="at://did:plc:dvrocvv5szl2evqiafsx4iyw/app.bsky.feed.post/3llvwklpum225"></bsky-comments>
 <footer class="py-14 bg-[var(--footerBgColor)] shrink-0">
  <div class="relative mx-auto md:w-[600px] w-auto px-[1.3125rem]">
    <ul class="flex justify-center list-none" role="list">
      <li class="mx-3" role="listitem">
        <a href="/">Home</a>
      </li>
      <li class="mx-3" role="listitem">
        <a href="https://github.com/sponsors/kutyel/">Sponsor me</a>
      </li>
      <li class="mx-3" role="listitem">
        <a href="/atom.xml">RSS</a>
      </li>
    </ul>
  </div>
</footer>


<script src="https://gistcdn.githack.com/kutyel/41d12e099484fd390fb67168271fcdd9/raw/9be26e500525a2e4edacc53d3a8006aaddec0e15/bsky-comments.js"></script>
]]></description>
    <pubDate>Thu, 03 Apr 2025 13:00:00 UT</pubDate>
    <guid>https://flaviocorpa.com/the-wish-of-the-cat.html</guid>
    <dc:creator>Flavio Corpa</dc:creator>
</item>
<item>
    <title>My Journey to Japanese N3 Level</title>
    <link>https://flaviocorpa.com/my-journey-to-japanese-n3-level.html</link>
    <description><![CDATA[<nav class="my-6 py-2">
  <div class="relative mx-auto md:w-[600px] w-auto px-[1.3125rem] md:px-0" data-nav-wrap>
    <a class="mr-5 absolute left-[-10000px] focus:static focus:left-auto" href="#content"
      >Skip to content</a
    >
    <a class="mr-5" href="/">Home</a>
    <a class="mr-5" href="https://github.com/sponsors/kutyel">Sponsor me</a>
    <a class="mr-5" href="/atom.xml">RSS</a>
  </div>
</nav>


<style>
  bsky-comments {
    --background-color: var(--bgColor);
    --text-color: var(--textColor);
    --link-color: var(--textLinkColor);
    --link-hover-color: var(--textLinkHoverColor);
    --comment-meta-color: #888;
    --error-color: #ff4d4d;
    --reply-border-color: var(--separatorColor);
    --button-background-color: var(--btnBgColor);
    --button-hover-background-color: rgba(var(--btnBgColor), 0.2);
    --author-avatar-border-radius: 50%;
  }
</style>

<main class="flex-1" id="content" tabindex="-1">
  <article class="pb-10">
    <header class="bg-[var(--headerBgColor)] mb-8 px-[1.3125rem] md:px-0 py-4 md:py-8">
      <div class="mx-auto md:w-[600px]">
        <h1 class="text-[1.7rem] md:text-[3rem] m-0 mb-4 font-normal leading-[1.2] text-[var(--h1Color)]">
          My Journey to Japanese N3 Level
        </h1>
        <div class="mx-auto md:w-[600px]">
          <small class="italic">18/09/2024</small>
          <small class="italic"> | 8 min read</small>
          
          <small class="italic"> (updated: 06/11/2024 00:15)</small>
          
          <div class="mt-2">[ <a title="All pages tagged &#39;japanese&#39;." href="/tags/japanese.html" rel="tag">japanese</a>, <a title="All pages tagged &#39;noken&#39;." href="/tags/noken.html" rel="tag">noken</a>, <a title="All pages tagged &#39;languages&#39;." href="/tags/languages.html" rel="tag">languages</a>, <a title="All pages tagged &#39;polyglot&#39;." href="/tags/polyglot.html" rel="tag">polyglot</a> ]</div>
        </div>
      </div>
    </header>
    <section class="mx-auto md:w-[600px] px-[1.3125rem] md:px-0"><p><img src="./images/n3.png" alt="logo" width="650px"></p>
<p>Recently, on the Bunpro community forums I was asked about my particular Japanese learning journey, and I decided this was a topic where I really wanted to pour out my thoughts, so here I go!</p>
<p><img src="./images/question.png" alt="question" width="650px"></p>
<p>It all started on my first trip to Japan in 2017, back then, only my younger brother knew a little bit of Japanese. Rather soon, it became really evident to us that indeed some degree of language knowledge was needed in order to travel efficiently around Japan. Even after our second trip, in 2023, the situation has not really improved an English is very scarce even for tourist-facing businesses! 🤯</p>
<h2 id="motivation">Motivation</h2>
<p>So I came back from our first trip to Japan in love with the country and its culture, as up until that point I had only travelled within Spain and some European countries. Really, as a western traveller, if you have never been to Japan (or Asia) before, the experience is just mind-boggling in a good way and I really enjoyed it, everything is different! And Japan is so incredibly clean and its citizens as polite as a modern human society can get. I forgot to mention that I had already watched maybe circa ~200 animes by that time (yes, I am a real w33b 😅).</p>
<p>Therefore I came back from our first trip determined to learn the language and enrolled the EOI (<em>Official School of Languages</em> by its acronym in Spanish, a language school organised by the state and almost free of charge) in the first year of Japanese. I was really lucky that from the very beginning the teacher was native (hi Norika! 🙇🏼‍♂️) and an excellent and passionate instructor of the language.</p>
<p>I reached a point in my life where I was already very happy with my English level (reached C2 around that time) and, since I love learning new languages, I decided that for my next challenge I would take up a tough one, rather than going for the low-hanging fruit and pick an “easy” European language (and boy how much trouble was waiting for me after that choice 😅).</p>
<h2 id="eoi">EOI</h2>
<p>I enrolled in the EOI for Japanese and have been styuding there for the last 5 scholar years. This was a great idea because it forced me to have some exposure to Japanese at least 4h/week. If you want to maximize your language learning you normally need to do some degree of <strong>cultural immersion</strong>, I can’t move to Japan right now so that is not going to happen, so I needed to expose myself to the language as much as possible within reasonable bounds.</p>
<p>I did this thanks to the EOI, watching anime, listening to J-POP (especially to RADWIMPS and Asian Kungfu Generation, my favourites 🤩) and attending language exchanges whenever the school or the local university organized them (<ruby>交流会<rt>こうりゅうかい</rt></ruby>). These language exchanges are great for meeting natives and try and wet your feet and start to talk, but they are very short and not very well suited for introverts I’m afraid.</p>
<p>I felt extremely disappointed watching YouTube videos saying: HERE IS HOW I ACHIEVED N1 LEVEL IN 2 YEARS!! And they forgot to mention that they <em>moved to Japan</em> 😅. Please, language Youtubers, don’t do this. Do not deceive your audience and do not create false expectations on us language learners because the reality is… <strong>Japanese is HARD. REALLY HARD.</strong> In my own experience I would say that maybe x5 times harder than English, so we need to set reasonable expectations for ourselves, be patient and assume that language and culture learning are lifetime experiences, we should not hurry them!</p>
<p>One of the nice things about the EOI is that you learn progressively and by topic certain grammar and vocabulary that is aimed primarily, I would say, to visit Japan as a tourist and having everyday conversations. This is really nice but they do not force too much the Kanji on you (which is a mistake in my opinion), and so it happens that when you visit Japan and see complex kanji all around you get really overwhelmed, you basically can’t read 80% of what you see if you only know ひらがな/カタカナ.</p>
<p>Even though we do listening practice and some conversation, after 5 full years I’m still not fluent. I feel I’ve reached a point when I’m about to take off and I’m almost ready to start talking non stop, but that will have to wait. I have a lot of grammar and vocab knowledge by now, but feel that putting it together in conversation is a whole different beast. I will keep pushing though! 💪🏻</p>
<h2 id="wanikani">WaniKani</h2>
<p>I did two things when I set my mind to learn Japanese: the first one was joining the EOI and the second one was to register into <a href="https://www.wanikani.com/">WaniKani</a>, and when the end of the year sale came up (they have one every year) I purchased the <strong>lifetime membership</strong>.</p>
<blockquote>
<p>I won’t hide the fact that I saw my little brother doing reviews on this website for a very long time and I knew from his experience that the method worked and he recommended it also.</p>
</blockquote>
<p>WaniKani is an excellent website to learn kanji that uses an SRS (Spaced Repetition System) and fun mnemonics to help you remember each kanji’s meaning and different readings (yes, in Japanese there are sometimes more than one different reading per kanji! 🥹).</p>
<p><img src="./images/wk.png" alt="wk" width="650px"></p>
<p>I really enjoyed the gamified nature of the website and could feel that I was making good progress, so I decided to join one of those <a href="https://community.wanikani.com/t/let%E2%80%99s-climb-tokyo-skytree-level-60-in-autumn-2023/44711">races to the top</a> that the WaniKani community does, and this was a <em>terrible mistake</em> that I would later regret…</p>
<p><img src="./images/skytree.png" alt="skytree" width="650px"></p>
<p>While learning Japanese, one of the elephants in the room that no one wants to address are kanji (there are other elephants also, like <ruby>敬語<rt>けいご</rt></ruby> and the endless counters of the language), so I decided I would spend a little time each day to study kanji and that way I would get them out of my way ASAP. This was a really practical choice and one I’m very proud of because I was always ahead of my classmates in kanji knowledge and this also made possible to digest complex readings on an earlier stage. In fact I already knew most of the kanji needed to pass the N3 exam right after my first year of WaniKani. 😎</p>
<blockquote>
<p>Consistency is key, and a bit of effort every single day goes a long way</p>
</blockquote>
<p>Here is my final position in the Tokyo Skytree challenge, I joined when I was level 20 in WaniKani, and finished the challenge (reached level 60) only 18 months after joining.</p>
<p><img src="./images/top.png" alt="top" width="650px"></p>
<p><strong>What do I regret about joining the challenge?</strong> In order to prioritize Kanji learning, I dismissed vocabulary, using some external plugins to re-order the reviews of the website and only focus on radical/kanji. This is a terrible mistake because when you learn a radical/kanji in isolation, the way it remains forever in your brain is when you see actual WORDS with those kanji in your vocabulary. So doing this was very foolish of me and made me forget some Kanji that I should know by now, but I do not… DO NOT DO THIS!!</p>
<h2 id="bunpro">Bunpro</h2>
<p><img src="./images/bunpro.png" alt="bunpro" width="650px"></p>
<p>After some degree of success with KaniWani, I felt that I knew a lot of kanji, but could not say the same about grammar, that’s when I found <a href="https://bunpro.jp/">Bunpro</a>!</p>
<p>The idea to keep using an SRS but to learn grammar was very appealing, so I used Bunpro more or less for two years. I did not pay for the lifetime membership this time, just for two years because I wanted to try out the service before deciding to purchase the complete version.</p>
<p>The Noken focused grammar and vocabulary decks were really handy, that’s what I mostly used to learn all the grammar up to N3, so it was helpful to some degree.</p>
<p>But somehow, the gamification and overall interface of the website is not as engaging as WaniKani, so I could not keep my streak there for too long. Also something that annoyed me a little was <strong>the lack of custom decks</strong>. I found myself wanting to study for a particular quarter test for EOI and wanting to just put the grammar of the Marugoto books we were using in a custom deck, but currently this is not possible and it was a bit dissapointing. <del>Hopefully they will add this functionality in the future! 🤞🏻</del> UPDATE: Indeed custom decks have been added as of 2025!</p>
<h2 id="the-jlpt-exams">The JLPT Exams</h2>
<p>Some people do not realise this, but <strong>exams are actually really important to consolidate your knowledge!</strong> Since I knew this, after my 1st year of EOI I took the JLPT N5 exam (the easiest) and passed it. The mark was enough to pass but not something incredible, my goal was just to set a milestone for myself and to succeed.</p>
<p>After the 3rd year learning Japanese in the EOI I decided to try out N4, and also passed it, again without a great mark but I will take it! 🎉 Finally, this year, after 5 years of learning Japanese I decided to give N3 a go, this was my original goal and I was a bit nervous… but as you might have guessed by reading this post, I succeeded again! 🙌🏻</p>
<h2 id="the-final-struggle-towards-n3">The final struggle towards N3</h2>
<p>After I enlisted to take the N3 exam on July 2024, the weeks were passing by and the school year of the EOI typically ends in May, so I needed to do something to prevent Japanese from escaping my brain! 🤣 (Summer holidays are tough!)</p>
<p>Thanks to my Japanese teacher, Norika, she lent me the <ruby>日本語総<rt>にほんごそう</rt></ruby>まとめ books to prepare for N3, which I found to be of great help because they are designed to study during a <strong>period of 6 weeks</strong> and you can interleave a bit of grammar/kanji/vocabulary each day.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">I’ve used these 3 for N3 and they worked like a charm 🙌🏼 <a href="https://t.co/I5Fb28Pe90">pic.twitter.com/I5Fb28Pe90</a></p>&mdash; Flavio 🏴‍☠️ (@FlavioCorpa) <a href="https://twitter.com/FlavioCorpa/status/1829423854470455528?ref_src=twsrc%5Etfw">August 30, 2024</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>I sincerely believe I would have not passed the JLPT N3 test had I not used those final weeks to study and crystalize my knowledge!</p>
<h2 id="going-forward">Going forward</h2>
<p>As I said at the beginning of this post, <strong>a language learning journey basically never ends</strong>, I’m STILL learning new English words almost everyday (all TV I consume and most fantasy/scifi books I read are in English), so I’m determined to do the same with Japanese! I will join again the next course of the EOI and will try and finally start talking as much I can, to see if I can breakthrough and sky rocket my learning process! 🤞🏻</p>
<p>Compared to other people that reached N1 level in 2 years, I don’t feel special at all, and rather feel a bit clumsy/embarrased for telling you that it took me 5 years to reach N3 level… but hey! Every person’s language journey is different, and I’m not going to feel ashamed about mine. 😉</p>
<p>I hope that if you are also learning Japanese, you got at least a couple of useful tips if you managed to read this far (sorry for the long blogpost LOL 🤣) and that you PLEASE do not repeat the same mistakes I fell for! 🙏🏻 I’m also really interested in knowing about your journey or any useful tips that worked for you, so feel free to comment down below in the blog or follow me on <a href="https://x.com/FlavioCorpa">Twitter</a> to keep the conversation going. 🌊</p>
<p>Best of luck in your Japanese learning journey! 👋🏻</p></section>
  </article>
</main>


<bsky-comments post="at://did:plc:dvrocvv5szl2evqiafsx4iyw/app.bsky.feed.post/3lbu2ym72422p"></bsky-comments>
 <footer class="py-14 bg-[var(--footerBgColor)] shrink-0">
  <div class="relative mx-auto md:w-[600px] w-auto px-[1.3125rem]">
    <ul class="flex justify-center list-none" role="list">
      <li class="mx-3" role="listitem">
        <a href="/">Home</a>
      </li>
      <li class="mx-3" role="listitem">
        <a href="https://github.com/sponsors/kutyel/">Sponsor me</a>
      </li>
      <li class="mx-3" role="listitem">
        <a href="/atom.xml">RSS</a>
      </li>
    </ul>
  </div>
</footer>


<script src="https://gistcdn.githack.com/kutyel/41d12e099484fd390fb67168271fcdd9/raw/9be26e500525a2e4edacc53d3a8006aaddec0e15/bsky-comments.js"></script>
]]></description>
    <pubDate>Wed, 18 Sep 2024 15:00:00 UT</pubDate>
    <guid>https://flaviocorpa.com/my-journey-to-japanese-n3-level.html</guid>
    <dc:creator>Flavio Corpa</dc:creator>
</item>
<item>
    <title>Haskell for Elm developers: giving names to stuff (Part 5 - Semigroups and Monoids)</title>
    <link>https://flaviocorpa.com/haskell-for-elm-developers-giving-names-to-stuff-part-5-semigroups-and-monoids.html</link>
    <description><![CDATA[<nav class="my-6 py-2">
  <div class="relative mx-auto md:w-[600px] w-auto px-[1.3125rem] md:px-0" data-nav-wrap>
    <a class="mr-5 absolute left-[-10000px] focus:static focus:left-auto" href="#content"
      >Skip to content</a
    >
    <a class="mr-5" href="/">Home</a>
    <a class="mr-5" href="https://github.com/sponsors/kutyel">Sponsor me</a>
    <a class="mr-5" href="/atom.xml">RSS</a>
  </div>
</nav>


<style>
  bsky-comments {
    --background-color: var(--bgColor);
    --text-color: var(--textColor);
    --link-color: var(--textLinkColor);
    --link-hover-color: var(--textLinkHoverColor);
    --comment-meta-color: #888;
    --error-color: #ff4d4d;
    --reply-border-color: var(--separatorColor);
    --button-background-color: var(--btnBgColor);
    --button-hover-background-color: rgba(var(--btnBgColor), 0.2);
    --author-avatar-border-radius: 50%;
  }
</style>

<main class="flex-1" id="content" tabindex="-1">
  <article class="pb-10">
    <header class="bg-[var(--headerBgColor)] mb-8 px-[1.3125rem] md:px-0 py-4 md:py-8">
      <div class="mx-auto md:w-[600px]">
        <h1 class="text-[1.7rem] md:text-[3rem] m-0 mb-4 font-normal leading-[1.2] text-[var(--h1Color)]">
          Haskell for Elm developers: giving names to stuff (Part 5 - Semigroups and Monoids)
        </h1>
        <div class="mx-auto md:w-[600px]">
          <small class="italic">14/08/2024</small>
          <small class="italic"> | 6 min read</small>
          
          <small class="italic"> (updated: 14/08/2024 15:15)</small>
          
          <div class="mt-2">[ <a title="All pages tagged &#39;haskell&#39;." href="/tags/haskell.html" rel="tag">haskell</a>, <a title="All pages tagged &#39;elm&#39;." href="/tags/elm.html" rel="tag">elm</a>, <a title="All pages tagged &#39;fp&#39;." href="/tags/fp.html" rel="tag">fp</a> ]</div>
        </div>
      </div>
    </header>
    <section class="mx-auto md:w-[600px] px-[1.3125rem] md:px-0"><p><img src="./images/haskell-elm.svg" alt="logo" width="300px"></p>
<p>Hello everyone! In my <a href="https://flaviocorpa.com/haskell-for-elm-developers-giving-names-to-stuff-part-4-parser-combinators.html">last post</a>, instead of going for the low-hanging fruit (like I’m doing right now 🤣) I decided to talk about parser combinators because it is a topic that I <em>really</em> enjoy. But now we should proceed on the quest of “giving names to stuff”, so let us talk about Semigroups and Monoids!</p>
<h2 id="what-is-a-semigroup">What is a Semigroup?</h2>
<p>As you may already know, these fancy terms come from <a href="https://en.wikipedia.org/wiki/Semigroup"><strong>algebra</strong></a>, but we are not going to write a mathematical post, we are just going to focus on learning Haskell through simple Elm code examples. So, how are Semigroups defined in Haskell?</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Semigroup</span> a <span class="kw">where</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="ot">  (&lt;&gt;) ::</span> a <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> a</span></code></pre></div>
<p>Actually it is not something really exciting, a <code>Semigroup</code> is every single type that has a <code>&lt;&gt;</code> operator (or an <code>append</code> function, which behaves the same way) and just allows us to put things together…</p>
<p>The only interesting prerequisite that we need to have in mind to be considered a Semigroup, is that the <code>&lt;&gt;</code> operation should be <strong>associative</strong>: <code>a &lt;&gt; (b &lt;&gt; c) = (a &lt;&gt; b) &lt;&gt; c</code>.</p>
<p>For Elm, what simple examples come to mind? Of course, lists and strings!</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> [<span class="dv">1</span><span class="op">,</span> <span class="dv">2</span>] <span class="op">++</span> [<span class="dv">3</span><span class="op">,</span> <span class="dv">4</span>]</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>[<span class="dv">1</span><span class="op">,</span><span class="dv">2</span><span class="op">,</span><span class="dv">3</span><span class="op">,</span><span class="dv">4</span>] : <span class="dt">List</span> <span class="fu">number</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> <span class="st">&quot;dear&quot;</span> <span class="op">++</span> <span class="st">&quot; &quot;</span> <span class="op">++</span> <span class="st">&quot;semigroups!&quot;</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;dear semigroups!&quot;</span> : <span class="dt">String</span></span></code></pre></div>
<p>If you notice, the <code>++</code> operator is just sugar for this operation (which we will call <code>mappend</code> from now on) on lists and strings, we are just concatenating stuff together!</p>
<p>In fact, a quick search in <a href="https://package.elm-lang.org/packages/elm/core/latest/Array#append"><code>elm/core</code></a> looking up the <code>append</code> function reveals us some Semigroups that we have available in Elm, namely: <code>Array</code>, <code>String</code> and <code>List</code>.</p>
<p>But is this all there is to it? 🤔</p>
<h2 id="enter-the-monoid">Enter the Monoid!</h2>
<p>Monoids in Haskell are defined as this:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Semigroup</span> a <span class="ot">=&gt;</span> <span class="dt">Monoid</span> a <span class="kw">where</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="ot">  mappend ::</span> a <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> a</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>  <span class="fu">mappend</span> <span class="ot">=</span> (<span class="op">&lt;&gt;</span>)</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="ot">  mempty ::</span> a</span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a><span class="ot">  mconcat ::</span> [a] <span class="ot">-&gt;</span> a</span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>  <span class="fu">mconcat</span> <span class="ot">=</span> <span class="fu">foldr</span> <span class="fu">mappend</span> <span class="fu">mempty</span></span></code></pre></div>
<p>One of the first things we can notice, is that every Monoid <strong>has</strong> to have a Semigroup instance, and this is logical because we still want to put things together. In fact, in the following line we already see what we agreed on above, that the funny looking <code>&lt;&gt;</code> is gonna be known as <code>mappend</code> (if you are wondering, the “m” before append stands for Monoid, of course!).</p>
<p>But what makes Monoids special is the next following bit: <code>mempty :: a</code>. Yes, every Monoid NEEDs to have an <code>identity</code>, an element you can <code>mappend</code> to the rest of the elements without changing its intrisic value (this is sometimes also known as the <code>empty</code> case).</p>
<p>Can you think about what this <code>mempty</code> element is for Strings and Lists? 🤔</p>
<p>Of course, the empty list and empty string, respectively!</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> [<span class="dv">1</span><span class="op">,</span> <span class="dv">2</span><span class="op">,</span> <span class="dv">3</span>] <span class="op">++</span> []</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>[<span class="dv">1</span><span class="op">,</span><span class="dv">2</span><span class="op">,</span><span class="dv">3</span>] : <span class="dt">List</span> <span class="fu">number</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> <span class="st">&quot;immutable&quot;</span> <span class="op">++</span> <span class="st">&quot;&quot;</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;immutable&quot;</span> : <span class="dt">String</span></span></code></pre></div>
<p>Notice now the third thing we can see in the definition of Monoids: <code>mconcat :: [a] -&gt; a</code>, this one already has a default value (so we don’t have to provide it, it comes for free by defining <code>mempty</code> and <code>mappend</code>): <code>foldr mappend mempty</code>, we will talk more about this in the last section of the blogpost.</p>
<p>For now, let us focus for a moment in this <code>mconcat</code> function:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="fu">mconcat</span><span class="ot"> ::</span> <span class="dt">Monoid</span> m <span class="ot">=&gt;</span> [m] <span class="ot">-&gt;</span> m</span></code></pre></div>
<p>From our current intuition about this concept, it should be clear to us that, if we have a list of things that we can join (or <code>mappend</code>), we should be able to get out a single thing out with all the things in that <code>List</code> appended, right? (This sounds way too obvious but please bear with me).</p>
<p>Then, let’s search the <a href="https://package.elm-lang.org/packages/elm/core/1.0.5/String#concat"><code>elm/core</code></a> package again for instances of this <code>concat</code> operation:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="fu">concat</span> : <span class="dt">List</span> (<span class="dt">List</span> <span class="fu">a</span>) <span class="op">-&gt;</span> <span class="dt">List</span> <span class="fu">a</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="fu">concat</span> [[<span class="dv">1</span><span class="op">,</span><span class="dv">2</span>]<span class="op">,</span>[<span class="dv">3</span>]<span class="op">,</span>[<span class="dv">4</span><span class="op">,</span><span class="dv">5</span>]] <span class="co">-- -&gt; [1,2,3,4,5]</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a><span class="fu">concat</span> : <span class="dt">List</span> <span class="dt">String</span> <span class="op">-&gt;</span> <span class="dt">String</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a><span class="fu">concat</span> [<span class="st">&quot;never&quot;</span><span class="op">,</span><span class="st">&quot;the&quot;</span><span class="op">,</span><span class="st">&quot;less&quot;</span>] <span class="co">-- -&gt; &quot;nevertheless&quot;</span></span></code></pre></div>
<p>Our usual suspects, <code>List</code> and <code>String</code>… but what happens when we look up <code>empty</code>? 🤔</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="fu">empty</span> : <span class="dt">Array</span> <span class="fu">a</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="fu">empty</span> : <span class="dt">Dict</span> <span class="fu">k</span> <span class="fu">v</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="fu">empty</span> : <span class="dt">Set</span> <span class="fu">a</span></span></code></pre></div>
<p><code>Array</code>, <code>Dict</code> and <code>Set</code> also pop up! The trick here is, for <code>Dict</code> and <code>Set</code> the <code>mappend</code> operation is actually called <a href="https://package.elm-lang.org/packages/elm/core/1.0.5/Dict#union"><code>Dict.union</code></a> and <a href="https://package.elm-lang.org/packages/elm/core/1.0.5/Set#union"><code>Set.union</code></a> respectively!</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="fu">union</span> : <span class="dt">Dict</span> <span class="fu">comparable</span> <span class="fu">v</span> <span class="op">-&gt;</span> <span class="dt">Dict</span> <span class="fu">comparable</span> <span class="fu">v</span> <span class="op">-&gt;</span> <span class="dt">Dict</span> <span class="fu">comparable</span> <span class="fu">v</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="fu">union</span> : <span class="dt">Set</span> <span class="fu">comparable</span> <span class="op">-&gt;</span> <span class="dt">Set</span> <span class="fu">comparable</span> <span class="op">-&gt;</span> <span class="dt">Set</span> <span class="fu">comparable</span></span></code></pre></div>
<p>In fact, there are some <a href="https://github.com/arowM/elm-monoid/blob/1.1.0/src/Monoid.elm">Monoid packages</a> in Elm that reveal us some <strong>really</strong> interesting stuff:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="fu">batch</span> : <span class="dt">List</span> (<span class="dt">Cmd</span> <span class="fu">msg</span>) <span class="op">-&gt;</span> <span class="dt">Cmd</span> <span class="fu">msg</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="fu">batch</span> : <span class="dt">List</span> (<span class="dt">Sub</span> <span class="fu">msg</span>) <span class="op">-&gt;</span> <span class="dt">Sub</span> <span class="fu">msg</span></span></code></pre></div>
<p>Does this remind you of something? Let me refresh your memory:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="fu">mconcat</span><span class="ot"> ::</span> <span class="dt">Monoid</span> m <span class="ot">=&gt;</span> [m] <span class="ot">-&gt;</span> m</span></code></pre></div>
<p>YES! Some everyday used Monoids in Elm include: <code>Array</code>, <code>List</code>, <code>String</code>, <code>Dict</code>, <code>Set</code>, <code>Cmd</code> and <code>Sub</code>… therefore, as always… YOU HAVE BEEN USING MONOIDS ALL ALONG™️!!! 🤯🤯🤯 (Ok this is already part of the trademark by now 🤣).</p>
<h2 id="monoids-for-number-manmicroscope">Monoids for <code>number</code> 👨🏼‍🔬</h2>
<p>If you have a bit of a curious mind, you might notice the following functions in Elm:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> (<span class="op">+</span>)</span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="op">&lt;</span><span class="fu">function</span><span class="op">&gt;</span> : <span class="fu">number</span> <span class="op">-&gt;</span> <span class="fu">number</span> <span class="op">-&gt;</span> <span class="fu">number</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> (<span class="op">*</span>)</span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a><span class="op">&lt;</span><span class="fu">function</span><span class="op">&gt;</span> : <span class="fu">number</span> <span class="op">-&gt;</span> <span class="fu">number</span> <span class="op">-&gt;</span> <span class="fu">number</span></span></code></pre></div>
<p>If you remember from <a href="https://flaviocorpa.com/haskell-for-elm-developers-giving-names-to-stuff-part-1-functors.html">our very first post</a>, <code>number</code> is a typeclass defined for us in Elm with which we can do very little.</p>
<p>Anyway, by looking at the shape of the addition and multiplication operator, we may realise they both match the <code>mappend</code> type signature! This means that for a certain type, <strong>maybe more than one Monoid instance is possible</strong>. This is very relevant, as the <code>mempty</code> for this two Monoids (they are called <code>Sum</code> and <code>Product</code> in Haskell) are different:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> <span class="dv">1</span> <span class="op">+</span> <span class="dv">2</span> <span class="op">+</span> <span class="dv">0</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a><span class="dv">3</span> : <span class="fu">number</span></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> <span class="dv">3</span> <span class="op">*</span> <span class="dv">3</span> <span class="op">*</span> <span class="dv">1</span></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a><span class="dv">9</span> : <span class="fu">number</span></span></code></pre></div>
<p>Yes, the identity value (the one that does not affect the result) for summation is <code>0</code>, whereas for multiplication is <code>1</code>! Math is really interesting, isn’t it!? 🤓</p>
<h2 id="the-secret-behind-every-fold">The Secret Behind EVERY Fold</h2>
<p>But after all this is said and done… why should I bother? Is this just some nerdy terminology??</p>
<p>Well, now comes what was for me one of the most mind-boggling programming moments: have you ever had to reduce (or <code>fold</code>) anything in programming? If so, brace yourself for impact because…</p>
<blockquote>
<p><strong>Behind every folding operation, lies hidden a Monoid instance</strong>!!!</p>
</blockquote>
<p>🤯🤯🤯🤯🤯🤯🤯🤯🤯</p>
<p>Let me give you some time to digest that… remember how earlier we said that we were going to talk a bit more about the fact that <code>mconcat</code> is defined as <code>mconcat = foldr mappend mempty</code>?</p>
<p>I will casually remind you of how <code>foldr</code> is defined in Elm (this also applies to Haskell, of course!):</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="fu">foldr</span> : (<span class="fu">a</span> <span class="op">-&gt;</span> <span class="fu">b</span> <span class="op">-&gt;</span> <span class="fu">b</span>) <span class="op">-&gt;</span> <span class="fu">b</span> <span class="op">-&gt;</span> <span class="dt">List</span> <span class="fu">a</span> <span class="op">-&gt;</span> <span class="fu">b</span></span></code></pre></div>
<p>This means that, every time you are folding <strong>anything</strong>, you need a “reducing” function and and accumulator. The accumulator, if you are following my train of thought, is the <code>mempty</code> value every Monoid has to have. And the “reducing” function (in the case of <code>foldr</code> is <code>(a -&gt; b -&gt; b)</code>), is just a function from <code>a -&gt; b</code> that is also able to concat two <code>b</code>s! (This means that in reality this “reducing” function is effectively like calling <code>fmap</code> and then <code>mconcat</code>).</p>
<p>So, whether you like it or not, every single time in your life that you had to <code>reduce</code> or <code>fold</code> anything in programming, you were using an underlying Monoid all along! ✨🎩🪄</p>
<h2 id="a-brief-word-about-foldmap">A brief word about <code>foldMap</code></h2>
<p>In fact, the relationship between folds and Monoids makes itself super evident in the <a href="https://hackage.haskell.org/package/base-4.20.0.1/docs/Prelude.html#v:foldMap"><code>foldMap</code></a> function that we have available in Haskell (sadly, this is not so common in Elm 😢):</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="fu">foldMap</span><span class="ot"> ::</span> <span class="dt">Monoid</span> m <span class="ot">=&gt;</span> (a <span class="ot">-&gt;</span> m) <span class="ot">-&gt;</span> [a] <span class="ot">-&gt;</span> m</span></code></pre></div>
<p>Since <code>foldMap</code> requires a Monoid instance, this is like folding but in <em>autopilot</em> for us, because the appending function is taken directly from the Monoid instance!</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="fu">foldMap</span> <span class="dt">Sum</span> [<span class="dv">1</span>, <span class="dv">3</span>, <span class="dv">5</span>]</span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Sum</span> {getSum <span class="ot">=</span> <span class="dv">9</span>}</span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="fu">foldMap</span> <span class="dt">Product</span> [<span class="dv">1</span>, <span class="dv">3</span>, <span class="dv">5</span>]</span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Product</span> {getProduct <span class="ot">=</span> <span class="dv">15</span>}</span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="fu">foldMap</span> (<span class="fu">replicate</span> <span class="dv">3</span>) [<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>]</span>
<span id="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a>[<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">2</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">3</span>,<span class="dv">3</span>]</span></code></pre></div>
<p>This is really convenient and can spare you from using <code>foldr</code> or <code>foldl</code> if you know which is the explicit Monoid from which you want to fold on! 🙌🏻</p>
<h2 id="acknowledgements">Acknowledgements</h2>
<p>Special thanks to <a href="https://twitter.com/trupill">@serras</a> for technical proofreading this post again. 🙏🏻</p>
<p>Thanks to all the people who liked and answered to my <a href="https://x.com/FlavioCorpa/status/1823417934578090127">previous tweet</a>, it feels nice to think that you are gonna spend some time pouring your thoughts out and some people might even read it! 😅</p>
<p>Hope you learned something about Semigroups and Monoids, and if you already knew all of this, that at least you enjoyed the ride! 😉</p>
<p>If you found joy in this blogpost and would like me to continue the series, please consider <a href="https://github.com/sponsors/kutyel">sponsoring my work</a>, share it in your social networks and <strong>follow me on <a href="https://twitter.com/FlavioCorpa">Twitter</a>!</strong> 🙌🏻</p></section>
  </article>
</main>

 <footer class="py-14 bg-[var(--footerBgColor)] shrink-0">
  <div class="relative mx-auto md:w-[600px] w-auto px-[1.3125rem]">
    <ul class="flex justify-center list-none" role="list">
      <li class="mx-3" role="listitem">
        <a href="/">Home</a>
      </li>
      <li class="mx-3" role="listitem">
        <a href="https://github.com/sponsors/kutyel/">Sponsor me</a>
      </li>
      <li class="mx-3" role="listitem">
        <a href="/atom.xml">RSS</a>
      </li>
    </ul>
  </div>
</footer>


<script src="https://gistcdn.githack.com/kutyel/41d12e099484fd390fb67168271fcdd9/raw/9be26e500525a2e4edacc53d3a8006aaddec0e15/bsky-comments.js"></script>
]]></description>
    <pubDate>Wed, 14 Aug 2024 15:00:00 UT</pubDate>
    <guid>https://flaviocorpa.com/haskell-for-elm-developers-giving-names-to-stuff-part-5-semigroups-and-monoids.html</guid>
    <dc:creator>Flavio Corpa</dc:creator>
</item>
<item>
    <title>Haskell for Elm developers: giving names to stuff (Part 4 - Parser combinators)</title>
    <link>https://flaviocorpa.com/haskell-for-elm-developers-giving-names-to-stuff-part-4-parser-combinators.html</link>
    <description><![CDATA[<nav class="my-6 py-2">
  <div class="relative mx-auto md:w-[600px] w-auto px-[1.3125rem] md:px-0" data-nav-wrap>
    <a class="mr-5 absolute left-[-10000px] focus:static focus:left-auto" href="#content"
      >Skip to content</a
    >
    <a class="mr-5" href="/">Home</a>
    <a class="mr-5" href="https://github.com/sponsors/kutyel">Sponsor me</a>
    <a class="mr-5" href="/atom.xml">RSS</a>
  </div>
</nav>


<style>
  bsky-comments {
    --background-color: var(--bgColor);
    --text-color: var(--textColor);
    --link-color: var(--textLinkColor);
    --link-hover-color: var(--textLinkHoverColor);
    --comment-meta-color: #888;
    --error-color: #ff4d4d;
    --reply-border-color: var(--separatorColor);
    --button-background-color: var(--btnBgColor);
    --button-hover-background-color: rgba(var(--btnBgColor), 0.2);
    --author-avatar-border-radius: 50%;
  }
</style>

<main class="flex-1" id="content" tabindex="-1">
  <article class="pb-10">
    <header class="bg-[var(--headerBgColor)] mb-8 px-[1.3125rem] md:px-0 py-4 md:py-8">
      <div class="mx-auto md:w-[600px]">
        <h1 class="text-[1.7rem] md:text-[3rem] m-0 mb-4 font-normal leading-[1.2] text-[var(--h1Color)]">
          Haskell for Elm developers: giving names to stuff (Part 4 - Parser combinators)
        </h1>
        <div class="mx-auto md:w-[600px]">
          <small class="italic">28/03/2024</small>
          <small class="italic"> | 10 min read</small>
          
          <small class="italic"> (updated: 03/04/2024 11:15)</small>
          
          <div class="mt-2">[ <a title="All pages tagged &#39;haskell&#39;." href="/tags/haskell.html" rel="tag">haskell</a>, <a title="All pages tagged &#39;elm&#39;." href="/tags/elm.html" rel="tag">elm</a>, <a title="All pages tagged &#39;fp&#39;." href="/tags/fp.html" rel="tag">fp</a> ]</div>
        </div>
      </div>
    </header>
    <section class="mx-auto md:w-[600px] px-[1.3125rem] md:px-0"><p><img src="./images/haskell-elm.svg" alt="logo" width="300px"></p>
<blockquote>
<p>⚠️ DISCLAIMER ⚠️
This is by no means a full in-depth explanation of parser combinators, as there are many papers on the subject. This post assumes you are somewhat familiar with <code>elm/parser</code>, and thus you are equipped with the tools you need to get familiar with parser combinators in Haskell!</p>
</blockquote>
<p>Hey! Long time no see, I’ve finally gathered my inner strength to be brave enough to write this post, yay! 🎉</p>
<p>Even though this might not be a fully complete explanation of parser combinators, as said in the above disclaimer, you might want to have a refresher on what <code>Applicative</code> functors were:</p>
<ul>
<li><a href="https://flaviocorpa.com/haskell-for-elm-developers-giving-names-to-stuff-part-2-applicative-functors.html">Haskell for Elm developers: giving names to stuff (Part 2 - Applicative Functors)</a></li>
</ul>
<p>This will become relevant to this post, as you will soon notice, but first of all, another brief reminder before we get onto the good stuff.</p>
<h2 id="what-is-a-parser">What is a Parser?</h2>
<p>Basically speaking, a <em>parser</em> is a function that takes some text input and returns some <em>structure</em> (normally an Abstract Syntax Tree, aka: AST) as an output. A <em>parser combinator</em> is, thus, a higher-order function that takes parsers as input and returns a new parser as output.</p>
<p>As this definition is better explained with examples, let’s have a look at the simplest possible definition of a parser in Haskell:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">Parser</span> a <span class="ot">=</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> (a, <span class="dt">String</span>)</span></code></pre></div>
<p>Although no <em>production ready</em> parser combinators library would be as naive, it serves well our purpose to understand the simple essence of it:</p>
<ol>
<li>Await a <code>String</code> value.</li>
<li>Produce a result that may or not succeed (that’s why it returns a <code>Maybe</code>, although with this minimalistic design there is no possible way to know why the parser failed).</li>
<li>Return a tuple of the value you want to parse and whatever’s left of the string that you did not consume to produce a value of type <code>a</code>.</li>
</ol>
<p>Some people like to think about parsers as somewhat simple machines that need a <strong>cursor</strong>, and that parse left to right the input and produce results as they traverse the text input, but this illustration might not be so accurate in certain implementations.</p>
<p>For the Haskell curious (which I guess you are since you are reading this post), notice how the above definition of a <code>Parser</code> looks suspiciously familiar to the <code>State</code> monad:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">State</span> s a <span class="ot">=</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>  <span class="dt">State</span> {<span class="ot"> runState ::</span> s <span class="ot">-&gt;</span> (a, s) }</span></code></pre></div>
<p>We could maybe dedicate a following blogpost on its own just to the <code>State</code> monad, but this is out of the scope of this post. Suffice to say that during the research for writing these lines I found that there’s actually a quite nice <a href="https://package.elm-lang.org/packages/folkertdev/elm-state/latest/State">Elm package</a> that implements the <code>State</code> monad! 🤯</p>
<h2 id="how-are-parsers-defined-in-elm">How are parsers defined in Elm?</h2>
<p>Now that we are getting a bit more familiar with the way a parser is constructed, let’s have a look at the <em>de facto</em> only parser library that exists for Elm, <code>elm/parser</code> and see how the <code>Parser</code> type is defined there:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- Parser.Advanced.elm</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">Parser</span> <span class="fu">context</span> <span class="fu">problem</span> <span class="fu">value</span> <span class="op">=</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Parser</span> (<span class="dt">State</span> <span class="fu">context</span> <span class="op">-&gt;</span> <span class="dt">PStep</span> <span class="fu">context</span> <span class="fu">problem</span> <span class="fu">value</span>)</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">PStep</span> <span class="fu">context</span> <span class="fu">problem</span> <span class="fu">value</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>  <span class="op">=</span> <span class="dt">Good</span> <span class="dt">Bool</span> <span class="fu">value</span> (<span class="dt">State</span> <span class="fu">context</span>)</span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">Bad</span> <span class="dt">Bool</span> (<span class="dt">Bag</span> <span class="fu">context</span> <span class="fu">problem</span>)</span></code></pre></div>
<p>If you squint your eyes hard enough, you can see the resemblance. For example, if we strip the <code>context</code> and <code>problem</code> type variables, which are used to give more information to the user about why a certain parser failed, and we simplify the <code>State</code> type that the author used here (not the <code>State</code> monad, do not be confused!), it will look like this:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">Parser</span> <span class="fu">value</span> <span class="op">=</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Parser</span> (<span class="dt">String</span> <span class="op">-&gt;</span> <span class="dt">PStep</span> <span class="fu">value</span>)</span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">PStep</span> <span class="fu">value</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">=</span> <span class="dt">Good</span> <span class="fu">value</span> <span class="dt">String</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">Bad</span> <span class="dt">String</span></span></code></pre></div>
<p>This looks a bit closer to the initial Haskell definition we looked at, and you can therefore now notice that <code>PStep</code> is just a sophisticated version of <code>Maybe</code> that will give you more information in case of failure.</p>
<h2 id="the-hidden-typeclass">The hidden typeclass</h2>
<p>The hidden secret of parser combinators, in my humble opinion, lies in the simple <code>oneOf</code> function:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="fu">oneOf</span> : <span class="dt">List</span> (<span class="dt">Parser</span> <span class="fu">a</span>) <span class="op">-&gt;</span> <span class="dt">Parser</span> <span class="fu">a</span></span></code></pre></div>
<p>When you are parsing stuff, sometimes you are parsing something AND something (that’s when the <code>Applicative</code> typeclass kicks in), but usually you also need to parse something OR something else. This is where the <code>oneOf</code> function comes in handy, for example in the <code>elm/json</code> library you have the following decoding function:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="fu">maybe</span> : <span class="dt">Decoder</span> <span class="fu">a</span> <span class="op">-&gt;</span> <span class="dt">Decoder</span> (<span class="dt">Maybe</span> <span class="fu">a</span>)</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="fu">maybe</span> <span class="fu">decoder</span> <span class="op">=</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>  <span class="fu">oneOf</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>    [ <span class="fu">map</span> <span class="dt">Just</span> <span class="fu">decoder</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">,</span> <span class="fu">succeed</span> <span class="dt">Nothing</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>    ]</span></code></pre></div>
<p>This simple decoder allows us to declare that you might parse something present in your input (or not), and appropriately represent that into a <code>Maybe</code> type. But, how would such combinator look in Haskell? 🤔</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="ot">optional ::</span> <span class="dt">Alternative</span> f <span class="ot">=&gt;</span> f a <span class="ot">-&gt;</span> f (<span class="dt">Maybe</span> a)</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>optional d <span class="ot">=</span> <span class="dt">Just</span> <span class="op">&lt;$&gt;</span> d <span class="op">&lt;|&gt;</span> <span class="fu">pure</span> <span class="dt">Nothing</span></span></code></pre></div>
<p>As you can see, the <code>maybe</code> decoder function is called <code>optional</code> in Haskell, but the interesting stuff is the typeclass constraint: <code>Alternative f =&gt;</code>. This is the magical final piece of the puzzle we need to understand to <em>get</em> parser combinators!</p>
<p>Let’s have a look at simplified version of how the <code>Alternative</code> typeclass is defined in Haskell:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Applicative</span> f <span class="ot">=&gt;</span> <span class="dt">Alternative</span> f <span class="kw">where</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- The identity of &#39;&lt;|&gt;&#39;</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="ot">  empty ::</span> f a</span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- An associative binary operation</span></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a><span class="ot">  (&lt;|&gt;) ::</span> f a <span class="ot">-&gt;</span> f a <span class="ot">-&gt;</span> f a</span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- One or more.</span></span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a><span class="ot">  some ::</span> f a <span class="ot">-&gt;</span> f [a]</span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- Zero or more.</span></span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a><span class="ot">  many ::</span> f a <span class="ot">-&gt;</span> f [a]</span></code></pre></div>
<p>Since <code>some</code> and <code>many</code> are defined in terms of <code>&lt;|&gt;</code>, we can notice quickly that the relevant part is the new <code>&lt;|&gt;</code> operator, which does not have a name but by using the pipe I think it might convey the idea of a lifted OR (<code>|</code>) operator.</p>
<p>So again, where in Elm we can express that we can parse one thing or another as items in a list given to <code>oneOf</code>, in Haskell there is the infix binary operator <code>&lt;|&gt;</code> to define all the possible things we want to parse.</p>
<p>If you also noticed, <code>Alternative</code> requires an <code>Applicative</code> instance to also be present! So, in every possible Haskell implementation of <code>Parser</code>, mandatorily you are going to have this code blow:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Applicative</span> <span class="dt">Parser</span> <span class="kw">where</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- ...</span></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Alternative</span> <span class="dt">Parser</span> <span class="kw">where</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- ...</span></span></code></pre></div>
<p>This is what makes parser combinators work: an <code>Applicative</code> instance, and an <code>Alternative</code> one, that is it! ✨</p>
<h2 id="interesting-aha-moment">Interesting <em>aha!</em> moment</h2>
<p>While scanning though the <code>elm/parser</code> library, you will find this code:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- INFIX OPERATORS</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a><span class="kw">infix</span> <span class="kw">left</span> <span class="dv">5</span> (<span class="op">|=</span>) <span class="op">=</span> <span class="fu">keeper</span></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a><span class="kw">infix</span> <span class="kw">left</span> <span class="dv">6</span> (<span class="op">|.</span>) <span class="op">=</span> <span class="fu">ignorer</span></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a><span class="co">{-| Just like the [`(|=)`](Parser#|=) from the `Parser` module.</span></span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a><span class="co">-}</span></span>
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a><span class="fu">keeper</span> : <span class="dt">Parser</span> <span class="fu">c</span> <span class="fu">x</span> (<span class="fu">a</span> <span class="op">-&gt;</span> <span class="fu">b</span>) <span class="op">-&gt;</span> <span class="dt">Parser</span> <span class="fu">c</span> <span class="fu">x</span> <span class="fu">a</span> <span class="op">-&gt;</span> <span class="dt">Parser</span> <span class="fu">c</span> <span class="fu">x</span> <span class="fu">b</span></span>
<span id="cb10-10"><a href="#cb10-10" aria-hidden="true" tabindex="-1"></a><span class="fu">keeper</span> <span class="fu">parseFunc</span> <span class="fu">parseArg</span> <span class="op">=</span></span>
<span id="cb10-11"><a href="#cb10-11" aria-hidden="true" tabindex="-1"></a>  <span class="fu">map2</span> (<span class="op">&lt;|</span>) <span class="fu">parseFunc</span> <span class="fu">parseArg</span></span>
<span id="cb10-12"><a href="#cb10-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-13"><a href="#cb10-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-14"><a href="#cb10-14" aria-hidden="true" tabindex="-1"></a><span class="co">{-| Just like the [`(|.)`](Parser#|.) from the `Parser` module.</span></span>
<span id="cb10-15"><a href="#cb10-15" aria-hidden="true" tabindex="-1"></a><span class="co">-}</span></span>
<span id="cb10-16"><a href="#cb10-16" aria-hidden="true" tabindex="-1"></a><span class="fu">ignorer</span> : <span class="dt">Parser</span> <span class="fu">c</span> <span class="fu">x</span> <span class="fu">keep</span> <span class="op">-&gt;</span> <span class="dt">Parser</span> <span class="fu">c</span> <span class="fu">x</span> <span class="fu">ignore</span> <span class="op">-&gt;</span> <span class="dt">Parser</span> <span class="fu">c</span> <span class="fu">x</span> <span class="fu">keep</span></span>
<span id="cb10-17"><a href="#cb10-17" aria-hidden="true" tabindex="-1"></a><span class="fu">ignorer</span> <span class="fu">keepParser</span> <span class="fu">ignoreParser</span> <span class="op">=</span></span>
<span id="cb10-18"><a href="#cb10-18" aria-hidden="true" tabindex="-1"></a>  <span class="fu">map2</span> <span class="fu">always</span> <span class="fu">keepParser</span> <span class="fu">ignoreParser</span></span></code></pre></div>
<p>Which is funny, because we CANNOT define infix operators in Elm, but Evan can 😜. Besides that, what is actually interesting is that, for conveniency, it is better to have infix operators for the <code>keeper</code> and <code>ignorer</code> (or the <code>eater</code> operator, as Tereza Sokol called it in <a href="https://youtu.be/M9ulswr1z0E?si=9LyCZ9lX298x2GYQ">her nice talk</a> 🤣) functions that allows us to consume or discard input, because it leads to somewhat more readable code™️.</p>
<p>If we want to find those functions in Haskell, let me confess something right now: I did not show you in the previous <code>Applicative</code> post <strong>all</strong> there is to it regarding applicative functors, you have been lied to! 😈</p>
<p>Here is the complete definition of the <code>Applicative</code> typeclass:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> (<span class="dt">Functor</span> f) <span class="ot">=&gt;</span> <span class="dt">Applicative</span> f <span class="kw">where</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>  <span class="ot">{-# MINIMAL pure, ((&lt;*&gt;) | liftA2) #-}</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- | Lift a value.</span></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a><span class="ot">  pure ::</span> a <span class="ot">-&gt;</span> f a</span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- | Sequential application.</span></span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a><span class="ot">  (&lt;*&gt;) ::</span> f (a <span class="ot">-&gt;</span> b) <span class="ot">-&gt;</span> f a <span class="ot">-&gt;</span> f b</span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a>  (<span class="op">&lt;*&gt;</span>) <span class="ot">=</span> liftA2 <span class="fu">id</span></span>
<span id="cb11-10"><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-11"><a href="#cb11-11" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- | Lift a binary function to actions.</span></span>
<span id="cb11-12"><a href="#cb11-12" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- ==== __Example__</span></span>
<span id="cb11-13"><a href="#cb11-13" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- &gt;&gt;&gt; liftA2 (,) (Just 3) (Just 5)</span></span>
<span id="cb11-14"><a href="#cb11-14" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- Just (3,5)</span></span>
<span id="cb11-15"><a href="#cb11-15" aria-hidden="true" tabindex="-1"></a><span class="ot">  liftA2 ::</span> (a <span class="ot">-&gt;</span> b <span class="ot">-&gt;</span> c) <span class="ot">-&gt;</span> f a <span class="ot">-&gt;</span> f b <span class="ot">-&gt;</span> f c</span>
<span id="cb11-16"><a href="#cb11-16" aria-hidden="true" tabindex="-1"></a>  liftA2 f x <span class="ot">=</span> (<span class="op">&lt;*&gt;</span>) (<span class="fu">fmap</span> f x)</span>
<span id="cb11-17"><a href="#cb11-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-18"><a href="#cb11-18" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- | Sequence actions, discarding the value of the first argument.</span></span>
<span id="cb11-19"><a href="#cb11-19" aria-hidden="true" tabindex="-1"></a>  <span class="co">--</span></span>
<span id="cb11-20"><a href="#cb11-20" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- ==== __Examples__</span></span>
<span id="cb11-21"><a href="#cb11-21" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- If used in conjunction with the Applicative instance for &#39;Maybe&#39;,</span></span>
<span id="cb11-22"><a href="#cb11-22" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- you can chain Maybe computations, with a possible &quot;early return&quot;</span></span>
<span id="cb11-23"><a href="#cb11-23" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- in case of &#39;Nothing&#39;.</span></span>
<span id="cb11-24"><a href="#cb11-24" aria-hidden="true" tabindex="-1"></a>  <span class="co">--</span></span>
<span id="cb11-25"><a href="#cb11-25" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- &gt;&gt;&gt; Just 2 *&gt; Just 3</span></span>
<span id="cb11-26"><a href="#cb11-26" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- Just 3</span></span>
<span id="cb11-27"><a href="#cb11-27" aria-hidden="true" tabindex="-1"></a>  <span class="co">--</span></span>
<span id="cb11-28"><a href="#cb11-28" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- &gt;&gt;&gt; Nothing *&gt; Just 3</span></span>
<span id="cb11-29"><a href="#cb11-29" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- Nothing</span></span>
<span id="cb11-30"><a href="#cb11-30" aria-hidden="true" tabindex="-1"></a><span class="ot">  (*&gt;) ::</span> f a <span class="ot">-&gt;</span> f b <span class="ot">-&gt;</span> f b</span>
<span id="cb11-31"><a href="#cb11-31" aria-hidden="true" tabindex="-1"></a>  a1 <span class="op">*&gt;</span> a2 <span class="ot">=</span> (<span class="fu">id</span> <span class="op">&lt;$</span> a1) <span class="op">&lt;*&gt;</span> a2</span>
<span id="cb11-32"><a href="#cb11-32" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-33"><a href="#cb11-33" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- | Sequence actions, discarding the value of the second argument.</span></span>
<span id="cb11-34"><a href="#cb11-34" aria-hidden="true" tabindex="-1"></a><span class="ot">  (&lt;*) ::</span> f a <span class="ot">-&gt;</span> f b <span class="ot">-&gt;</span> f a</span>
<span id="cb11-35"><a href="#cb11-35" aria-hidden="true" tabindex="-1"></a>  (<span class="op">&lt;*</span>) <span class="ot">=</span> liftA2 <span class="fu">const</span></span></code></pre></div>
<p>In case you did not notice, lets have the type signatures side by side now:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="ot">(&lt;*&gt;) ::</span> f (a <span class="ot">-&gt;</span> b)          <span class="ot">-&gt;</span> f a          <span class="ot">-&gt;</span> f b</span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>(<span class="op">|=</span>)  <span class="op">:</span> <span class="dt">Parser</span> c x (a <span class="ot">-&gt;</span> b)  <span class="ot">-&gt;</span> <span class="dt">Parser</span> c x a <span class="ot">-&gt;</span> <span class="dt">Parser</span> c x b</span></code></pre></div>
<p>and…</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="ot">(&lt;*) ::</span> f keep         <span class="ot">-&gt;</span> f ignore          <span class="ot">-&gt;</span> f keep</span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>(<span class="op">|.</span>) <span class="op">:</span> <span class="dt">Parser</span> c x keep <span class="ot">-&gt;</span> <span class="dt">Parser</span> c x ignore <span class="ot">-&gt;</span> <span class="dt">Parser</span> c x keep</span></code></pre></div>
<p>So this means that the <code>&lt;*</code> and the <code>&lt;*&gt;</code> operators are, respectively, the <code>ignorer</code> and <code>keeper</code> functions from <code>elm/parser</code>!! 🤯🤯🤯</p>
<p>What about the <code>*&gt;</code> operator? Well, as you know, in Haskell we have this massive operator overflow, so it is exactly the same as <code>&lt;*</code> but it let’s us ignore the argument to the <em>left</em> of the operator, as we will now see in a REAL WORLD™️ parser code sample. 😉</p>
<h2 id="a-real-worldtm-haskell-parser-example">A real world™️ Haskell parser example</h2>
<p>To make sure we actually learned something about parser combinators in this post, let’s have a look at a portion of my <a href="https://github.com/higherkindness/avro-parser-haskell"><code>language-avro</code></a> Haskell library:</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- | Parses a single import into the &#39;ImportType&#39; structure.</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="ot">parseImport ::</span> <span class="dt">MonadParsec</span> <span class="dt">Char</span> <span class="dt">T.Text</span> m <span class="ot">=&gt;</span> m <span class="dt">ImportType</span></span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a>parseImport <span class="ot">=</span></span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a>  reserved <span class="st">&quot;import&quot;</span></span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">*&gt;</span> ( (impHelper <span class="dt">IdlImport</span> <span class="st">&quot;idl&quot;</span> <span class="op">&lt;?&gt;</span> <span class="st">&quot;Import of type IDL&quot;</span>)</span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a>           <span class="op">&lt;|&gt;</span> (impHelper <span class="dt">ProtocolImport</span> <span class="st">&quot;protocol&quot;</span> <span class="op">&lt;?&gt;</span> <span class="st">&quot;Import of type protocol&quot;</span>)</span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a>           <span class="op">&lt;|&gt;</span> (impHelper <span class="dt">SchemaImport</span> <span class="st">&quot;schema&quot;</span> <span class="op">&lt;?&gt;</span> <span class="st">&quot;Import of type schema&quot;</span>)</span>
<span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a>       )</span>
<span id="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb14-10"><a href="#cb14-10" aria-hidden="true" tabindex="-1"></a><span class="ot">    impHelper ::</span> <span class="dt">MonadParsec</span> <span class="dt">Char</span> <span class="dt">T.Text</span> m <span class="ot">=&gt;</span> (<span class="dt">T.Text</span> <span class="ot">-&gt;</span> a) <span class="ot">-&gt;</span> <span class="dt">T.Text</span> <span class="ot">-&gt;</span> m a</span>
<span id="cb14-11"><a href="#cb14-11" aria-hidden="true" tabindex="-1"></a>    impHelper ct t <span class="ot">=</span> ct <span class="op">&lt;$&gt;</span> (reserved t <span class="op">*&gt;</span> strlit <span class="op">&lt;*</span> symbol <span class="st">&quot;;&quot;</span>)</span></code></pre></div>
<blockquote>
<p>If you are curious regarding how such a parser would look with other libraries (like <code>trifecta</code>), you can have a look at <a href="https://github.com/kutyel/haskell-kata/commit/bde30daf28718eda7f35b22325a07ce29f8e9882">this code</a>, which is surprisingly similar to Elm!</p>
</blockquote>
<p>Before you freak out, let me explain to you what this piece of code is trying to parse: in the <a href="https://avro.apache.org/docs/1.11.1/idl-language/#imports">Avro IDL language</a> (which is used for example, in <a href="https://kafka.apache.org/">Kafka</a>), you can define imports of 3 different types:</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode protobuf"><code class="sourceCode protobuf"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> idl <span class="st">&quot;foo.avdl&quot;</span>;</span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> protocol <span class="st">&quot;foo.avpr&quot;</span>;</span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> schema <span class="st">&quot;foo.avsc&quot;</span>;</span></code></pre></div>
<p>To represent this in Haskell, first we need a data type that we want our parser to return:</p>
<div class="sourceCode" id="cb16"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- | Type for the possible import types in &#39;Protocol&#39;.</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">ImportType</span></span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a>  <span class="ot">=</span> <span class="dt">IdlImport</span> <span class="dt">T.Text</span></span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">ProtocolImport</span> <span class="dt">T.Text</span></span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">SchemaImport</span> <span class="dt">T.Text</span></span>
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Eq</span>, <span class="dt">Show</span>, <span class="dt">Ord</span>)</span></code></pre></div>
<p>And now we can proceed with the parsing stuff, you will notice a few interesting things</p>
<ol>
<li>There is a strange <code>reserved</code> combinator, which is a user defined combinator that is pretty clever and has the notion of comments/whitespace.</li>
<li>Similarly, <code>strlit</code> is also user defined and it helps us to parse string literals.</li>
<li>What the hell is <code>&lt;?&gt;</code> ?? Another crazy operator?? Well, do not worry, it is just to give proper error messages when the parser get’s stuck, the Elm equivalent would be the <code>problem : String -&gt; Parser a</code> function. 😉</li>
<li>What is that scary <code>MonadParsec Char T.Text m =&gt; m</code> typeclass constrain? Well, I would gladly read that as just <code>Parser</code> in the example we were giving before, but since in my package I used the <a href="https://hackage.haskell.org/package/megaparsec"><code>megaparsec</code></a> library, I did not want to lie to you again and show you the real type of the parser (more on <code>megaparsec</code> later).</li>
</ol>
<p>Here is a similar parser, written with <code>elm/parser</code> as a reference!</p>
<div class="sourceCode" id="cb17"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Parser</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">exposing</span></span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a>        ( (<span class="op">|.</span>)</span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a>        <span class="op">,</span> (<span class="op">|=</span>)</span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a>        <span class="op">,</span> <span class="dt">Parser</span></span>
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a>        <span class="op">,</span> <span class="fu">chompIf</span></span>
<span id="cb17-7"><a href="#cb17-7" aria-hidden="true" tabindex="-1"></a>        <span class="op">,</span> <span class="fu">chompWhile</span></span>
<span id="cb17-8"><a href="#cb17-8" aria-hidden="true" tabindex="-1"></a>        <span class="op">,</span> <span class="fu">getChompedString</span></span>
<span id="cb17-9"><a href="#cb17-9" aria-hidden="true" tabindex="-1"></a>        <span class="op">,</span> <span class="fu">oneOf</span></span>
<span id="cb17-10"><a href="#cb17-10" aria-hidden="true" tabindex="-1"></a>        <span class="op">,</span> <span class="fu">spaces</span></span>
<span id="cb17-11"><a href="#cb17-11" aria-hidden="true" tabindex="-1"></a>        <span class="op">,</span> <span class="fu">succeed</span></span>
<span id="cb17-12"><a href="#cb17-12" aria-hidden="true" tabindex="-1"></a>        <span class="op">,</span> <span class="fu">symbol</span></span>
<span id="cb17-13"><a href="#cb17-13" aria-hidden="true" tabindex="-1"></a>        )</span>
<span id="cb17-14"><a href="#cb17-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-15"><a href="#cb17-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-16"><a href="#cb17-16" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">Import</span></span>
<span id="cb17-17"><a href="#cb17-17" aria-hidden="true" tabindex="-1"></a>    <span class="op">=</span> <span class="dt">Idl</span> <span class="dt">String</span></span>
<span id="cb17-18"><a href="#cb17-18" aria-hidden="true" tabindex="-1"></a>    <span class="op">|</span> <span class="dt">Protocol</span> <span class="dt">String</span></span>
<span id="cb17-19"><a href="#cb17-19" aria-hidden="true" tabindex="-1"></a>    <span class="op">|</span> <span class="dt">Schema</span> <span class="dt">String</span></span>
<span id="cb17-20"><a href="#cb17-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-21"><a href="#cb17-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-22"><a href="#cb17-22" aria-hidden="true" tabindex="-1"></a><span class="fu">parser</span> : <span class="dt">Parser</span> <span class="dt">Import</span></span>
<span id="cb17-23"><a href="#cb17-23" aria-hidden="true" tabindex="-1"></a><span class="fu">parser</span> <span class="op">=</span></span>
<span id="cb17-24"><a href="#cb17-24" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span></span>
<span id="cb17-25"><a href="#cb17-25" aria-hidden="true" tabindex="-1"></a>        <span class="fu">importHelper</span> :</span>
<span id="cb17-26"><a href="#cb17-26" aria-hidden="true" tabindex="-1"></a>            (<span class="dt">String</span> <span class="op">-&gt;</span> <span class="dt">Import</span>)</span>
<span id="cb17-27"><a href="#cb17-27" aria-hidden="true" tabindex="-1"></a>            <span class="op">-&gt;</span> <span class="dt">String</span></span>
<span id="cb17-28"><a href="#cb17-28" aria-hidden="true" tabindex="-1"></a>            <span class="op">-&gt;</span> <span class="dt">Parser</span> <span class="dt">Import</span></span>
<span id="cb17-29"><a href="#cb17-29" aria-hidden="true" tabindex="-1"></a>        <span class="fu">importHelper</span> <span class="fu">ct</span> <span class="fu">t</span> <span class="op">=</span></span>
<span id="cb17-30"><a href="#cb17-30" aria-hidden="true" tabindex="-1"></a>            <span class="fu">succeed</span> <span class="fu">ct</span></span>
<span id="cb17-31"><a href="#cb17-31" aria-hidden="true" tabindex="-1"></a>                <span class="op">|.</span> <span class="fu">symbol</span> <span class="fu">t</span></span>
<span id="cb17-32"><a href="#cb17-32" aria-hidden="true" tabindex="-1"></a>                <span class="op">|.</span> <span class="fu">spaces</span></span>
<span id="cb17-33"><a href="#cb17-33" aria-hidden="true" tabindex="-1"></a>                <span class="op">|=</span> <span class="fu">strlit</span></span>
<span id="cb17-34"><a href="#cb17-34" aria-hidden="true" tabindex="-1"></a>                <span class="op">|.</span> <span class="fu">symbol</span> <span class="st">&quot;;&quot;</span></span>
<span id="cb17-35"><a href="#cb17-35" aria-hidden="true" tabindex="-1"></a>    <span class="kw">in</span></span>
<span id="cb17-36"><a href="#cb17-36" aria-hidden="true" tabindex="-1"></a>    <span class="fu">succeed</span> <span class="fu">identity</span></span>
<span id="cb17-37"><a href="#cb17-37" aria-hidden="true" tabindex="-1"></a>        <span class="op">|.</span> <span class="fu">symbol</span> <span class="st">&quot;import&quot;</span></span>
<span id="cb17-38"><a href="#cb17-38" aria-hidden="true" tabindex="-1"></a>        <span class="op">|.</span> <span class="fu">spaces</span></span>
<span id="cb17-39"><a href="#cb17-39" aria-hidden="true" tabindex="-1"></a>        <span class="op">|=</span> <span class="fu">oneOf</span></span>
<span id="cb17-40"><a href="#cb17-40" aria-hidden="true" tabindex="-1"></a>            [ <span class="fu">importHelper</span> <span class="dt">Idl</span> <span class="st">&quot;idl&quot;</span></span>
<span id="cb17-41"><a href="#cb17-41" aria-hidden="true" tabindex="-1"></a>            <span class="op">,</span> <span class="fu">importHelper</span> <span class="dt">Protocol</span> <span class="st">&quot;protocol&quot;</span></span>
<span id="cb17-42"><a href="#cb17-42" aria-hidden="true" tabindex="-1"></a>            <span class="op">,</span> <span class="fu">importHelper</span> <span class="dt">Schema</span> <span class="st">&quot;schema&quot;</span></span>
<span id="cb17-43"><a href="#cb17-43" aria-hidden="true" tabindex="-1"></a>            ]</span>
<span id="cb17-44"><a href="#cb17-44" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-45"><a href="#cb17-45" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-46"><a href="#cb17-46" aria-hidden="true" tabindex="-1"></a><span class="fu">strlit</span> : <span class="dt">Parser</span> <span class="dt">String</span></span>
<span id="cb17-47"><a href="#cb17-47" aria-hidden="true" tabindex="-1"></a><span class="fu">strlit</span> <span class="op">=</span></span>
<span id="cb17-48"><a href="#cb17-48" aria-hidden="true" tabindex="-1"></a>    <span class="fu">getChompedString</span> <span class="op">&lt;|</span></span>
<span id="cb17-49"><a href="#cb17-49" aria-hidden="true" tabindex="-1"></a>        <span class="fu">succeed</span> ()</span>
<span id="cb17-50"><a href="#cb17-50" aria-hidden="true" tabindex="-1"></a>            <span class="op">|.</span> <span class="fu">chompIf</span> (\<span class="fu">c</span> <span class="op">-&gt;</span> <span class="fu">c</span> <span class="op">==</span> <span class="ch">&#39;&quot;&#39;</span>)</span>
<span id="cb17-51"><a href="#cb17-51" aria-hidden="true" tabindex="-1"></a>            <span class="op">|.</span> <span class="fu">chompWhile</span> <span class="dt">Char</span><span class="op">.</span><span class="fu">isLower</span></span>
<span id="cb17-52"><a href="#cb17-52" aria-hidden="true" tabindex="-1"></a>            <span class="op">|.</span> <span class="fu">chompIf</span> (\<span class="fu">c</span> <span class="op">-&gt;</span> <span class="fu">c</span> <span class="op">==</span> <span class="ch">&#39;.&#39;</span>)</span>
<span id="cb17-53"><a href="#cb17-53" aria-hidden="true" tabindex="-1"></a>            <span class="op">|.</span> <span class="fu">chompWhile</span> <span class="dt">Char</span><span class="op">.</span><span class="fu">isLower</span></span>
<span id="cb17-54"><a href="#cb17-54" aria-hidden="true" tabindex="-1"></a>            <span class="op">|.</span> <span class="fu">chompIf</span> (\<span class="fu">c</span> <span class="op">-&gt;</span> <span class="fu">c</span> <span class="op">==</span> <span class="ch">&#39;&quot;&#39;</span>)</span>
<span id="cb17-55"><a href="#cb17-55" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-56"><a href="#cb17-56" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-57"><a href="#cb17-57" aria-hidden="true" tabindex="-1"></a><span class="fu">output</span> <span class="op">=</span></span>
<span id="cb17-58"><a href="#cb17-58" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Parser</span><span class="op">.</span><span class="fu">run</span> <span class="fu">parser</span> <span class="st">&quot;import protocol \&quot;foo.avpr\&quot;;&quot;</span></span>
<span id="cb17-59"><a href="#cb17-59" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- &gt; Ok (Protocol &quot;\&quot;foo.avpr\&quot;&quot;)</span></span></code></pre></div>
<p>As you can see, the code is fairly similar, we only used the <code>oneOf</code> instead of the <code>&lt;|&gt;</code> operator, and the only complicated thing in Elm was figuring out how our <code>strlit</code> combinator had to look like. (Obviously this implementation is not perfect, but it is good enough for educational purposes).</p>
<p>If you were able to understand the above Haskell code, congratulations, you know parser combinators already! 🎉🎉🎉</p>
<h2 id="the-state-of-parsers-in-the-haskell-ecosystem">The state of parsers in the Haskell ecosystem</h2>
<p>As opposed to Elm, where there is only one choice (<code>elm/parser</code>), the Haskell ecosystem is much more rich and diverse, each one with their different tradeoffs. Here is an <em>incomplete list</em> of parser combinator libraries I’m aware of:</p>
<ul>
<li>Parsec</li>
<li>Trifecta</li>
<li>Attoparsec</li>
<li>Megaparsec</li>
<li>Earley</li>
<li>… (many, many more!!)</li>
</ul>
<p>The only one I’ve used in production and am a bit more familiar with is <code>megaparsec</code>, and I learned a lot regarding how to use it from <a href="https://markkarpov.com/tutorial/megaparsec.html">Mark Karpov excellent’s blogpost</a>. I really recommend it since it is quite performant and it has some really nice and smart combinators that will spare you a ton of work.</p>
<h2 id="acknowledgements">Acknowledgements</h2>
<p>Special thanks to <a href="https://twitter.com/trupill">@serras</a> for technical proofreading this post again. 🙏🏻</p>
<p>Hope <code>Parser</code> combinators finally clicked for you ✨ (if they had not already) and you learned something new. Ah! And in case you did not notice…</p>
<blockquote>
<p>JSON Decoders are actually parser combinators! 🤯🤯🤯</p>
</blockquote>
<p>So, as always, if you were doing JSON Decoders you were using parser combinators all along without noticing it! 😁</p>
<p>If you enjoyed this post and would like me to continue the series, please consider <a href="https://github.com/sponsors/kutyel">sponsoring my work</a>, share it in your social networks and <strong>follow me on <a href="https://twitter.com/FlavioCorpa">Twitter</a>!</strong> 🙌🏻</p></section>
  </article>
</main>

 <footer class="py-14 bg-[var(--footerBgColor)] shrink-0">
  <div class="relative mx-auto md:w-[600px] w-auto px-[1.3125rem]">
    <ul class="flex justify-center list-none" role="list">
      <li class="mx-3" role="listitem">
        <a href="/">Home</a>
      </li>
      <li class="mx-3" role="listitem">
        <a href="https://github.com/sponsors/kutyel/">Sponsor me</a>
      </li>
      <li class="mx-3" role="listitem">
        <a href="/atom.xml">RSS</a>
      </li>
    </ul>
  </div>
</footer>


<script src="https://gistcdn.githack.com/kutyel/41d12e099484fd390fb67168271fcdd9/raw/9be26e500525a2e4edacc53d3a8006aaddec0e15/bsky-comments.js"></script>
]]></description>
    <pubDate>Thu, 28 Mar 2024 17:00:00 UT</pubDate>
    <guid>https://flaviocorpa.com/haskell-for-elm-developers-giving-names-to-stuff-part-4-parser-combinators.html</guid>
    <dc:creator>Flavio Corpa</dc:creator>
</item>
<item>
    <title>Do you even Effect.ap, bro?</title>
    <link>https://flaviocorpa.com/do-you-even-effect-ap-bro.html</link>
    <description><![CDATA[<nav class="my-6 py-2">
  <div class="relative mx-auto md:w-[600px] w-auto px-[1.3125rem] md:px-0" data-nav-wrap>
    <a class="mr-5 absolute left-[-10000px] focus:static focus:left-auto" href="#content"
      >Skip to content</a
    >
    <a class="mr-5" href="/">Home</a>
    <a class="mr-5" href="https://github.com/sponsors/kutyel">Sponsor me</a>
    <a class="mr-5" href="/atom.xml">RSS</a>
  </div>
</nav>


<style>
  bsky-comments {
    --background-color: var(--bgColor);
    --text-color: var(--textColor);
    --link-color: var(--textLinkColor);
    --link-hover-color: var(--textLinkHoverColor);
    --comment-meta-color: #888;
    --error-color: #ff4d4d;
    --reply-border-color: var(--separatorColor);
    --button-background-color: var(--btnBgColor);
    --button-hover-background-color: rgba(var(--btnBgColor), 0.2);
    --author-avatar-border-radius: 50%;
  }
</style>

<main class="flex-1" id="content" tabindex="-1">
  <article class="pb-10">
    <header class="bg-[var(--headerBgColor)] mb-8 px-[1.3125rem] md:px-0 py-4 md:py-8">
      <div class="mx-auto md:w-[600px]">
        <h1 class="text-[1.7rem] md:text-[3rem] m-0 mb-4 font-normal leading-[1.2] text-[var(--h1Color)]">
          Do you even Effect.ap, bro?
        </h1>
        <div class="mx-auto md:w-[600px]">
          <small class="italic">17/11/2023</small>
          <small class="italic"> | 4 min read</small>
          
          <div class="mt-2">[ <a title="All pages tagged &#39;web&#39;." href="/tags/web.html" rel="tag">web</a>, <a title="All pages tagged &#39;typescript&#39;." href="/tags/typescript.html" rel="tag">typescript</a>, <a title="All pages tagged &#39;fp&#39;." href="/tags/fp.html" rel="tag">fp</a>, <a title="All pages tagged &#39;effect-ts&#39;." href="/tags/effect-ts.html" rel="tag">effect-ts</a> ]</div>
        </div>
      </div>
    </header>
    <section class="mx-auto md:w-[600px] px-[1.3125rem] md:px-0"><p><img src="./images/Effect.png" alt="effect-ts" width="400px"></p>
<p>After my last functional programming workshop in React Alicante 2023, I got a fair complain: <em>“Why aren’t we doing this in TypeScript”?</em>. And the reason was simple: a few years ago, there was <strong>no clear improvement over <a href="https://ramdajs.com/">Ramda</a> and <a href="https://crocks.dev">Crocks</a> for JavaScript</strong>. These libraries worked great and provided everything I needed for a pleasant functional programming experience: function composition, currying and data-last, unary functions that I could compose easily, to give you a sample snippet:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode js"><code class="sourceCode javascript"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="co">// getStreetName :: User -&gt; Maybe String</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> getStreetName <span class="op">=</span> <span class="fu">compose</span>(</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>    <span class="fu">chain</span>(<span class="fu">getProp</span>(<span class="st">&#39;name&#39;</span>))<span class="op">,</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>    <span class="fu">chain</span>(<span class="fu">getProp</span>(<span class="st">&#39;street&#39;</span>))<span class="op">,</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>    <span class="fu">getProp</span>(<span class="st">&#39;address&#39;</span>)</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>  )</span></code></pre></div>
<p>However, it is hard enough to explain functional concepts, so the added complexity for the students of having to compile this operations in their heads (not being used to them) and receiving no help from their editor whatsoever made it a fair complain. So, I made up my mind, I was going to rewrite my <a href="https://github.com/kutyel/fpjs-workshop">workshop repo exercises</a> into TypeScript! 🚀</p>
<h2 id="historical-issues-with-fp-in-typescript">Historical issues with FP in TypeScript</h2>
<p>However, there was a tiny little issue: all typings for Ramda and Crocks for TypeScript are <strong>utterly broken</strong>. Those libraries were designed to work in JavaScript, and never had TypeScript in mind. For example, curried functions in general <a href="https://discord.com/channels/795981131316985866/1159080096339087390/1159094255822843904">mess up with TypeScript’s type inference</a>, which is tree based, and a function like <a href="https://ramdajs.com/docs/#curry"><code>curry</code></a> itself would be virtually impossible to represent in TypeScript.</p>
<p>Furthermore, I needed a library like Crocks, that provided me the data structures and ADTs (Algebraic Data Types) that I am used to and that was thought from the ground up to work with TypeScript and made it shine. And that is when I decided to finally try out <a href="https://effect.website/">Effect.ts</a>!</p>
<h2 id="enter-effectts">Enter <code>Effect.ts</code></h2>
<p>After watching a couple of <a href="https://youtu.be/fTN8BX5qj6s?si=wEXoaqvUgtBPhmJi">videos on YouTube</a>, reading a few Twitter threads and <a href="https://discord.com/channels/795981131316985866/1159105251685711963">asking some questions on their Discord</a> (which is really friendly btw), I managed to convert my exercises successfully to TypeScript and to solve them in really elegant ways:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode ts"><code class="sourceCode typescript"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> register <span class="op">=</span> (name<span class="op">:</span> <span class="dt">string</span>)<span class="op">:</span> Effect<span class="op">.</span><span class="at">Effect</span><span class="op">&lt;</span><span class="dt">never</span><span class="op">,</span> <span class="dt">never</span><span class="op">,</span> <span class="dt">string</span><span class="op">&gt;</span> <span class="kw">=&gt;</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>  <span class="fu">pipe</span>(</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>    <span class="fu">validateName</span>(name)<span class="op">,</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>    Effect<span class="op">.</span><span class="fu">flatMap</span>(save)<span class="op">,</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>    Effect<span class="op">.</span><span class="fu">match</span>({</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>      onFailure<span class="op">:</span> (error) <span class="kw">=&gt;</span> <span class="vs">`Failure: </span><span class="sc">${</span>error<span class="sc">}</span><span class="vs">`</span><span class="op">,</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>      onSuccess<span class="op">:</span> (user) <span class="kw">=&gt;</span> <span class="vs">`Success: </span><span class="sc">${</span>user<span class="op">.</span><span class="at">name</span><span class="sc">}</span><span class="vs"> saved!`</span><span class="op">,</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>    })</span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>  )</span></code></pre></div>
<p>The overall concept of Effect is quite easy to grasp, it is really well explained with amazing documentation and it is very powerful at its core. The only thing I needed to get used to is that <strong>the <code>pipe</code> function needs to receive as the first argument the data itself, instead of only a succession of curried functions</strong>. This single detail pleases the TypeScript compiler (type inference can now work nicely) and allows me to keep focusing on writing my declarative functions the way I want to! 💯</p>
<h2 id="do-you-even-lift-bro">Do you even <code>lift</code>, bro?</h2>
<p>Everything was fine and dandy until I reached the exercises with Applicative Functors and I found <a href="https://github.com/Effect-TS/effect/issues/1502">one issue</a> with the library: there was no <code>ap</code> method in the <code>Effect</code> type, nor in the <code>Either</code> type. I <a href="https://discord.com/channels/795981131316985866/1125094089281511474/threads/1160871851631849532">asked this on their discord</a> and it was agreed that those functions were missing, so I decided to <a href="https://github.com/Effect-TS/effect/pull/1504">contribute them</a>, as you can see by the headline image of this blogpost. 😉</p>
<p>The funny thing about this is that there were other ways to solve this exercise, for example, the <code>Effect.all</code> function:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode ts"><code class="sourceCode typescript"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> renderAllDOM<span class="op">:</span> Effect<span class="op">.</span><span class="at">Effect</span><span class="op">&lt;</span><span class="dt">never</span><span class="op">,</span> <span class="dt">never</span><span class="op">,</span> <span class="dt">string</span><span class="op">&gt;</span> <span class="op">=</span> Effect<span class="op">.</span><span class="fu">all</span>([</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>  <span class="fu">getPost</span>(<span class="dv">1</span>)<span class="op">,</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>  <span class="fu">getComments</span>(<span class="dv">1</span>)<span class="op">,</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>])<span class="op">.</span><span class="fu">pipe</span>(Effect<span class="op">.</span><span class="fu">map</span>(renderAll))</span></code></pre></div>
<p>And even another syntactical choice is offered to the Effect user: using <strong>async generators</strong> to emulate Haskell’s <code>do-notation</code>! 🤯</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode ts"><code class="sourceCode typescript"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> renderGenDOM <span class="op">=</span> Effect<span class="op">.</span><span class="fu">gen</span>(<span class="kw">function</span><span class="op">*</span> (_) {</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> posts <span class="op">=</span> <span class="kw">yield</span><span class="op">*</span> <span class="fu">_</span>(<span class="fu">getPost</span>(<span class="dv">1</span>))</span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> comments <span class="op">=</span> <span class="kw">yield</span><span class="op">*</span> <span class="fu">_</span>(<span class="fu">getComments</span>(<span class="dv">1</span>))</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> <span class="fu">renderAll</span>([posts<span class="op">,</span> comments])</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>})</span></code></pre></div>
<p>What this means is that, obviously, the <code>Effect</code> and <code>Either</code> types <strong>were already valid Applicative Functors</strong>, they were just missing a specific operator to made the code a <em>bit more familiar</em> to functional programmers coming from Haskell like myself. The same code, using the classic <code>ap</code> operator, would be like the following:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode ts"><code class="sourceCode typescript"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> renderDOM<span class="op">:</span> Effect<span class="op">.</span><span class="at">Effect</span><span class="op">&lt;</span><span class="dt">never</span><span class="op">,</span> <span class="dt">never</span><span class="op">,</span> <span class="dt">string</span><span class="op">&gt;</span> <span class="op">=</span> <span class="fu">pipe</span>(</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>  Effect<span class="op">.</span><span class="fu">succeed</span>(render)<span class="op">,</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>  Effect<span class="op">.</span><span class="fu">ap</span>(<span class="fu">getPost</span>(<span class="dv">1</span>))<span class="op">,</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>  Effect<span class="op">.</span><span class="fu">ap</span>(<span class="fu">getComments</span>(<span class="dv">1</span>))</span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>)</span></code></pre></div>
<p>Which style to go for is a matter of personal preference, but I’m glad my contribution to the library made this choice also available. 😊</p>
<h2 id="effectts-vs-fp-ts"><code>Effect.ts</code> vs <code>fp-ts</code></h2>
<p>Every time I tried applying what I knew about FP from Ramda/JS to TypeScript, I always felt I was out of my comfort zone. I never quite understood fully <code>fp-ts</code>, since it was <strong>heavily inspired by Scala</strong> and I learnt functional programming in Haskell. This might sound silly and appear to be a trivial difference, but it is not, at least for the way my brain was wired. 🧠</p>
<p>On the contrary, Effect seemed to be very simple to understand in principle and everything felt like pieces of a puzzle 🧩 fitting together and playing along very nicely with the subtleties of TypeScript, like, type inference sort of keeps working (<em>with some exceptional footguns</em>) and currying and function composition work reasonably well, and that is amazing!</p>
<p>Also, having the incredible <a href="https://twitter.com/GiulioCanti">@gcanti</a> on board the <code>Effect.ts</code> train, is not only a good sign (<em>he was absolutely kind and helpful both on Github and Discord</em>), but it is a clear correct step in the right direction for functional programming in TypeScript!</p>
<h2 id="conclusion">Conclusion</h2>
<p>With my existing knowledge of functional programming concepts, it took me <em>less than a week</em> (‼️) to learn the basics of <code>Effect.ts</code>, and now I can <strong>thoroughly recommend it</strong> to the people that want to use these timeless concepts in their TypeScript codebases.</p>
<p>If you have enjoyed this blogpost, definitely give <code>Effect.ts</code> a try and follow me on Twitter (<a href="https://twitter.com/FlavioCorpa">@FlavioCorpa</a>) to support my impostor syndrome and motivate me to keep writing technical posts! 🙏🏻</p>
<p>I hope to give a future workshop in <a href="https://reactalicante.es/">React Alicante 2024</a> and teach the amazing super powers of functional programming in TypeScript with <code>Effect.ts</code>, if you want to learn more and meet me in person, hope to see you there! 🤞🏻</p></section>
  </article>
</main>

 <footer class="py-14 bg-[var(--footerBgColor)] shrink-0">
  <div class="relative mx-auto md:w-[600px] w-auto px-[1.3125rem]">
    <ul class="flex justify-center list-none" role="list">
      <li class="mx-3" role="listitem">
        <a href="/">Home</a>
      </li>
      <li class="mx-3" role="listitem">
        <a href="https://github.com/sponsors/kutyel/">Sponsor me</a>
      </li>
      <li class="mx-3" role="listitem">
        <a href="/atom.xml">RSS</a>
      </li>
    </ul>
  </div>
</footer>


<script src="https://gistcdn.githack.com/kutyel/41d12e099484fd390fb67168271fcdd9/raw/9be26e500525a2e4edacc53d3a8006aaddec0e15/bsky-comments.js"></script>
]]></description>
    <pubDate>Fri, 17 Nov 2023 17:22:00 UT</pubDate>
    <guid>https://flaviocorpa.com/do-you-even-effect-ap-bro.html</guid>
    <dc:creator>Flavio Corpa</dc:creator>
</item>
<item>
    <title>Taking Screenshots with Elm 0.19</title>
    <link>https://flaviocorpa.com/taking-screenshots-with-elm-0-19.html</link>
    <description><![CDATA[<nav class="my-6 py-2">
  <div class="relative mx-auto md:w-[600px] w-auto px-[1.3125rem] md:px-0" data-nav-wrap>
    <a class="mr-5 absolute left-[-10000px] focus:static focus:left-auto" href="#content"
      >Skip to content</a
    >
    <a class="mr-5" href="/">Home</a>
    <a class="mr-5" href="https://github.com/sponsors/kutyel">Sponsor me</a>
    <a class="mr-5" href="/atom.xml">RSS</a>
  </div>
</nav>


<style>
  bsky-comments {
    --background-color: var(--bgColor);
    --text-color: var(--textColor);
    --link-color: var(--textLinkColor);
    --link-hover-color: var(--textLinkHoverColor);
    --comment-meta-color: #888;
    --error-color: #ff4d4d;
    --reply-border-color: var(--separatorColor);
    --button-background-color: var(--btnBgColor);
    --button-hover-background-color: rgba(var(--btnBgColor), 0.2);
    --author-avatar-border-radius: 50%;
  }
</style>

<main class="flex-1" id="content" tabindex="-1">
  <article class="pb-10">
    <header class="bg-[var(--headerBgColor)] mb-8 px-[1.3125rem] md:px-0 py-4 md:py-8">
      <div class="mx-auto md:w-[600px]">
        <h1 class="text-[1.7rem] md:text-[3rem] m-0 mb-4 font-normal leading-[1.2] text-[var(--h1Color)]">
          Taking Screenshots with Elm 0.19
        </h1>
        <div class="mx-auto md:w-[600px]">
          <small class="italic">04/08/2023</small>
          <small class="italic"> | 5 min read</small>
          
          <div class="mt-2">[ <a title="All pages tagged &#39;web&#39;." href="/tags/web.html" rel="tag">web</a>, <a title="All pages tagged &#39;elm&#39;." href="/tags/elm.html" rel="tag">elm</a>, <a title="All pages tagged &#39;fp&#39;." href="/tags/fp.html" rel="tag">fp</a>, <a title="All pages tagged &#39;screenshots&#39;." href="/tags/screenshots.html" rel="tag">screenshots</a>, <a title="All pages tagged &#39;frontend&#39;." href="/tags/frontend.html" rel="tag">frontend</a> ]</div>
        </div>
      </div>
    </header>
    <section class="mx-auto md:w-[600px] px-[1.3125rem] md:px-0"><p>Recently I had to implement frontend screenshots in an Elm app, and all the blog posts I could find were for outdated versions of Elm (&lt; 0.19)🌳, so here is how I managed to do it! Hopefully it helps someone else. 🤞🏻</p>
<p>My only 2 constraints were the following:</p>
<ul>
<li>The endpoint I was using to store the screenshots only accepted mime type <code>image/jpeg</code>.</li>
<li>I need to take a <em>sequence</em> of screenshots and focus on an individual bit of the UI, while hiding (in this case changing the HTML content to <code>REDACTED</code>) some parts of it.</li>
</ul>
<p>Obviously the code shown here can be simplified to fit your needs too but I wanted to present you something taken from the real world. 😉</p>
<h2 id="going-outside-of-elm">Going outside of Elm</h2>
<p>As you probably figured by now, this is not possible to do only in Elm, so we need to resort to <a href="https://guide.elm-lang.org/interop/ports.html">Ports</a> and a JavaScript library.</p>
<p>After an incredible waste of time trying out different JS libs to accomplish this, I had to settle with <a href="https://github.com/niklasvh/html2canvas"><code>html2canvas</code></a>, as apparently this is the only working library that produces images out of the DOM, not HTML docs or any other file format. 🤷🏼‍♂️</p>
<p>Now let’s get into the code part, we need at least 2 ports: one we will use to tell JS we want to take some screenshots, and another to receive back the response from outside of Elm.</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- App.elm</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="kw">port</span> <span class="fu">takeScreenshots</span> : <span class="dt">List</span> <span class="dt">DocumentId</span> <span class="op">-&gt;</span> <span class="dt">Cmd</span> <span class="fu">msg</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="kw">port</span> <span class="fu">receiveScreenshotData</span> : (<span class="dt">List</span> <span class="dt">ImagePortData</span> <span class="op">-&gt;</span> <span class="fu">msg</span>) <span class="op">-&gt;</span> <span class="dt">Sub</span> <span class="fu">msg</span></span></code></pre></div>
<p>The only important thing to highlight from the ports is that I had to construct a special type <code>ImagePortData</code> with the things I wanted to get back from JavaScript, here you have it defined for completion:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- Data.elm</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="kw">alias</span> <span class="dt">ImagePortData</span> <span class="op">=</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>    { <span class="fu">image</span> : <span class="dt">String</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">,</span> <span class="fu">time</span> : <span class="dt">String</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">,</span> <span class="fu">documentId</span> : <span class="dt">DocumentId</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>    }</span></code></pre></div>
<p>I wanted the timestamp from JS as an ISO String (this can also be done from the Elm side but anyway 🙄), the <code>documentId</code> was needed to hide/show parts of the UI I did not want to see in the screenshot and the <code>image</code> was the encoded <code>base64</code> string that JS was going to send me from the library.</p>
<p>After that I just needed to add a couple of messages and a subscription, following The Elm Architecture principles:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- App.elm</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">Msg</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">=</span> <span class="dt">NoOp</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- .. bunch of other msgs</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">|</span> <span class="dt">TakeScreenshots</span> (<span class="dt">List</span> <span class="dt">DocumentId</span>)</span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">|</span> <span class="dt">ScreenshotsTaken</span> (<span class="dt">List</span> <span class="dt">ImagePortData</span>)</span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>    <span class="op">|</span> <span class="dt">ScreenshotsSaved</span> (<span class="dt">Result</span> <span class="dt">Http</span><span class="op">.</span><span class="dt">Error</span> ())</span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a><span class="co">-- ...</span></span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a><span class="fu">subscriptions</span> : <span class="dt">Model</span> <span class="op">-&gt;</span> <span class="dt">Sub</span> <span class="dt">Msg</span></span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a><span class="fu">subscriptions</span> <span class="fu">model</span> <span class="op">=</span></span>
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Sub</span><span class="op">.</span><span class="fu">batch</span></span>
<span id="cb3-16"><a href="#cb3-16" aria-hidden="true" tabindex="-1"></a>        [ <span class="co">-- ... other subs</span></span>
<span id="cb3-17"><a href="#cb3-17" aria-hidden="true" tabindex="-1"></a>        <span class="op">,</span> <span class="fu">receiveScreenshotData</span> <span class="dt">ScreenshotsTaken</span></span>
<span id="cb3-18"><a href="#cb3-18" aria-hidden="true" tabindex="-1"></a>        ]</span></code></pre></div>
<p>You can probably use less <code>Msg</code>s, but in my case I used <code>TakeScreenshots</code> to ask JavaScript from Elm to take the screenshots, <code>ScreenshotsTaken</code> to receive the screenshot data back to Elm world and send them to the “save screenshots” endpoint, and finally a <code>ScreenshotsSaved</code> to do something after all this process is finished.</p>
<p>I think to show the actual pattern match on <code>Msg</code> in the <code>update</code> function is not really useful as it entirely depends on what you want your Elm app to do, so it is skipped for brevity.</p>
<p>The only bit of wiring that I needed to make is to modify the known <code>Config</code> (many real world Elm apps use this pattern, although you might not need it) type to accept a <code>msg</code>:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- Config.elm</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="kw">alias</span> <span class="dt">Config</span> <span class="fu">msg</span> <span class="op">=</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>    { <span class="fu">host</span> : <span class="dt">String</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- other unrelated stuff</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">,</span> <span class="fu">takeScreenshots</span> : <span class="dt">List</span> <span class="dt">DocumentId</span> <span class="op">-&gt;</span> <span class="fu">msg</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>    }</span></code></pre></div>
<p>Another relevant bit of code was the actual call to the save screenshots endpoint, which you can have a look at here:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- Data.elm</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="fu">saveScreenshots</span> : <span class="dt">Config</span> <span class="fu">msg</span> <span class="op">-&gt;</span> <span class="dt">List</span> <span class="dt">ImagePortData</span> <span class="op">-&gt;</span> (<span class="dt">Result</span> <span class="dt">Http</span><span class="op">.</span><span class="dt">Error</span> () <span class="op">-&gt;</span> <span class="fu">msg</span>) <span class="op">-&gt;</span> <span class="dt">Cmd</span> <span class="fu">msg</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="fu">saveScreenshots</span> { <span class="fu">host</span><span class="op">,</span> <span class="fu">token</span> } <span class="fu">listImgs</span> <span class="fu">resultMsg</span> <span class="op">=</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Http</span><span class="op">.</span><span class="fu">putWithHeaders</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a>        { <span class="fu">url</span> <span class="op">=</span> <span class="dt">Url</span><span class="op">.</span><span class="fu">crossOrigin</span> <span class="fu">host</span> [ <span class="st">&quot;store&quot;</span><span class="op">,</span> <span class="st">&quot;screenshots&quot;</span><span class="op">,</span> <span class="st">&quot;endpoint&quot;</span> ] []</span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>        <span class="op">,</span> <span class="fu">headers</span> <span class="op">=</span> [ <span class="dt">Http</span><span class="op">.</span><span class="fu">tokenHeader</span> <span class="fu">token</span> ]</span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>        <span class="op">,</span> <span class="fu">jsonBody</span> <span class="op">=</span></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a>            <span class="fu">listImgs</span></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a>                <span class="op">|&gt;</span> <span class="dt">Encode</span><span class="op">.</span><span class="fu">list</span></span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a>                    (\{ <span class="fu">image</span><span class="op">,</span> <span class="fu">time</span><span class="op">,</span> <span class="fu">documentId</span> } <span class="op">-&gt;</span></span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a>                        <span class="dt">Encode</span><span class="op">.</span><span class="fu">object</span></span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a>                            [ ( <span class="st">&quot;document_id&quot;</span><span class="op">,</span> <span class="dt">Encode</span><span class="op">.</span><span class="fu">string</span> <span class="fu">documentId</span> )</span>
<span id="cb5-14"><a href="#cb5-14" aria-hidden="true" tabindex="-1"></a>                            <span class="op">,</span> ( <span class="st">&quot;screenshot&quot;</span></span>
<span id="cb5-15"><a href="#cb5-15" aria-hidden="true" tabindex="-1"></a>                              <span class="op">,</span> <span class="dt">Encode</span><span class="op">.</span><span class="fu">object</span></span>
<span id="cb5-16"><a href="#cb5-16" aria-hidden="true" tabindex="-1"></a>                                    [ ( <span class="st">&quot;image&quot;</span><span class="op">,</span> <span class="dt">Encode</span><span class="op">.</span><span class="fu">string</span> <span class="fu">image</span> )</span>
<span id="cb5-17"><a href="#cb5-17" aria-hidden="true" tabindex="-1"></a>                                    <span class="op">,</span> ( <span class="st">&quot;time&quot;</span><span class="op">,</span> <span class="dt">Encode</span><span class="op">.</span><span class="fu">string</span> <span class="fu">time</span> )</span>
<span id="cb5-18"><a href="#cb5-18" aria-hidden="true" tabindex="-1"></a>                                    ]</span>
<span id="cb5-19"><a href="#cb5-19" aria-hidden="true" tabindex="-1"></a>                              )</span>
<span id="cb5-20"><a href="#cb5-20" aria-hidden="true" tabindex="-1"></a>                            ]</span>
<span id="cb5-21"><a href="#cb5-21" aria-hidden="true" tabindex="-1"></a>                    )</span>
<span id="cb5-22"><a href="#cb5-22" aria-hidden="true" tabindex="-1"></a>        <span class="op">,</span> <span class="fu">expect</span> <span class="op">=</span> <span class="dt">Http</span><span class="op">.</span><span class="fu">expectWhatever</span> <span class="fu">resultMsg</span></span>
<span id="cb5-23"><a href="#cb5-23" aria-hidden="true" tabindex="-1"></a>        }</span></code></pre></div>
<p>Do not focus too much on <code>Http.putWithHeaders</code>, as this is just a custom wrapper around the usual <code>Http.put</code> module stuff just making my life easier.</p>
<p>I have to mention that, since <a href="https://github.com/elm/http/issues/56#issuecomment-462489112">Elm does not have a Blob type</a>, we can just use <code>String</code> to receive the encoded <code>base64</code> image data, and it will just work. 🪄</p>
<h2 id="ok-but-where-is-the-javascript-thinking">Ok but where is the JavaScript? 🤔</h2>
<p>Obviously I have just shown for now the Elm part of the code relevant to the screenshots, but the actual magic is performed in the JS side to make all of this work, here is the code:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode js"><code class="sourceCode javascript"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> html2canvas <span class="im">from</span> <span class="st">&#39;html2canvas&#39;</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>app<span class="op">.</span><span class="at">ports</span><span class="op">.</span><span class="at">takeScreenshots</span><span class="op">.</span><span class="fu">subscribe</span>((documentIds) <span class="kw">=&gt;</span> {</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> promisedScreenshots <span class="op">=</span> documentIds<span class="op">.</span><span class="fu">map</span>(<span class="kw">async</span> (documentId) <span class="kw">=&gt;</span> {</span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>    <span class="co">// take the screenshot</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">const</span> canvas <span class="op">=</span> <span class="cf">await</span> <span class="fu">html2canvas</span>(<span class="bu">document</span><span class="op">.</span><span class="at">body</span><span class="op">,</span> {</span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a>      <span class="dt">useCORS</span><span class="op">:</span> <span class="kw">true</span><span class="op">,</span></span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a>      <span class="dt">allowTaint</span><span class="op">:</span> <span class="kw">true</span><span class="op">,</span></span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a>      <span class="dt">foreignObjectRendering</span><span class="op">:</span> <span class="kw">true</span><span class="op">,</span></span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a>      <span class="co">// change all other documents to REDACTED</span></span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a>      <span class="dt">onclone</span><span class="op">:</span> (doc) <span class="kw">=&gt;</span></span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a>        doc</span>
<span id="cb6-13"><a href="#cb6-13" aria-hidden="true" tabindex="-1"></a>          <span class="op">.</span><span class="fu">querySelectorAll</span>(<span class="vs">`[data-document-id]:not([data-document-id=&quot;</span><span class="sc">${</span>documentId<span class="sc">}</span><span class="vs">&quot;])`</span>)</span>
<span id="cb6-14"><a href="#cb6-14" aria-hidden="true" tabindex="-1"></a>          <span class="op">.</span><span class="fu">forEach</span>((node) <span class="kw">=&gt;</span> node<span class="op">.</span><span class="at">childNodes</span><span class="op">.</span><span class="fu">forEach</span>((c) <span class="kw">=&gt;</span> (c<span class="op">.</span><span class="at">textContent</span> <span class="op">=</span> <span class="st">&#39;REDACTED&#39;</span>)))<span class="op">,</span></span>
<span id="cb6-15"><a href="#cb6-15" aria-hidden="true" tabindex="-1"></a>    })</span>
<span id="cb6-16"><a href="#cb6-16" aria-hidden="true" tabindex="-1"></a>    <span class="kw">const</span> image <span class="op">=</span> canvas<span class="op">.</span><span class="fu">toDataURL</span>(<span class="st">&#39;image/jpeg&#39;</span>)</span>
<span id="cb6-17"><a href="#cb6-17" aria-hidden="true" tabindex="-1"></a>    <span class="kw">const</span> time <span class="op">=</span> <span class="kw">new</span> <span class="bu">Date</span>()<span class="op">.</span><span class="fu">toISOString</span>()</span>
<span id="cb6-18"><a href="#cb6-18" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> { image<span class="op">,</span> time<span class="op">,</span> documentId }</span>
<span id="cb6-19"><a href="#cb6-19" aria-hidden="true" tabindex="-1"></a>  })</span>
<span id="cb6-20"><a href="#cb6-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-21"><a href="#cb6-21" aria-hidden="true" tabindex="-1"></a>  <span class="co">// send it back to Elm</span></span>
<span id="cb6-22"><a href="#cb6-22" aria-hidden="true" tabindex="-1"></a>  <span class="bu">Promise</span><span class="op">.</span><span class="fu">all</span>(promisedScreenshots)<span class="op">.</span><span class="fu">then</span>(app<span class="op">.</span><span class="at">ports</span><span class="op">.</span><span class="at">receiveScreenshotData</span><span class="op">.</span><span class="at">send</span>)</span>
<span id="cb6-23"><a href="#cb6-23" aria-hidden="true" tabindex="-1"></a>})</span></code></pre></div>
<p>There are a few things to say about this snippet:</p>
<ol>
<li><p>As I mentioned, I needed to produce a <strong>list</strong> of screenshots, so I used the given list of ids sent from Elm to map them into a list of screenshots in the line with <code>documentIds.map(async (documentId) =&gt; ...</code>. This produces a list of JS <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promises</a>, since the <code>html2canvas</code> call returns a Promise, so I needed to wait for all of them to resolve before sending the data back to Elm (this can be easily done with <code>Promise.all</code>, even using <code>async/await</code> I was not spared of having to do this unfortunately 😭). I did not get this part right at the beginning and received an obscure Elm compiler error message, but I can promise this is one of the very few <a href="https://github.com/elm/core/issues/1043">well know issues</a> were what is wrong is not completely obvious. 😅</p></li>
<li><p>If you notice the actual call to <code>html2canvas</code>, you will notice it takes a second argument which is a JS object with some settings (I mostly only used <code>useCORS</code>, <code>allowTaint</code> and <code>foreignObjectRendering</code>), you can probably skip those but I noticed that this tweaks actually <strong>improved pretty much the overall quality of the screenshots</strong>, so I had to use them.</p></li>
<li><p>Probably the most important setting I had to use is the <code>onclone</code> function, which is a callback you can use to manipulate the DOM <em>before</em> taking the actual screenshot, pretty handy for what I needed to do!</p></li>
<li><p>If you have a closer look on my <code>querySelectorAll</code> line, you will notice a neat trick shamelessly <a href="https://stackoverflow.com/questions/25287229/cant-find-a-not-equal-css-attribute-selector/68520810#68520810">copied from StackOverflow</a> (yes I still use that from time to time, sorry chatGPT 🤣), that allowed me to perform some operations on the REST of the things I did not want to appear in the screenshot!</p></li>
<li><p>Finally, if you pay attention to this bit: <code>canvas.toDataURL('image/jpeg')</code> you will notice that I am <a href="https://stackoverflow.com/questions/15685698/getting-binary-base64-data-from-html5-canvas-readasbinarystring/15685877#15685877">manually setting the image encoding</a> to the one my backend supported, the default for the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API">Canvas HTML API</a> is <code>image/png</code> by the way!</p></li>
</ol>
<hr />
<p>Nothing else to say, this all worked out in the end and I suffered so much I just wanted to skip some of it to the next generation of Elm developers! 😘</p>
<p>If you enjoyed reading this, please share it in your social networks and <strong>follow me on <a href="https://twitter.com/FlavioCorpa">Twitter</a>!</strong> 🙌🏻</p>
<p>Happy coding! 😎🖖🏻</p></section>
  </article>
</main>

 <footer class="py-14 bg-[var(--footerBgColor)] shrink-0">
  <div class="relative mx-auto md:w-[600px] w-auto px-[1.3125rem]">
    <ul class="flex justify-center list-none" role="list">
      <li class="mx-3" role="listitem">
        <a href="/">Home</a>
      </li>
      <li class="mx-3" role="listitem">
        <a href="https://github.com/sponsors/kutyel/">Sponsor me</a>
      </li>
      <li class="mx-3" role="listitem">
        <a href="/atom.xml">RSS</a>
      </li>
    </ul>
  </div>
</footer>


<script src="https://gistcdn.githack.com/kutyel/41d12e099484fd390fb67168271fcdd9/raw/9be26e500525a2e4edacc53d3a8006aaddec0e15/bsky-comments.js"></script>
]]></description>
    <pubDate>Fri, 04 Aug 2023 17:22:00 UT</pubDate>
    <guid>https://flaviocorpa.com/taking-screenshots-with-elm-0-19.html</guid>
    <dc:creator>Flavio Corpa</dc:creator>
</item>
<item>
    <title>Haskell for Elm developers: giving names to stuff (Part 3 - Monads!)</title>
    <link>https://flaviocorpa.com/haskell-for-elm-developers-giving-names-to-stuff-part-3-monads.html</link>
    <description><![CDATA[<nav class="my-6 py-2">
  <div class="relative mx-auto md:w-[600px] w-auto px-[1.3125rem] md:px-0" data-nav-wrap>
    <a class="mr-5 absolute left-[-10000px] focus:static focus:left-auto" href="#content"
      >Skip to content</a
    >
    <a class="mr-5" href="/">Home</a>
    <a class="mr-5" href="https://github.com/sponsors/kutyel">Sponsor me</a>
    <a class="mr-5" href="/atom.xml">RSS</a>
  </div>
</nav>


<style>
  bsky-comments {
    --background-color: var(--bgColor);
    --text-color: var(--textColor);
    --link-color: var(--textLinkColor);
    --link-hover-color: var(--textLinkHoverColor);
    --comment-meta-color: #888;
    --error-color: #ff4d4d;
    --reply-border-color: var(--separatorColor);
    --button-background-color: var(--btnBgColor);
    --button-hover-background-color: rgba(var(--btnBgColor), 0.2);
    --author-avatar-border-radius: 50%;
  }
</style>

<main class="flex-1" id="content" tabindex="-1">
  <article class="pb-10">
    <header class="bg-[var(--headerBgColor)] mb-8 px-[1.3125rem] md:px-0 py-4 md:py-8">
      <div class="mx-auto md:w-[600px]">
        <h1 class="text-[1.7rem] md:text-[3rem] m-0 mb-4 font-normal leading-[1.2] text-[var(--h1Color)]">
          Haskell for Elm developers: giving names to stuff (Part 3 - Monads!)
        </h1>
        <div class="mx-auto md:w-[600px]">
          <small class="italic">01/03/2023</small>
          <small class="italic"> | 6 min read</small>
          
          <small class="italic"> (updated: 03/03/2023 12:57)</small>
          
          <div class="mt-2">[ <a title="All pages tagged &#39;haskell&#39;." href="/tags/haskell.html" rel="tag">haskell</a>, <a title="All pages tagged &#39;elm&#39;." href="/tags/elm.html" rel="tag">elm</a>, <a title="All pages tagged &#39;fp&#39;." href="/tags/fp.html" rel="tag">fp</a> ]</div>
        </div>
      </div>
    </header>
    <section class="mx-auto md:w-[600px] px-[1.3125rem] md:px-0"><p><img src="./images/haskell-elm.svg" alt="logo" width="300px"></p>
<p>It is finally time, I did not think I would ever write a <a href="https://byorgey.wordpress.com/2009/01/12/abstraction-intuition-and-the-monad-tutorial-fallacy/"><code>Monad</code> tutorial</a>, but here it is! 😅 Let us have a look at the way <code>Monad</code>s are defined in Haskell:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> (<span class="dt">Applicative</span> m) <span class="ot">=&gt;</span> <span class="dt">Monad</span> m <span class="kw">where</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="ot">  return ::</span> a <span class="ot">-&gt;</span> m a</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="ot">  (&gt;&gt;) ::</span> m a <span class="ot">-&gt;</span> m b <span class="ot">-&gt;</span> m b</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="ot">  (&gt;&gt;=) ::</span> m a <span class="ot">-&gt;</span> (a <span class="ot">-&gt;</span> m b) <span class="ot">-&gt;</span> m b</span></code></pre></div>
<p>The first thing we can notice again is that the typeclass definition has itself a typeclass constraint, implied by the <code>class Applicative m =&gt;</code> bit, just like in our previous post about Applicative Functors.</p>
<p>Needless to say, this means that every <code>Monad</code> instance must satisfy the <code>Applicative</code> instance first, and that one, in return, the <code>Functor</code> instance. 😵‍💫 By the way, if you have not already, to understand this whole post and gain more intuition about <code>Monad</code>s, you better read the previous two posts I made:</p>
<ol>
<li><a href="https://flaviocorpa.com/haskell-for-elm-developers-giving-names-to-stuff-part-1-functors.html">Haskell for Elm developers: giving names to stuff (Part 1 - Functors)</a></li>
<li><a href="https://flaviocorpa.com/haskell-for-elm-developers-giving-names-to-stuff-part-2-applicative-functors.html">Haskell for Elm developers: giving names to stuff (Part 2 - Applicative Functors)</a></li>
</ol>
<p>SPOILER ALERT ⚠️! In Elm, some examples of <code>Monad</code>s you use every day are… 🥁🥁🥁 (<em>drum rolls…</em>) again: <code>List</code>, <code>Maybe</code>, <code>Result</code> and <code>Task</code>!!! 🤯</p>
<h2 id="the-return-function">The <code>return</code> function</h2>
<p>If you have good memory, you might be asking yourself right now: what is the difference between <code>pure :: a -&gt; m a</code> and <code>return</code>?</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="fu">return</span><span class="ot"> ::</span> a <span class="ot">-&gt;</span> m a</span></code></pre></div>
<p>And the answer is: there is <strong>none</strong>.</p>
<p>If you want to find out the <a href="https://stackoverflow.com/a/32788607/2834553">historical reasons</a> why we ended up with two functions called different that basically do the same thing, please check this <a href="https://www.reddit.com/r/haskell/comments/4tu9qf/is_there_any_pure_return/">Reddit thread</a> from 7 years go. 👴🏻 There is a modern <a href="https://github.com/search?o=desc&amp;q=use+pure+instead+of+return&amp;s=&amp;type=Commits">Haskell trend</a> to prefer <code>pure</code> over <code>return</code> in code (I contributed to this trend a fair bit myself), but it is totally up to you!</p>
<h2 id="the-mr-pointy-rofl-operator-">The Mr. Pointy (🤣) operator (<code>&gt;&gt;</code>)</h2>
<p>I did not come up with the name, I swear, I read it in the <a href="https://haskellbook.com/">Haskell Book™️</a>. Some people refer to it as the <em>sequencing operator</em>, but it does not have an “official” English-language name:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="ot">(&gt;&gt;) ::</span> m a <span class="ot">-&gt;</span> m b <span class="ot">-&gt;</span> m b</span></code></pre></div>
<p>The only thing the Mr. Pointy operator does is sequencing two actions while discarding any result value of the first action.</p>
<p>Let’s have another peek at the implementation of the <code>Monad</code> typeclass in <code>GHC.Base</code> and see what we can learn this time from it:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> (<span class="dt">Applicative</span> m) <span class="ot">=&gt;</span> <span class="dt">Monad</span> m <span class="kw">where</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- | Sequentially compose two actions, passing any value produced</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- by the first as an argument to the second.</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="ot">  (&gt;&gt;=) ::</span> m a <span class="ot">-&gt;</span> (a <span class="ot">-&gt;</span> m b) <span class="ot">-&gt;</span> m b</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- | Sequentially compose two actions, discarding any value produced</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- by the first, like sequencing operators (such as the semicolon)</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- in imperative languages.</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a><span class="ot">  (&gt;&gt;) ::</span> m a <span class="ot">-&gt;</span> m b <span class="ot">-&gt;</span> m b</span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a>  m <span class="op">&gt;&gt;</span> k <span class="ot">=</span> m <span class="op">&gt;&gt;=</span> \_ <span class="ot">-&gt;</span> k</span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a>  <span class="ot">{-# INLINE (&gt;&gt;) #-}</span></span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- | Inject a value into the monadic type.</span></span>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a><span class="ot">  return ::</span> a <span class="ot">-&gt;</span> m a</span>
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a>  <span class="fu">return</span> <span class="ot">=</span> <span class="fu">pure</span></span></code></pre></div>
<p>First thing we can notice is hey! Another language pragma, this time called <a href="https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/pragmas.html#inline-pragma"><code>INLINE pragma</code></a>, do not worry too much about it, all it is doing is performing a little optimization on the compiler level to tell GHC that it can go ahead and <em>inline</em> that function. A second thing we can notice is that Mr. Pointy (<code>&gt;&gt;</code>) is defined in terms of <code>&gt;&gt;=</code>:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="ot">  (&gt;&gt;) ::</span> m a <span class="ot">-&gt;</span> m b <span class="ot">-&gt;</span> m b</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>  m <span class="op">&gt;&gt;</span> k <span class="ot">=</span> m <span class="op">&gt;&gt;=</span> \_ <span class="ot">-&gt;</span> k</span></code></pre></div>
<p>Because of this, we are not going to waste any time trying to find the definition of Mr. Pointy in Elm (because if you define <code>&gt;&gt;=</code> for your type, you again get <em>for free</em> the definition of <code>&gt;&gt;</code>), but rather cut right to the meat!</p>
<h2 id="the-monadic-bind-operator-">The Monadic bind operator (<code>&gt;&gt;=</code>)</h2>
<p>I am going to try my best to give you the simplest explanation about this operator, but since I assume you know Elm, the explanation is going to be quite trivial: 😉</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="ot">(&gt;&gt;=) ::</span> m a <span class="ot">-&gt;</span> (a <span class="ot">-&gt;</span> m b) <span class="ot">-&gt;</span> m b</span></code></pre></div>
<p>By looking at the type signature of the bind operator, does it not look familiar to you, dear Elm developer? Have you ever tried to <code>flatMap</code> a <code>List</code>? <code>flatMap</code> is the name chosen by JavaScript and many other languages, but Elm chose a couple of interesting ones, let us begin first with the <code>List</code> Monad. 🙊</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> <span class="dt">List</span><span class="op">.</span><span class="fu">concatMap</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="op">&lt;</span><span class="fu">function</span><span class="op">&gt;</span> : (<span class="fu">a</span> <span class="op">-&gt;</span> <span class="dt">List</span> <span class="fu">b</span>) <span class="op">-&gt;</span> <span class="dt">List</span> <span class="fu">a</span> <span class="op">-&gt;</span> <span class="dt">List</span> <span class="fu">b</span></span></code></pre></div>
<p>As you can see, <code>List.concatMap</code> is just a flipped version of the <code>&gt;&gt;=</code> operator for Elm, but what about <code>Maybe</code>, <code>Result</code> and <code>Task</code>?</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> <span class="dt">Maybe</span><span class="op">.</span><span class="fu">andThen</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="op">&lt;</span><span class="fu">function</span><span class="op">&gt;</span> : (<span class="fu">a</span> <span class="op">-&gt;</span> <span class="dt">Maybe</span> <span class="fu">b</span>) <span class="op">-&gt;</span> <span class="dt">Maybe</span> <span class="fu">a</span> <span class="op">-&gt;</span> <span class="dt">Maybe</span> <span class="fu">b</span></span></code></pre></div>
<p>Yes! We can say with confidence that those types satisfy the <code>Monad</code> instance because we have <code>Maybe.andThen</code>, <code>Result.andThen</code> and <code>Task.andThen</code> and all of those functions allow us to <strong>chain computations</strong>! 👏🏻 Hope that was not so scary after all! 👻😘</p>
<h2 id="the-infamous-do-notation">The infamous <code>do</code> notation</h2>
<p><a href="https://github.com/avh4/elm-format/issues/568">Famously</a>, the issue with the <code>|&gt; andThen</code> approach, is that <a href="https://github.com/avh4/elm-format"><strong>elm-format</strong></a> (the <em>de facto standard</em> for all Elm applications) formats everything in a rather <a href="https://github.com/avh4/elm-format/issues/352">ugly manner</a>:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="fu">map5</span> :</span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>    (<span class="fu">a</span> <span class="op">-&gt;</span> <span class="fu">b</span> <span class="op">-&gt;</span> <span class="fu">c</span> <span class="op">-&gt;</span> <span class="fu">d</span> <span class="op">-&gt;</span> <span class="fu">e</span> <span class="op">-&gt;</span> <span class="fu">result</span>)</span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>    <span class="op">-&gt;</span> <span class="dt">Task</span> <span class="fu">x</span> <span class="fu">a</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">-&gt;</span> <span class="dt">Task</span> <span class="fu">x</span> <span class="fu">b</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">-&gt;</span> <span class="dt">Task</span> <span class="fu">x</span> <span class="fu">c</span></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">-&gt;</span> <span class="dt">Task</span> <span class="fu">x</span> <span class="fu">d</span></span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">-&gt;</span> <span class="dt">Task</span> <span class="fu">x</span> <span class="fu">e</span></span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a>    <span class="op">-&gt;</span> <span class="dt">Task</span> <span class="fu">x</span> <span class="fu">result</span></span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a><span class="fu">map5</span> <span class="fu">func</span> <span class="fu">taskA</span> <span class="fu">taskB</span> <span class="fu">taskC</span> <span class="fu">taskD</span> <span class="fu">taskE</span> <span class="op">=</span></span>
<span id="cb9-10"><a href="#cb9-10" aria-hidden="true" tabindex="-1"></a>    <span class="fu">taskA</span></span>
<span id="cb9-11"><a href="#cb9-11" aria-hidden="true" tabindex="-1"></a>        <span class="op">|&gt;</span> <span class="fu">andThen</span></span>
<span id="cb9-12"><a href="#cb9-12" aria-hidden="true" tabindex="-1"></a>            (\<span class="fu">a</span> <span class="op">-&gt;</span></span>
<span id="cb9-13"><a href="#cb9-13" aria-hidden="true" tabindex="-1"></a>                <span class="fu">taskB</span></span>
<span id="cb9-14"><a href="#cb9-14" aria-hidden="true" tabindex="-1"></a>                    <span class="op">|&gt;</span> <span class="fu">andThen</span></span>
<span id="cb9-15"><a href="#cb9-15" aria-hidden="true" tabindex="-1"></a>                        (\<span class="fu">b</span> <span class="op">-&gt;</span></span>
<span id="cb9-16"><a href="#cb9-16" aria-hidden="true" tabindex="-1"></a>                            <span class="fu">taskC</span></span>
<span id="cb9-17"><a href="#cb9-17" aria-hidden="true" tabindex="-1"></a>                                <span class="op">|&gt;</span> <span class="fu">andThen</span></span>
<span id="cb9-18"><a href="#cb9-18" aria-hidden="true" tabindex="-1"></a>                                    (\<span class="fu">c</span> <span class="op">-&gt;</span></span>
<span id="cb9-19"><a href="#cb9-19" aria-hidden="true" tabindex="-1"></a>                                        <span class="fu">taskD</span></span>
<span id="cb9-20"><a href="#cb9-20" aria-hidden="true" tabindex="-1"></a>                                            <span class="op">|&gt;</span> <span class="fu">andThen</span></span>
<span id="cb9-21"><a href="#cb9-21" aria-hidden="true" tabindex="-1"></a>                                                (\<span class="fu">d</span> <span class="op">-&gt;</span></span>
<span id="cb9-22"><a href="#cb9-22" aria-hidden="true" tabindex="-1"></a>                                                    <span class="fu">taskE</span></span>
<span id="cb9-23"><a href="#cb9-23" aria-hidden="true" tabindex="-1"></a>                                                        <span class="op">|&gt;</span> <span class="fu">andThen</span> (\<span class="fu">e</span> <span class="op">-&gt;</span> <span class="fu">succeed</span> (<span class="fu">func</span> <span class="fu">a</span> <span class="fu">b</span> <span class="fu">c</span> <span class="fu">d</span> <span class="fu">e</span>))</span>
<span id="cb9-24"><a href="#cb9-24" aria-hidden="true" tabindex="-1"></a>                                                )</span>
<span id="cb9-25"><a href="#cb9-25" aria-hidden="true" tabindex="-1"></a>                                    )</span>
<span id="cb9-26"><a href="#cb9-26" aria-hidden="true" tabindex="-1"></a>                        )</span>
<span id="cb9-27"><a href="#cb9-27" aria-hidden="true" tabindex="-1"></a>            )</span></code></pre></div>
<p>This, however, is <em>not an issue</em> that <code>elm-format</code> is responsible for (as a matter of fact, I love <code>elm-format</code> and think it is a <strong>modern masterpiece</strong> of software engineering! 😍), but it is rather a <em>consequence</em> of the language design decision <em>NOT</em> to have something like <code>do</code> notation in Elm. For example, the above code would be really similar <strong>without</strong> <code>do</code> notation in Haskell (if you use a formatter like <a href="https://ormolu-live.tweag.io/"><code>ormolu</code></a>):</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="ot">map5 ::</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>  (a <span class="ot">-&gt;</span> b <span class="ot">-&gt;</span> c <span class="ot">-&gt;</span> d <span class="ot">-&gt;</span> e <span class="ot">-&gt;</span> result) <span class="ot">-&gt;</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Task</span> x a <span class="ot">-&gt;</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Task</span> x b <span class="ot">-&gt;</span></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Task</span> x c <span class="ot">-&gt;</span></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Task</span> x d <span class="ot">-&gt;</span></span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Task</span> x e <span class="ot">-&gt;</span></span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Task</span> x result</span>
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a>map5 func taskA taskB taskC taskD taskE <span class="ot">=</span></span>
<span id="cb10-10"><a href="#cb10-10" aria-hidden="true" tabindex="-1"></a>  taskA</span>
<span id="cb10-11"><a href="#cb10-11" aria-hidden="true" tabindex="-1"></a>    <span class="op">&gt;&gt;=</span> \a <span class="ot">-&gt;</span></span>
<span id="cb10-12"><a href="#cb10-12" aria-hidden="true" tabindex="-1"></a>      taskB</span>
<span id="cb10-13"><a href="#cb10-13" aria-hidden="true" tabindex="-1"></a>        <span class="op">&gt;&gt;=</span> \b <span class="ot">-&gt;</span></span>
<span id="cb10-14"><a href="#cb10-14" aria-hidden="true" tabindex="-1"></a>          taskC</span>
<span id="cb10-15"><a href="#cb10-15" aria-hidden="true" tabindex="-1"></a>            <span class="op">&gt;&gt;=</span> \c <span class="ot">-&gt;</span></span>
<span id="cb10-16"><a href="#cb10-16" aria-hidden="true" tabindex="-1"></a>              taskD</span>
<span id="cb10-17"><a href="#cb10-17" aria-hidden="true" tabindex="-1"></a>                <span class="op">&gt;&gt;=</span> \d <span class="ot">-&gt;</span></span>
<span id="cb10-18"><a href="#cb10-18" aria-hidden="true" tabindex="-1"></a>                  taskE</span>
<span id="cb10-19"><a href="#cb10-19" aria-hidden="true" tabindex="-1"></a>                    <span class="op">&gt;&gt;=</span> \e <span class="ot">-&gt;</span> <span class="fu">pure</span> (func a b c d e)</span></code></pre></div>
<p>Yes, there are Haskellers that still to this very day <strong>format their code by hand</strong> (😅), and so they would use less indentation in the aforementioned code, but we are not gonna let humans get in the way of the machine (thank God we have formatters 😍). Nevertheless, thanks to <code>do</code> notation, we can write it in the following manner:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="ot">map5 ::</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>  (a <span class="ot">-&gt;</span> b <span class="ot">-&gt;</span> c <span class="ot">-&gt;</span> d <span class="ot">-&gt;</span> e <span class="ot">-&gt;</span> result) <span class="ot">-&gt;</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Task</span> x a <span class="ot">-&gt;</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Task</span> x b <span class="ot">-&gt;</span></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Task</span> x c <span class="ot">-&gt;</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Task</span> x d <span class="ot">-&gt;</span></span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Task</span> x e <span class="ot">-&gt;</span></span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Task</span> x result</span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a>map5 func taskA taskB taskC taskD taskE <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb11-10"><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a>  a <span class="ot">&lt;-</span> taskA</span>
<span id="cb11-11"><a href="#cb11-11" aria-hidden="true" tabindex="-1"></a>  b <span class="ot">&lt;-</span> taskB</span>
<span id="cb11-12"><a href="#cb11-12" aria-hidden="true" tabindex="-1"></a>  c <span class="ot">&lt;-</span> taskC</span>
<span id="cb11-13"><a href="#cb11-13" aria-hidden="true" tabindex="-1"></a>  d <span class="ot">&lt;-</span> taskD</span>
<span id="cb11-14"><a href="#cb11-14" aria-hidden="true" tabindex="-1"></a>  e <span class="ot">&lt;-</span> taskE</span>
<span id="cb11-15"><a href="#cb11-15" aria-hidden="true" tabindex="-1"></a>  <span class="fu">pure</span> <span class="op">$</span> func a b c d e</span></code></pre></div>
<p>Doesn’t it just look beautiful!? 💜</p>
<blockquote>
<p>Funnily enough, <a href="https://github.com/tweag/ormolu"><strong>ormolu</strong></a> is the closest we can get to something like <code>elm-format</code> in Haskell (which I also love 🤩 and am using to format every code sample in this blogpost) and many Haskellers hate it for no reason at all! 🤷🏼‍♂️</p>
</blockquote>
<blockquote>
<p>EDIT: As pointed out by <a href="https://twitter.com/TankorSmash/status/1631347082274512897?s=20">@TankorSmash on Twitter</a>, the actual closest to <code>elm-format</code> would probably be <a href="https://github.com/cjoach/hindent-elm"><code>hindent-elm</code></a>, but it might not work 100% correctly or as complete as other Haskell formatters.</p>
</blockquote>
<h2 id="acknowledgements">Acknowledgements</h2>
<p>Special thanks to <a href="https://twitter.com/Forensor">@forensor</a> and other readers that have encouraged me to continue the series. Kudos to <a href="https://twitter.com/avh4">Aaron VonderHaar</a> and to <a href="https://markkarpov.com/about.html">Mark Karpov</a> for creating and maintaining <code>elm-format</code> and <code>ormolu</code> respectively! 🙌🏻</p>
<p>Thanks again to <a href="https://twitter.com/trupill">@serras</a> for technical proofreading this post again (he single-handedly wrote an <a href="https://leanpub.com/book-of-monads">entire book</a> exclusively about <code>Monad</code>s after all 🫡) and remember! <strong>Always be nice</strong> to each other online and have in mind that we are all in different learning paths in our lives and that we can help each other out by giving <em>constructive feedback</em>, rather than trying to <a href="https://twitter.com/FlavioCorpa/status/1629225727852789762?s=20">destroy people’s hopes and dreams</a>. 😅</p>
<p>Hope <code>Monad</code>s finally clicked for you ✨ (if they had not already) and you learned something new! If you enjoyed this post and would like me to continue the series (<em>next up would probably be maybe <strong>parser combinators</strong>?</em>, let me know what you would like to hear next!), please share it in your social networks and <strong>follow me on <a href="https://twitter.com/FlavioCorpa">Twitter</a>!</strong> 🙌🏻</p></section>
  </article>
</main>

 <footer class="py-14 bg-[var(--footerBgColor)] shrink-0">
  <div class="relative mx-auto md:w-[600px] w-auto px-[1.3125rem]">
    <ul class="flex justify-center list-none" role="list">
      <li class="mx-3" role="listitem">
        <a href="/">Home</a>
      </li>
      <li class="mx-3" role="listitem">
        <a href="https://github.com/sponsors/kutyel/">Sponsor me</a>
      </li>
      <li class="mx-3" role="listitem">
        <a href="/atom.xml">RSS</a>
      </li>
    </ul>
  </div>
</footer>


<script src="https://gistcdn.githack.com/kutyel/41d12e099484fd390fb67168271fcdd9/raw/9be26e500525a2e4edacc53d3a8006aaddec0e15/bsky-comments.js"></script>
]]></description>
    <pubDate>Wed, 01 Mar 2023 17:22:00 UT</pubDate>
    <guid>https://flaviocorpa.com/haskell-for-elm-developers-giving-names-to-stuff-part-3-monads.html</guid>
    <dc:creator>Flavio Corpa</dc:creator>
</item>
<item>
    <title>Declarative UIs without CSS with elm-ui</title>
    <link>https://flaviocorpa.com/declarative-uis-without-css-with-elm-ui.html</link>
    <description><![CDATA[<nav class="my-6 py-2">
  <div class="relative mx-auto md:w-[600px] w-auto px-[1.3125rem] md:px-0" data-nav-wrap>
    <a class="mr-5 absolute left-[-10000px] focus:static focus:left-auto" href="#content"
      >Skip to content</a
    >
    <a class="mr-5" href="/">Home</a>
    <a class="mr-5" href="https://github.com/sponsors/kutyel">Sponsor me</a>
    <a class="mr-5" href="/atom.xml">RSS</a>
  </div>
</nav>


<style>
  bsky-comments {
    --background-color: var(--bgColor);
    --text-color: var(--textColor);
    --link-color: var(--textLinkColor);
    --link-hover-color: var(--textLinkHoverColor);
    --comment-meta-color: #888;
    --error-color: #ff4d4d;
    --reply-border-color: var(--separatorColor);
    --button-background-color: var(--btnBgColor);
    --button-hover-background-color: rgba(var(--btnBgColor), 0.2);
    --author-avatar-border-radius: 50%;
  }
</style>

<main class="flex-1" id="content" tabindex="-1">
  <article class="pb-10">
    <header class="bg-[var(--headerBgColor)] mb-8 px-[1.3125rem] md:px-0 py-4 md:py-8">
      <div class="mx-auto md:w-[600px]">
        <h1 class="text-[1.7rem] md:text-[3rem] m-0 mb-4 font-normal leading-[1.2] text-[var(--h1Color)]">
          Declarative UIs without CSS with elm-ui
        </h1>
        <div class="mx-auto md:w-[600px]">
          <small class="italic">24/02/2023</small>
          <small class="italic"> | less than a minute</small>
          
          <div class="mt-2">[ <a title="All pages tagged &#39;egghead&#39;." href="/tags/egghead.html" rel="tag">egghead</a>, <a title="All pages tagged &#39;elm&#39;." href="/tags/elm.html" rel="tag">elm</a>, <a title="All pages tagged &#39;elm-ui&#39;." href="/tags/elm-ui.html" rel="tag">elm-ui</a>, <a title="All pages tagged &#39;web&#39;." href="/tags/web.html" rel="tag">web</a>, <a title="All pages tagged &#39;frontend&#39;." href="/tags/frontend.html" rel="tag">frontend</a> ]</div>
        </div>
      </div>
    </header>
    <section class="mx-auto md:w-[600px] px-[1.3125rem] md:px-0"><p><a href="https://egghead.io/courses/declarative-uis-without-css-with-elm-ui-93bd?af=e68v38">Check out my <code>elm-ui</code> course on egghead.io!</a></p>
<p><a href="(https://egghead.io/courses/declarative-uis-without-css-with-elm-ui-93bd?af=e68v38)"><img src="./images/elm-ui-course.webp" alt="course-img" /></a></p>
<p><code>elm-ui</code> is a package for layout and interface design. This is a novel iteration on declarative styling where you can use Elm types and functions to define your UI in a declarative way.</p>
<p>The novel part is that it <strong>does not require you to know CSS</strong> to be used. The API is very simple and can be learned quickly! 💅🏻</p>
<p>The approach taken by <code>elm-ui</code> is based on two big ideas: Getting the compiler to verify as much of the layout and styling as possible by defining them in Elm code Enabling refactoring capabilities of Elm for UI code.</p>
<h2 id="future-new-eggheadio-elm-course">Future new egghead.io Elm course!?</h2>
<p>If you would like me to work on a <a href="https://egghead.io/q?access_state=free">free community egghead.io resource</a> to learn Elm from scratch, you can please <a href="https://github.com/sponsors/kutyel/">sponsor my work on Github Sponsors</a> or just reach out to me on <a href="https://twitter.com/FlavioCorpa">Twitter</a> and let me know!</p>
<p>The more requests I get the more motivation I will have to put in the time and effort to create the next ultimate Elm learning resource! 🙌🏻</p></section>
  </article>
</main>

 <footer class="py-14 bg-[var(--footerBgColor)] shrink-0">
  <div class="relative mx-auto md:w-[600px] w-auto px-[1.3125rem]">
    <ul class="flex justify-center list-none" role="list">
      <li class="mx-3" role="listitem">
        <a href="/">Home</a>
      </li>
      <li class="mx-3" role="listitem">
        <a href="https://github.com/sponsors/kutyel/">Sponsor me</a>
      </li>
      <li class="mx-3" role="listitem">
        <a href="/atom.xml">RSS</a>
      </li>
    </ul>
  </div>
</footer>


<script src="https://gistcdn.githack.com/kutyel/41d12e099484fd390fb67168271fcdd9/raw/9be26e500525a2e4edacc53d3a8006aaddec0e15/bsky-comments.js"></script>
]]></description>
    <pubDate>Fri, 24 Feb 2023 12:07:00 UT</pubDate>
    <guid>https://flaviocorpa.com/declarative-uis-without-css-with-elm-ui.html</guid>
    <dc:creator>Flavio Corpa</dc:creator>
</item>
<item>
    <title>Haskell for Elm developers: giving names to stuff (Part 2 - Applicative Functors)</title>
    <link>https://flaviocorpa.com/haskell-for-elm-developers-giving-names-to-stuff-part-2-applicative-functors.html</link>
    <description><![CDATA[<nav class="my-6 py-2">
  <div class="relative mx-auto md:w-[600px] w-auto px-[1.3125rem] md:px-0" data-nav-wrap>
    <a class="mr-5 absolute left-[-10000px] focus:static focus:left-auto" href="#content"
      >Skip to content</a
    >
    <a class="mr-5" href="/">Home</a>
    <a class="mr-5" href="https://github.com/sponsors/kutyel">Sponsor me</a>
    <a class="mr-5" href="/atom.xml">RSS</a>
  </div>
</nav>


<style>
  bsky-comments {
    --background-color: var(--bgColor);
    --text-color: var(--textColor);
    --link-color: var(--textLinkColor);
    --link-hover-color: var(--textLinkHoverColor);
    --comment-meta-color: #888;
    --error-color: #ff4d4d;
    --reply-border-color: var(--separatorColor);
    --button-background-color: var(--btnBgColor);
    --button-hover-background-color: rgba(var(--btnBgColor), 0.2);
    --author-avatar-border-radius: 50%;
  }
</style>

<main class="flex-1" id="content" tabindex="-1">
  <article class="pb-10">
    <header class="bg-[var(--headerBgColor)] mb-8 px-[1.3125rem] md:px-0 py-4 md:py-8">
      <div class="mx-auto md:w-[600px]">
        <h1 class="text-[1.7rem] md:text-[3rem] m-0 mb-4 font-normal leading-[1.2] text-[var(--h1Color)]">
          Haskell for Elm developers: giving names to stuff (Part 2 - Applicative Functors)
        </h1>
        <div class="mx-auto md:w-[600px]">
          <small class="italic">23/02/2023</small>
          <small class="italic"> | 6 min read</small>
          
          <small class="italic"> (updated: 03/05/2023 15:22)</small>
          
          <div class="mt-2">[ <a title="All pages tagged &#39;haskell&#39;." href="/tags/haskell.html" rel="tag">haskell</a>, <a title="All pages tagged &#39;elm&#39;." href="/tags/elm.html" rel="tag">elm</a>, <a title="All pages tagged &#39;fp&#39;." href="/tags/fp.html" rel="tag">fp</a> ]</div>
        </div>
      </div>
    </header>
    <section class="mx-auto md:w-[600px] px-[1.3125rem] md:px-0"><p><img src="./images/haskell-elm.svg" alt="logo" width="300px"></p>
<p>Since the previous post had some measure of success, I decided to continue the series! 🎉</p>
<p>Without much preamble, let’s look at the typeclass definition in Haskell for Applicative Functors:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> (<span class="dt">Functor</span> f) <span class="ot">=&gt;</span> <span class="dt">Applicative</span> f <span class="kw">where</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="ot">  pure ::</span> a <span class="ot">-&gt;</span> f a</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="ot">  (&lt;*&gt;) ::</span> f (a <span class="ot">-&gt;</span> b) <span class="ot">-&gt;</span> f a <span class="ot">-&gt;</span> f b</span></code></pre></div>
<p>This looks a bit scarier 👻 at the beginning, but do not worry, we will explain every bit at a time.</p>
<p>The first thing we can notice is that the typeclass definition has itself a typeclass constraint! This is new for us, we did not know that could happen (until now), and this is what the <code>class Functor f =&gt;</code> bit means.</p>
<p><strong>What are the implications of this?</strong> Well, as you might have already guessed, it just means one simple thing: <em>every</em> Applicative Functor must be first a <em>valid Functor</em>, not a very big surprise, right? 😉</p>
<p>The second thing we can notice is that, contrary to the <code>Functor</code> typeclass declaration that specified only a function to be implemented (<code>fmap</code>), now we have 2 functions every Applicative Functor must have to satisfy the instance: <code>pure</code>, and the mysterious <code>&lt;*&gt;</code> operator, which we will call the TIE fighter operator from now on (because I love the name and yes, I’m a big STAR WARS fan 🤓).</p>
<p>Let’s talk about each of them separately but first, spoiler alert ⚠️, in Elm, some examples of Applicative Functors you use every day are: <code>List</code>, <code>Maybe</code>, <code>Result</code> and <code>Task</code>.</p>
<h2 id="the-pure-function">The <code>pure</code> function</h2>
<p>Out of the two needed functions, <code>pure</code> is probably the easiest to explain: it just “lifts” any value <code>a</code> into an Applicative Functor context <code>f</code>.</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="fu">pure</span><span class="ot"> ::</span> a <span class="ot">-&gt;</span> f a</span></code></pre></div>
<p>What are some examples of this in Elm? For example, the <code>List.singleton</code> function!</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> <span class="dt">List</span><span class="op">.</span><span class="fu">singleton</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="op">&lt;</span><span class="fu">function</span><span class="op">&gt;</span> : <span class="fu">a</span> <span class="op">-&gt;</span> <span class="dt">List</span> <span class="fu">a</span></span></code></pre></div>
<p>Okay, what about <code>Maybe</code>?</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> <span class="dt">Just</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="op">&lt;</span><span class="fu">function</span><span class="op">&gt;</span> : <span class="fu">a</span> <span class="op">-&gt;</span> <span class="dt">Maybe</span> <span class="fu">a</span></span></code></pre></div>
<p>This might be new for you, but <strong>data constructors are also functions!</strong> 🤯</p>
<p>This means that for <code>Maybe</code> we just have <em>one</em> <code>pure</code> function (<code>Nothing</code> is just a value, not a function), and you probably can guess what is the <code>pure</code> implementation for <code>Result</code>:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> <span class="dt">Ok</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="op">&lt;</span><span class="fu">function</span><span class="op">&gt;</span> : <span class="fu">value</span> <span class="op">-&gt;</span> <span class="dt">Result</span> <span class="fu">error</span> <span class="fu">value</span></span></code></pre></div>
<p>This example is a little harder to understand, because the <code>f</code> Applicative Functor <em>structure</em> is actually <code>Result error</code>, so that this matches:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="fu">pure</span><span class="ot"> ::</span> value <span class="ot">-&gt;</span> f            value</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Ok</span> <span class="op">:</span>    value <span class="ot">-&gt;</span> <span class="dt">Result</span> <span class="fu">error</span> value</span></code></pre></div>
<p>Note that, because of this, the <code>Err</code> contructor/function is <em>not</em> a correct implementation, since the Applicative Functor structure is not preserved:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> <span class="dt">Err</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="op">&lt;</span><span class="fu">function</span><span class="op">&gt;</span> : <span class="fu">error</span> <span class="op">-&gt;</span> <span class="dt">Result</span> <span class="fu">error</span> <span class="fu">value</span></span></code></pre></div>
<p>You can probably see here that there is no <code>f a</code> structure, so only <code>Ok</code> could be considered the correct implementation of <code>pure</code> for <code>Result</code>.</p>
<p>To keep with the Elm explanations, <code>Task.succeed</code> is the <code>pure</code> equivalent for the <code>Task</code> Applicative Functor:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> <span class="kw">import</span> <span class="dt">Task</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> <span class="dt">Task</span><span class="op">.</span><span class="fu">succeed</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="op">&lt;</span><span class="fu">function</span><span class="op">&gt;</span> : <span class="fu">a</span> <span class="op">-&gt;</span> <span class="dt">Task</span><span class="op">.</span><span class="dt">Task</span> <span class="fu">x</span> <span class="fu">a</span></span></code></pre></div>
<h2 id="the-tie-fighter-operator-">The TIE fighter operator (<code>&lt;*&gt;</code>)</h2>
<p>Now let us begin with the fun part:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="ot">(&lt;*&gt;) ::</span> f (a <span class="ot">-&gt;</span> b) <span class="ot">-&gt;</span> f a <span class="ot">-&gt;</span> f b</span></code></pre></div>
<p>This is an <em>infix operator</em> that takes a lifted function <code>f (a -&gt; b)</code> and a lifted value <code>f a</code> and somehow magically <em>applies</em> (that’s why sometimes this function is also refered to as <code>apply</code> or just <code>ap</code>) the lifted function to the lifted <code>a</code> to finally return a lifted <code>b</code> value (<code>f b</code>). But by now you should be wondering: <strong>how on Earth is this actually useful!? 🤔</strong></p>
<p>Well, let’s have a peek at the actual implementation of the <code>Applicative</code> typeclass in <code>GHC.Base</code>:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> (<span class="dt">Functor</span> f) <span class="ot">=&gt;</span> <span class="dt">Applicative</span> f <span class="kw">where</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>  <span class="ot">{-# MINIMAL pure, ((&lt;*&gt;) | liftA2) #-}</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- | Lift a value.</span></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a><span class="ot">  pure ::</span> a <span class="ot">-&gt;</span> f a</span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- | Sequential application.</span></span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a><span class="ot">  (&lt;*&gt;) ::</span> f (a <span class="ot">-&gt;</span> b) <span class="ot">-&gt;</span> f a <span class="ot">-&gt;</span> f b</span>
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a>  (<span class="op">&lt;*&gt;</span>) <span class="ot">=</span> liftA2 <span class="fu">id</span></span>
<span id="cb10-10"><a href="#cb10-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-11"><a href="#cb10-11" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- | Lift a binary function to actions.</span></span>
<span id="cb10-12"><a href="#cb10-12" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- ==== __Example__</span></span>
<span id="cb10-13"><a href="#cb10-13" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- &gt;&gt;&gt; liftA2 (,) (Just 3) (Just 5)</span></span>
<span id="cb10-14"><a href="#cb10-14" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- Just (3,5)</span></span>
<span id="cb10-15"><a href="#cb10-15" aria-hidden="true" tabindex="-1"></a><span class="ot">  liftA2 ::</span> (a <span class="ot">-&gt;</span> b <span class="ot">-&gt;</span> c) <span class="ot">-&gt;</span> f a <span class="ot">-&gt;</span> f b <span class="ot">-&gt;</span> f c</span>
<span id="cb10-16"><a href="#cb10-16" aria-hidden="true" tabindex="-1"></a>  liftA2 f x <span class="ot">=</span> (<span class="op">&lt;*&gt;</span>) (<span class="fu">fmap</span> f x)</span></code></pre></div>
<p>First thing we notice is that there is a <a href="https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/pragmas.html#minimal-pragma">MINIMAL pragma</a>, this tells GHC (the main compiler of Haskell) that the required functions that a type needs to implement in order to have a valid <code>Applicative</code> instance are <code>pure</code> and <code>&lt;*&gt;</code> OR <code>liftA2</code>.</p>
<p>Second thing we can notice, is that <code>&lt;*&gt;</code> and <code>liftA2</code> are almost identical: they are defined in terms of each other! 🤯</p>
<p>So, <code>liftA2</code> is basically:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a>liftA2 f x <span class="ot">=</span> (<span class="op">&lt;*&gt;</span>) (<span class="fu">fmap</span> f x)</span></code></pre></div>
<p>And, the TIE fighter operator is just:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a>(<span class="op">&lt;*&gt;</span>) <span class="ot">=</span> liftA2 <span class="fu">id</span></span></code></pre></div>
<p>The <code>id</code> function is the silliest function in Haskell: <code>id :: a -&gt; a</code> and in Elm is properly called <code>identity</code>:</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> <span class="fu">identity</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="op">&lt;</span><span class="fu">function</span><span class="op">&gt;</span> : <span class="fu">a</span> <span class="op">-&gt;</span> <span class="fu">a</span></span></code></pre></div>
<p>The fact that these two functions are defined in terms of each other, just means that you need to implement one of them, and you will <a href="https://www.reddit.com/r/haskell/comments/11a54oh/comment/j9szz9k/?utm_source=share&amp;utm_medium=web2x&amp;context=3">get the other one for free</a>. But, leaving that behind us, does not the type declaration of <code>liftA2</code> look familiar to us Elm developers? 👀</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="ot">liftA2 ::</span> (a <span class="ot">-&gt;</span> b <span class="ot">-&gt;</span> c) <span class="ot">-&gt;</span> f a <span class="ot">-&gt;</span> f b <span class="ot">-&gt;</span> f c</span></code></pre></div>
<p>Besides, looking at the example code given, can we achieve something similar in Elm?</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- ==== __Example__</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- &gt;&gt;&gt; liftA2 (,) (Just 3) (Just 5)</span></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a><span class="co">-- Just (3,5)</span></span></code></pre></div>
<p>The answer is: yes, we can! 🚀</p>
<div class="sourceCode" id="cb16"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> <span class="dt">Maybe</span><span class="op">.</span><span class="fu">map2</span> <span class="dt">Tuple</span><span class="op">.</span><span class="fu">pair</span> (<span class="dt">Just</span> <span class="dv">3</span>) (<span class="dt">Just</span> <span class="dv">5</span>)</span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> (<span class="dv">3</span><span class="op">,</span><span class="dv">5</span>) : <span class="dt">Maybe</span> ( <span class="fu">number</span><span class="op">,</span> <span class="fu">number1</span> )</span></code></pre></div>
<p>Remember how I told you on the previous post that infix operators were just superior in Haskell? We are not able to do this <code>(,)</code> in Elm, so we need to resign ourselves to just use <code>Tuple.pair : a -&gt; b -&gt; ( a, b )</code>, which does basically the same.</p>
<p>If we query the Elm REPL for the type of <code>Maybe.map2</code>, we get:</p>
<div class="sourceCode" id="cb17"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> <span class="dt">Maybe</span><span class="op">.</span><span class="fu">map2</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a><span class="op">&lt;</span><span class="fu">function</span><span class="op">&gt;</span> : (<span class="fu">a</span> <span class="op">-&gt;</span> <span class="fu">b</span> <span class="op">-&gt;</span> <span class="fu">value</span>) <span class="op">-&gt;</span> <span class="dt">Maybe</span> <span class="fu">a</span> <span class="op">-&gt;</span> <span class="dt">Maybe</span> <span class="fu">b</span> <span class="op">-&gt;</span> <span class="dt">Maybe</span> <span class="fu">value</span></span></code></pre></div>
<p>Compare this to the type of <code>liftA2</code> again:</p>
<div class="sourceCode" id="cb18"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="fu">liftA2</span>     <span class="op">::</span> (<span class="fu">a</span> <span class="op">-&gt;</span> <span class="fu">b</span> <span class="op">-&gt;</span> <span class="fu">value</span>) <span class="op">-&gt;</span> <span class="fu">f</span> <span class="fu">a</span>     <span class="op">-&gt;</span> <span class="fu">f</span> <span class="fu">b</span>     <span class="op">-&gt;</span> <span class="fu">f</span> <span class="fu">c</span></span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Maybe</span><span class="op">.</span><span class="fu">map2</span>  : (<span class="fu">a</span> <span class="op">-&gt;</span> <span class="fu">b</span> <span class="op">-&gt;</span> <span class="fu">value</span>) <span class="op">-&gt;</span> <span class="dt">Maybe</span> <span class="fu">a</span> <span class="op">-&gt;</span> <span class="dt">Maybe</span> <span class="fu">b</span> <span class="op">-&gt;</span> <span class="dt">Maybe</span> <span class="fu">value</span></span></code></pre></div>
<p>You guessed it correctly: the <code>liftA2</code> equivalent in Elm are all the <code>*.map2</code> functions we can find!</p>
<p>So, when we said before that <code>List</code>, <code>Maybe</code>, <code>Result</code> and <code>Task</code> were <strong>Applicative Functors in Elm</strong>, is because we have <code>List.map2</code>, <code>Maybe.map2</code>, <code>Result.map2</code> and <code>Task.map2</code>.</p>
<p>This ties in nicely with an excellent article published by <a href="https://twitter.com/joelquen">Joël Quenneville</a> some time ago, called <a href="https://thoughtbot.com/blog/running-out-of-maps">“Running Out of Maps”</a> (very nice pun btw 😜).</p>
<p>In that post, he explains that if anytime you run out of <code>mapN</code> functions, you can define this simple combinator:</p>
<div class="sourceCode" id="cb19"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a><span class="fu">andMap</span> <span class="op">=</span> <span class="dt">Maybe</span><span class="op">.</span><span class="fu">map2</span> (<span class="op">|&gt;</span>)</span></code></pre></div>
<p>And if we query again the Elm REPL for the type of <code>andMap</code> we get the following:</p>
<div class="sourceCode" id="cb20"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> <span class="fu">andMap</span> <span class="op">=</span> <span class="dt">Maybe</span><span class="op">.</span><span class="fu">map2</span> (<span class="op">|&gt;</span>)</span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a><span class="op">&lt;</span><span class="fu">function</span><span class="op">&gt;</span> : <span class="dt">Maybe</span> <span class="fu">a</span> <span class="op">-&gt;</span> <span class="dt">Maybe</span> (<span class="fu">a</span> <span class="op">-&gt;</span> <span class="fu">value</span>) <span class="op">-&gt;</span> <span class="dt">Maybe</span> <span class="fu">value</span></span></code></pre></div>
<p>Am gonna casually remind you right now about the type declaration of the TIE fighter operator, in case you forgot:</p>
<div class="sourceCode" id="cb21"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a><span class="ot">(&lt;*&gt;) ::</span> f (a <span class="ot">-&gt;</span> b) <span class="ot">-&gt;</span> f a <span class="ot">-&gt;</span> f b</span></code></pre></div>
<p><strong>What can we draw from all this crazyness?</strong></p>
<p>We just FOUND THE TIE FIGHTER OPERATOR IN ELM! It is just <code>flip andMap</code>!! 😎</p>
<p><strong>So why all of this is important again and when the heck am I going to use Applicative Functors (I hear your mind saying 🧠💭)???</strong></p>
<p>Well, if you have ever used the <code>Json.Decode.Extra</code> package, you might have probably written code like this:</p>
<div class="sourceCode" id="cb22"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a><span class="fu">decoder</span> : <span class="dt">Decoder</span> <span class="dt">Document</span></span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a><span class="fu">decoder</span> <span class="op">=</span></span>
<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Decode</span><span class="op">.</span><span class="fu">succeed</span> <span class="dt">Document</span></span>
<span id="cb22-4"><a href="#cb22-4" aria-hidden="true" tabindex="-1"></a>        <span class="op">|&gt;</span> <span class="dt">Decode</span><span class="op">.</span><span class="fu">andMap</span> (<span class="dt">Decode</span><span class="op">.</span><span class="fu">field</span> <span class="st">&quot;id&quot;</span> <span class="dt">Decode</span><span class="op">.</span><span class="fu">string</span>)</span>
<span id="cb22-5"><a href="#cb22-5" aria-hidden="true" tabindex="-1"></a>        <span class="op">|&gt;</span> <span class="dt">Decode</span><span class="op">.</span><span class="fu">andMap</span> (<span class="dt">Decode</span><span class="op">.</span><span class="fu">field</span> <span class="st">&quot;title&quot;</span> <span class="dt">Decode</span><span class="op">.</span><span class="fu">string</span>)</span>
<span id="cb22-6"><a href="#cb22-6" aria-hidden="true" tabindex="-1"></a>        <span class="op">|&gt;</span> <span class="dt">Decode</span><span class="op">.</span><span class="fu">andMap</span> <span class="fu">documentTypeDecoder</span></span>
<span id="cb22-7"><a href="#cb22-7" aria-hidden="true" tabindex="-1"></a>        <span class="op">|&gt;</span> <span class="dt">Decode</span><span class="op">.</span><span class="fu">andMap</span> (<span class="dt">Decode</span><span class="op">.</span><span class="fu">field</span> <span class="st">&quot;ctime&quot;</span> <span class="dt">Iso8601</span><span class="op">.</span><span class="fu">decoder</span>)</span>
<span id="cb22-8"><a href="#cb22-8" aria-hidden="true" tabindex="-1"></a>        <span class="op">|&gt;</span> <span class="dt">Decode</span><span class="op">.</span><span class="fu">andMap</span> (<span class="dt">Decode</span><span class="op">.</span><span class="fu">field</span> <span class="st">&quot;mtime&quot;</span> <span class="dt">Iso8601</span><span class="op">.</span><span class="fu">decoder</span>)</span></code></pre></div>
<p>The exact same code in Haskell, using our beloved infix operators, would look like this:</p>
<div class="sourceCode" id="cb23"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true" tabindex="-1"></a><span class="ot">decoder ::</span> <span class="dt">Decoder</span> <span class="dt">Document</span></span>
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a>decoder <span class="ot">=</span></span>
<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Document</span></span>
<span id="cb23-4"><a href="#cb23-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">&lt;$&gt;</span> decodeStringField <span class="st">&quot;id&quot;</span></span>
<span id="cb23-5"><a href="#cb23-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">&lt;*&gt;</span> decodeStringField <span class="st">&quot;title&quot;</span></span>
<span id="cb23-6"><a href="#cb23-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">&lt;*&gt;</span> documentTypeDecoder</span>
<span id="cb23-7"><a href="#cb23-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">&lt;*&gt;</span> decodeIso8601Field <span class="st">&quot;ctime&quot;</span></span>
<span id="cb23-8"><a href="#cb23-8" aria-hidden="true" tabindex="-1"></a>    <span class="op">&lt;*&gt;</span> decodeIso8601Field <span class="st">&quot;mtime&quot;</span></span></code></pre></div>
<p>This means two things:</p>
<ol>
<li>You have been using Applicative Functors all along for a very long time probably without notice! 🥁🥁🥁</li>
<li>Of course, this also means that <a href="https://package.elm-lang.org/packages/elm-community/json-extra/latest/Json-Decode-Extra#andMap">Json.Decode.Decoder</a> is also an Applicative Functor!! 👏🏻</li>
</ol>
<h2 id="acknowledgements">Acknowledgements</h2>
<p>Many people has made possible the production of this blogpost, I want to personally thank <a href="https://twitter.com/RobertWPearce">Robert Pearce</a> for his excellent <a href="https://robertwpearce.com/the-hakyll-nix-template-tutorial.html">Hakyll + Nix tutorial</a>, and <a href="https://twitter.com/domenkozar">Domen Kožar</a>, for all his work with <a href="https://www.cachix.org/">Cachix</a> and the <a href="https://nixos.org/">Nix</a> ecosystem in general (and for his infinite patience 😇).</p>
<p>I would also like to thank <a href="https://twitter.com/bitemyapp">Chris Allen</a> and <a href="https://twitter.com/argumatronic">Julie Moronukie</a>, because together they created the <a href="https://haskellbook.com/">Haskell Book™️</a>, which is still in my opinion <strong>the best possible way to learn Haskell</strong> and it is actually the reason I am today working with Haskell.</p>
<p>Could not be more grateful to all of them! 😍</p>
<p>Enough bad puns for today, hope you learned something new! If you enjoyed this post and would like me to continue the series (<em>next up would probably be MOOONAAAAAADSSSS 👻🦇🦇🦇</em>), please share it in your social networks and <strong>follow me on <a href="https://twitter.com/FlavioCorpa">Twitter</a>!</strong> 🙌🏻</p></section>
  </article>
</main>

 <footer class="py-14 bg-[var(--footerBgColor)] shrink-0">
  <div class="relative mx-auto md:w-[600px] w-auto px-[1.3125rem]">
    <ul class="flex justify-center list-none" role="list">
      <li class="mx-3" role="listitem">
        <a href="/">Home</a>
      </li>
      <li class="mx-3" role="listitem">
        <a href="https://github.com/sponsors/kutyel/">Sponsor me</a>
      </li>
      <li class="mx-3" role="listitem">
        <a href="/atom.xml">RSS</a>
      </li>
    </ul>
  </div>
</footer>


<script src="https://gistcdn.githack.com/kutyel/41d12e099484fd390fb67168271fcdd9/raw/9be26e500525a2e4edacc53d3a8006aaddec0e15/bsky-comments.js"></script>
]]></description>
    <pubDate>Thu, 23 Feb 2023 12:22:00 UT</pubDate>
    <guid>https://flaviocorpa.com/haskell-for-elm-developers-giving-names-to-stuff-part-2-applicative-functors.html</guid>
    <dc:creator>Flavio Corpa</dc:creator>
</item>
<item>
    <title>Haskell for Elm developers: giving names to stuff (Part 1 - Functors)</title>
    <link>https://flaviocorpa.com/haskell-for-elm-developers-giving-names-to-stuff-part-1-functors.html</link>
    <description><![CDATA[<nav class="my-6 py-2">
  <div class="relative mx-auto md:w-[600px] w-auto px-[1.3125rem] md:px-0" data-nav-wrap>
    <a class="mr-5 absolute left-[-10000px] focus:static focus:left-auto" href="#content"
      >Skip to content</a
    >
    <a class="mr-5" href="/">Home</a>
    <a class="mr-5" href="https://github.com/sponsors/kutyel">Sponsor me</a>
    <a class="mr-5" href="/atom.xml">RSS</a>
  </div>
</nav>


<style>
  bsky-comments {
    --background-color: var(--bgColor);
    --text-color: var(--textColor);
    --link-color: var(--textLinkColor);
    --link-hover-color: var(--textLinkHoverColor);
    --comment-meta-color: #888;
    --error-color: #ff4d4d;
    --reply-border-color: var(--separatorColor);
    --button-background-color: var(--btnBgColor);
    --button-hover-background-color: rgba(var(--btnBgColor), 0.2);
    --author-avatar-border-radius: 50%;
  }
</style>

<main class="flex-1" id="content" tabindex="-1">
  <article class="pb-10">
    <header class="bg-[var(--headerBgColor)] mb-8 px-[1.3125rem] md:px-0 py-4 md:py-8">
      <div class="mx-auto md:w-[600px]">
        <h1 class="text-[1.7rem] md:text-[3rem] m-0 mb-4 font-normal leading-[1.2] text-[var(--h1Color)]">
          Haskell for Elm developers: giving names to stuff (Part 1 - Functors)
        </h1>
        <div class="mx-auto md:w-[600px]">
          <small class="italic">27/01/2023</small>
          <small class="italic"> | 6 min read</small>
          
          <div class="mt-2">[ <a title="All pages tagged &#39;haskell&#39;." href="/tags/haskell.html" rel="tag">haskell</a>, <a title="All pages tagged &#39;elm&#39;." href="/tags/elm.html" rel="tag">elm</a>, <a title="All pages tagged &#39;fp&#39;." href="/tags/fp.html" rel="tag">fp</a> ]</div>
        </div>
      </div>
    </header>
    <section class="mx-auto md:w-[600px] px-[1.3125rem] md:px-0"><p><img src="./images/haskell-elm.svg" alt="logo" width="300px"></p>
<p>This post is targeted towards all those Elm developers (and functional programmers in general) who are curious about Haskell and would like to learn how what they already know and love from Elm maps directly to Haskell.</p>
<p>Also, since Haskell’s feature set and syntax are wider than Elm’s, of course I’ll need to try and fill the gaps and explain certain things that just do not exist in Elm. 😉</p>
<p>If this first post gets enough attention, I might consider adding more follow up posts and turn this into a series (hopefully).</p>
<h2 id="lets-talk-about-functors">Let’s talk about <code>Functor</code>s!</h2>
<p>If you have ever seen Haskell code before, you can really tell it has greatly influenced Elm syntax, one of the biggest differences is that in Haskell type declarations are preceded by <code>::</code>, whereas in Elm only by <code>:</code>.</p>
<p>Another big difference is that in Haskell there is a concept called <strong>typeclasses</strong>, which we can explain more or less saying that they group a class of types and help us define interfaces that a certain data type need to fulfil to be considered “an instance of that specific typeclass”.</p>
<p>For example, the Functor typeclass in Haskell is defined like this:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Functor</span> f <span class="kw">where</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="ot">  fmap ::</span> (a <span class="ot">-&gt;</span> b) <span class="ot">-&gt;</span> f a <span class="ot">-&gt;</span> f b</span></code></pre></div>
<p>This typeclass declaration in Haskell just means that for a general type <code>f</code>, it will “be a Functor” if it has a map function. As you can see, any map function (or fmap) needs to have the signature <code>(a -&gt; b) -&gt; f a -&gt; f b</code>. More accurately, we can say that any custom type that implements a function with this type signature <strong>does have an instance of the Functor typeclass</strong>.</p>
<p>I probably do not need to explain what the (f)map function does, as you are already using Functors in Elm every single day! 🤯 To list some of them: <code>List</code>, <code>Maybe</code>, <code>Result</code>, <code>Dict</code>, <code>Task</code>, etc…</p>
<p>Why is that typeclass called <strong>Functor</strong> instead of <strong>Mappable</strong>? 🤷🏼‍♂️</p>
<p><strong>Why is this important?</strong> Well, I think one of the design decisions for Elm was to be simple from the beginning and not bother people with buzzwords, just let them use the code and gain intuition about how things work and that will do. But unfortunately if we want to learn Haskell after Elm we need to start putting random names on things! 😉</p>
<h2 id="infix-operators-are-nice-actually">Infix operators are nice, actually</h2>
<p>Yet another big difference between Haskell and Elm is obviously Haskellers love for <em>infix operators</em>. For example, instead of using fmap you could use the <code>&lt;$&gt;</code> operator. Consider the following mundane Elm code:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a>[<span class="dv">1</span><span class="op">,</span><span class="dv">2</span><span class="op">,</span><span class="dv">3</span><span class="op">,</span><span class="dv">4</span>] <span class="op">|&gt;</span> <span class="dt">List</span><span class="op">.</span><span class="fu">map</span> ((<span class="op">*</span>) <span class="dv">2</span>) <span class="co">-- &gt; [2,4,6,8] : List number</span></span></code></pre></div>
<p>This would be possible to write in many different styles in Haskell:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="fu">fmap</span> (<span class="op">*</span><span class="dv">2</span>) [<span class="dv">1</span><span class="op">..</span><span class="dv">4</span>]    <span class="co">-- &gt; [2,4,6,8]</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="fu">map</span> (<span class="op">*</span><span class="dv">2</span>) [<span class="dv">1</span><span class="op">..</span><span class="dv">4</span>]     <span class="co">-- &gt; [2,4,6,8]</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>(<span class="op">*</span><span class="dv">2</span>) <span class="op">&lt;$&gt;</span> [<span class="dv">1</span><span class="op">..</span><span class="dv">4</span>]     <span class="co">-- &gt; [2,4,6,8]</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>[<span class="dv">1</span><span class="op">..</span><span class="dv">4</span>] <span class="op">&lt;&amp;&gt;</span> (<span class="op">*</span><span class="dv">2</span>)     <span class="co">-- &gt; [2,4,6,8]</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>(<span class="op">*</span><span class="dv">2</span>) <span class="ot">`fmap`</span> [<span class="dv">1</span><span class="op">..</span><span class="dv">4</span>]  <span class="co">-- &gt; [2,4,6,8]</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>(<span class="op">*</span><span class="dv">2</span>) <span class="ot">`map`</span> [<span class="dv">1</span><span class="op">..</span><span class="dv">4</span>]   <span class="co">-- &gt; [2,4,6,8]</span></span></code></pre></div>
<p>There are quite a few things to learn from this snippet alone:</p>
<ol>
<li>Notice that <code>map</code> is just a more specific implementation of <code>fmap</code> that in Haskell only works with <code>List</code>s!</li>
<li>In Haskell we have some nice syntax sugar for ranges of things, where <code>[1..4]</code> is equivalent to <code>List.range 1 4</code> in Elm.</li>
<li>It is easier to work with infix operators and partially applied functions in Haskell generally speaking, where adding a parameter to either side of the operator would mean completely different things if that operation is not commutative (<code>2^</code> vs <code>^2</code>).</li>
<li>Any function in Haskell can be used as an infix operator with backticks (like in lines 5 and 6 of the Haskell snippet, this feels weird at the beginning, but sometimes it actually helps readability!).</li>
<li>If you need a flipped version of <code>&lt;$&gt;</code> for some reason, you can import it from <code>Data.Functor</code> and it is called <code>&lt;&amp;&gt;</code> 🙈.</li>
</ol>
<p><strong>Why is this nice?</strong> I won’t argue if this is better or worse, but at least we have more options in the language to express things!</p>
<p>What you haven’t been told is that <strong>Elm does actually have typeclasses</strong>! 😱 Noticed that <code>number</code> type in the previous snippet? <code>comparable</code> and <code>appendable</code> are other examples of typeclasses used in <code>elm/core</code>, so typeclasses exist in the language but we as users of Elm can’t define them, only its creator… 😜</p>
<h2 id="why-haskell-and-typeclasses-are-correct">Why Haskell and typeclasses are correct!</h2>
<p>This part is a little rant and totally subjective to how I view programming, but some time ago I tweeted this:</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Are you sure we don&#39;t need typeclasses? 😅 <a href="https://t.co/grL1GUH4K4">pic.twitter.com/grL1GUH4K4</a></p>&mdash; フラビオ🥷🏼 (@FlavioCorpa) <a href="https://twitter.com/FlavioCorpa/status/1570739010322169856?ref_src=twsrc%5Etfw">September 16, 2022</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>Now it is the perfect time to explain myself in more detail! (And without trying to offend anyone 😉).</p>
<p>I think the fact that we have to write such boilerplate code is a <em>mistake</em>, if <code>Result</code> is a functor, and <code>Cmd</code> too, <strong>we should not need to have to write</strong> that mapping function manually! In Haskell, you could achieve this easily like this:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# language DeriveFunctor #-}</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="co">-- ...</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">HttpCmd</span> err a</span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>  <span class="ot">=</span> <span class="dt">HttpCmd</span> (<span class="dt">Cmd</span> (<span class="dt">Result</span> (<span class="dt">Error</span> err) a))</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Functor</span>)</span></code></pre></div>
<p>By creating a <strong>newtype</strong> instead of a type alias and using some special Haskell magic, now we could just use <code>fmap</code> or <code>&lt;$&gt;</code> and never have to write such function by hand!</p>
<p>Of course you could still write the <code>fmap</code> function for this custom type by hand, but one of the nicest things about Haskell in my opinion is that it provides <em>deriving mechanisms</em> to implement things for free for us. One such mechanism is the <code>DeriveFunctor</code> language extension.</p>
<p>If we chose to keep the type alias approach we could have written the same function in Haskell this way:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="ot">httpCmdMap ::</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>  (<span class="dt">Functor</span> f1, <span class="dt">Functor</span> f2) <span class="ot">=&gt;</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>  (a <span class="ot">-&gt;</span> b) <span class="ot">-&gt;</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>  f1 (f2 a) <span class="ot">-&gt;</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>  f1 (f2 b)</span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a>httpCmdMap f <span class="ot">=</span> <span class="fu">fmap</span> (<span class="fu">fmap</span> f)</span></code></pre></div>
<p>This is another difference with Elm: whatever we see to the left of the fat arrow (<code>=&gt;</code>) in the type declaration, are called <strong>typeclass constraints</strong>, and what they mean in this specific case is that whatever type we use for <code>f1</code> and <code>f2</code>, they need to <em>have an instance of the <code>Functor</code> typeclass</em>.</p>
<p>As you might have noticed, Haskell has a compiler extension system that allow us to toggle additional features to the language, this is exactly what <code>{-# language DeriveFunctor #-}</code> does.</p>
<p>I am not saying we should have this in Elm (in fact, many complains about Haskell lie in the fact that we have probably <strong>too many language extensions</strong> already! 🙈) but, having types of classes that share common interfaces and being able to re-use functions and infix operators in many different types is a win-win from my perspective! 🚀</p>
<h2 id="a-small-note-on-function-composition">A small note on function composition</h2>
<p>I’ve seen many Elm developers (specially people learning the language, or new to functional programming in general) use the following pattern, which feels a bit wrong to me:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="fu">someListOfAs</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>    <span class="op">|&gt;</span> <span class="dt">List</span><span class="op">.</span><span class="fu">map</span> <span class="fu">turnAtoB</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>    <span class="op">|&gt;</span> <span class="dt">List</span><span class="op">.</span><span class="fu">map</span> <span class="fu">turnBtoC</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">|&gt;</span> <span class="dt">List</span><span class="op">.</span><span class="fu">map</span> <span class="fu">turnCtoD</span> <span class="co">-- &gt; List d</span></span></code></pre></div>
<p>Whenever you map something multiple times, we can make use of the fact that we can always <em>map once</em>, and <strong>compose N functions</strong> together!</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode elm"><code class="sourceCode elm"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- please do this instead 🙏🏻</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="fu">someListOfAs</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>    <span class="op">|&gt;</span> <span class="dt">List</span><span class="op">.</span><span class="fu">map</span> (<span class="fu">turnAtoB</span> <span class="op">&gt;&gt;</span> <span class="fu">turnBtoC</span> <span class="op">&gt;&gt;</span> <span class="fu">turnCtoD</span>)</span></code></pre></div>
<p>Since piping stuff with <code>|&gt;</code> is the bread and butter of Elm, people do not really stop and think that they can combine multiple operations at once, but hey! That’s why we have function composition and everything is curried by default in Elm, so let’s make use of it! 🤓</p>
<p>And here is a mini point in favor of Elm, the operators chosen for the language are <strong>much more readable</strong> in my opinion than the ones in Haskell, mainly:</p>
<ol>
<li>left to right composition: <code>&gt;&gt;</code> in Elm, <code>Control.Arrow.&gt;&gt;&gt;</code> in Haskell (not even in the Prelude! 😭).</li>
<li>right to left composition: <code>&lt;&lt;</code> in Elm, just <code>.</code> in Haskell, which is very weird for newcomers. 😕</li>
<li>left to right function application: <code>|&gt;</code> in Elm (the beloved pipe), <code>&amp;</code> in Haskell, absolutely terrible, no wonder it is not as commonly used as in Elm. 🥲</li>
<li>right to left function application: <code>&lt;|</code> in Elm, <code>$</code> in Haskell, which is probably one of the <a href="https://www.fpcomplete.com/haskell/tutorial/operators/">most widely used operators</a> and not very readable when you are learning Haskell at all! 🫢</li>
</ol>
<h2 id="acknowledgements">Acknowledgements</h2>
<p>I had the initial idea for this blogpost on a plane ✈️ back to Spain but what really motivated me was to try and share my love for Haskell with some very special Elm engineers that had to put up with me for some time and to which I would like to give special thanks: <a href="https://twitter.com/TomasLatal">@tomaslatal</a>, <a href="https://twitter.com/janiczek">@janiczek</a> and <a href="https://twitter.com/kurnick">@janjelinek</a>. 🙌🏻</p>
<p>I hope you all enjoyed this post, learned a thing or two and enticed you to learn a little more of Haskell. 😉</p>
<p>Also I want to give a huge kudos to <a href="https://twitter.com/trupill">@serras</a> for proofreading this post 😘.</p>
<p>If you enjoyed this post and would like to see this turned into a series (<em>I have ideas in my head already for posts about Applicatives, Monads, IO, parser combinators, etc.</em>), please share it in your social networks and <strong>follow me on <a href="https://twitter.com/FlavioCorpa">Twitter</a>!</strong> 🙌🏻</p></section>
  </article>
</main>


<bsky-comments post="at://did:plc:dvrocvv5szl2evqiafsx4iyw/app.bsky.feed.post/3lacoolte652w"></bsky-comments>
 <footer class="py-14 bg-[var(--footerBgColor)] shrink-0">
  <div class="relative mx-auto md:w-[600px] w-auto px-[1.3125rem]">
    <ul class="flex justify-center list-none" role="list">
      <li class="mx-3" role="listitem">
        <a href="/">Home</a>
      </li>
      <li class="mx-3" role="listitem">
        <a href="https://github.com/sponsors/kutyel/">Sponsor me</a>
      </li>
      <li class="mx-3" role="listitem">
        <a href="/atom.xml">RSS</a>
      </li>
    </ul>
  </div>
</footer>


<script src="https://gistcdn.githack.com/kutyel/41d12e099484fd390fb67168271fcdd9/raw/9be26e500525a2e4edacc53d3a8006aaddec0e15/bsky-comments.js"></script>
]]></description>
    <pubDate>Fri, 27 Jan 2023 15:01:00 UT</pubDate>
    <guid>https://flaviocorpa.com/haskell-for-elm-developers-giving-names-to-stuff-part-1-functors.html</guid>
    <dc:creator>Flavio Corpa</dc:creator>
</item>

    </channel>
</rss>
