<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Chris Penner</title>
    <link href="https://chrispenner.ca/atom.xml" rel="self" type="application/rss+xml" />
  <updated>2026-07-30T21:55:55.469195175Z</updated>
  <author>
      <name>Chris Penner</name>
  </author>
  <id>https://chrispenner.ca/</id>

  <entry>
      <title>Ditch your (mut)ex, you deserve better</title>
      <link href="https://chrispenner.ca/posts/mutexes"/>
      <id>https://chrispenner.ca/posts/mutexes</id>
      <updated>2025-11-11T00:00:00Z</updated>
      <summary>Mutexes are unreliable tools, let&#39;s explore better alternatives.</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/parallel-pipes.jpg" alt="Ditch your (mut)ex, you deserve better">
              <p>Having access to multiple parallel CPU cores isn't a new thing by any
means, people have been programming in parallel for half a century now,
but recent years we've found ourselves at an inflection point. Moore's
law is dying, beefy single cores are no longer keeping up. Modern
computers come with multiple CPU cores, so exploiting parallel compute
is more important than ever. Given how long it's been an area of
research we can naturally expect that effective tools have taken root
and that synchronizing threads is trivial now right...?</p>
<p>Unfortunately this has not been my experience, and I'm willing to bet
it hasn't been yours either. Managing shared state across threads is
hard, and the most commonly used tools: mutexes and semaphores, simply
haven't evolved much since their inception.</p>
<p>The words that follow will dig into the problems inherent to mutexes
and synchronizing shared mutable state. Afterwards we'll look into other
avenues which should prove more helpful.</p>
<h2 id="the-problem-with-shared-state">The Problem with Shared
State</h2>
<p>Let's begin by crafting a simple software system which needs
synchronization in the first place.</p>
<p>I'll present a commonly used example: the task of managing bank
account balances correctly in spite of parallel transfer requests.</p>
<p>Of course real banks don't store all their account balances in RAM,
so I'll hope that the reader can apply the concepts from this
pedagogical example to a their own domain as necessary, it serves as a
stand-in for any sufficiently complex system which requires ad-hoc
synchronization of arbitrary data between multiple threads.</p>
<p>Here's some golang'ish pseudo-code (please don't try to actually
compile it) for a simple bank account and the operations upon it. I'm
focused on the synchronization problems here, so forgive me for skipping
the double-entry accounting, input validation, and other real-world
complexities.</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode go"><code class="sourceCode go"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Account <span class="op">{</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>  balance <span class="dt">int</span><span class="op">,</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</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">// Deposit money into an account</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="kw">func</span> <span class="op">(</span>a <span class="op">*</span>Account<span class="op">)</span> deposit<span class="op">(</span>amount <span class="dt">int</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>  a<span class="op">.</span>balance <span class="op">+=</span> amount</span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a><span class="co">// Withdraw money from an account, or return false if there are insufficient funds</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a><span class="kw">func</span> <span class="op">(</span>a <span class="op">*</span>Account<span class="op">)</span> withdraw<span class="op">(</span>amount <span class="dt">int</span><span class="op">)</span> <span class="dt">bool</span> <span class="op">{</span></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="op">(</span>a<span class="op">.</span>balance <span class="op">&lt;=</span> amount<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="ot">false</span></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a>    balance <span class="op">-=</span> amount</span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="ot">true</span></span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Great! This defines our Account type and some methods for withdrawing
and depositing money into such an account. Now let's add a function to
transfer money between accounts:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode go"><code class="sourceCode go"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">func</span> transfer<span class="op">(</span>from <span class="op">*</span>Account<span class="op">,</span> to <span class="op">*</span>Account<span class="op">,</span> amount <span class="dt">int</span><span class="op">)</span> <span class="dt">bool</span> <span class="op">{</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="op">(</span>from<span class="op">.</span>withdraw<span class="op">(</span>amount<span class="op">))</span> <span class="op">{</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>    to<span class="op">.</span>deposit<span class="op">(</span>amount<span class="op">)</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="ot">true</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="ot">false</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Looks good, but now what happens when we start handling multiple
requests concurrently?</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode go"><code class="sourceCode go"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> TransferRequest <span class="op">{</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>  from <span class="op">*</span>Account<span class="op">,</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>  to <span class="op">*</span>Account<span class="op">,</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>  amount <span class="dt">int</span><span class="op">,</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></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">func</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>  <span class="co">// loop forever, accepting transfer requests and processing them in goroutines</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">{</span></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a>    req <span class="op">:=</span> acceptTransferRequest<span class="op">()</span></span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a>    <span class="cf">go</span> transfer<span class="op">(</span>req<span class="op">.</span>from<span class="op">,</span> req<span class="op">.</span>to<span class="op">,</span> req<span class="op">.</span>amount<span class="op">)</span></span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Things may work well in your tests if you're (un)lucky, and might
even work well in production for a while, but sooner or later you're
going to lose track of money and have some confused and angry
customers.</p>
<p>Do you see why? This brings us to our first synchronization problem
to solve, <strong>Data Races</strong>.</p>
<h3 id="data-races">Data races</h3>
<p><strong>Most</strong> programming languages are imperative with
mutable data structures <strong>[citation needed]</strong>, so passing
pointers to multiple threads leads to <em>shared mutable data</em>, and
<em>shared mutable data</em> necessarily causes <em>data races</em>.</p>
<p>A data race occurs any time two threads access the same memory
location concurrently and non-deterministically when at least one of the
accesses is a write. When a data race is present two runs of the same
code with the same state may non-deterministically have a different
result.</p>
<p>We're passing accounts by reference here, so multiple threads have
access to modify the same account. With multiple transfer go-routines
running on the same account, each could be paused by the scheduler at
nearly any point during its execution. This means that even within this
simple example we've already introduced a data race. Take another look
at the <code>withdraw</code> function, I'll point it out:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode go"><code class="sourceCode go"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Withdraw money from an account, or return false if there are insufficient funds</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="kw">func</span> <span class="op">(</span>a <span class="op">*</span>Account<span class="op">)</span> withdraw<span class="op">(</span>amount <span class="dt">int</span><span class="op">)</span> <span class="dt">bool</span> <span class="op">{</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>  hasFunds <span class="op">:=</span> a<span class="op">.</span>balance <span class="op">&gt;=</span> amount </span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>  <span class="co">// HERE! The scheduler could pause execution here and switch to another thread</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="op">(</span>hasFunds<span class="op">)</span> <span class="op">{</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>    balance <span class="op">-=</span> amount</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="ot">true</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="ot">false</span></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>If two threads are withdrawing $100 from Alice's account, which only
has $150 in it, it's possible that thread 1 checks the balance, sees
there's enough money, then gets paused by the scheduler. Thread 2 runs,
checks the balance, also sees there's enough money, then withdraws $100.
When thread 1 later resumes execution <em>after the check</em> it
withdraws its $100 too, Alice's account ends up with a negative balance
of -$50, which is invalid even though we had validation!</p>
<p>This sort of concurrency error is particularly insidious because the
original <code>withdraw</code> method is perfectly reasonable,
idiomatic, and correct in a single-threaded program; however when we
decide to add concurrency at a <strong>completely different
place</strong> in the system we've introduced a bug deep within existing
previously correct code. The idea that a perfectly normal evolution from
a single-threaded to a multi-threaded program can introduce
<strong>critical system-breaking bugs</strong> in completely unrelated
code without so much as a warning is quite frankly <em>completely
unacceptable</em>. As a craftsman I expect better from my tools.</p>
<p>Okay, but now that we've lost thousands if not millions of dollars,
how do we fix this?</p>
<p>Traditional knowledge points us towards <strong>Mutexes</strong>.</p>
<h3 id="mutexes">Mutexes</h3>
<p>Okay, we've encountered a problem with our shared mutable state, the
traditional approach to solving these problems is to enforce
<em>exclusive access</em> to the shared data in so-called "critical
sections". Mutexes are so-named because they provide
<strong>mut</strong>ual <strong>ex</strong>clusion, meaning only a
single thread may access a given virtual resource at a time.</p>
<p>Here's how we can edit our program to fix the data race problems
using a mutex:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode go"><code class="sourceCode go"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Account <span class="op">{</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>  mutex Mutex<span class="op">,</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>  balance <span class="dt">int</span><span class="op">,</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</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="kw">func</span> <span class="op">(</span>a <span class="op">*</span>Account<span class="op">)</span> deposit<span class="op">(</span>amount <span class="dt">int</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>  a<span class="op">.</span>mutex<span class="op">.</span>lock<span class="op">()</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>  <span class="cf">defer</span> a<span class="op">.</span>mutex<span class="op">.</span>unlock<span class="op">()</span></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a>  a<span class="op">.</span>balance <span class="op">+=</span> amount</span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</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="kw">func</span> <span class="op">(</span>a <span class="op">*</span>Account<span class="op">)</span> withdraw<span class="op">(</span>amount <span class="dt">int</span><span class="op">)</span> <span class="dt">bool</span> <span class="op">{</span></span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a>  a<span class="op">.</span>mutex<span class="op">.</span>lock<span class="op">()</span></span>
<span id="cb5-14"><a href="#cb5-14" aria-hidden="true" tabindex="-1"></a>  <span class="cf">defer</span> a<span class="op">.</span>mutex<span class="op">.</span>unlock<span class="op">()</span></span>
<span id="cb5-15"><a href="#cb5-15" aria-hidden="true" tabindex="-1"></a>  hasFunds <span class="op">:=</span> a<span class="op">.</span>balance <span class="op">&gt;=</span> amount </span>
<span id="cb5-16"><a href="#cb5-16" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="op">(</span>hasFunds<span class="op">)</span> <span class="op">{</span></span>
<span id="cb5-17"><a href="#cb5-17" aria-hidden="true" tabindex="-1"></a>    balance <span class="op">-=</span> amount</span>
<span id="cb5-18"><a href="#cb5-18" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="ot">true</span></span>
<span id="cb5-19"><a href="#cb5-19" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb5-20"><a href="#cb5-20" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="ot">false</span></span>
<span id="cb5-21"><a href="#cb5-21" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb5-22"><a href="#cb5-22" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Now every <code>Account</code> has a mutex on it, which acts as an
exclusive lock.</p>
<p>It's much like a bathroom key in a busy restaurant. When you want to
use the bathroom, you take the key, there's only one key available for
each bathroom, so while you've got hold of it nobody else can use that
bathroom. Now you're free to do your business, then you return the key
to the hook on the wall for the next person.</p>
<p>Unlike a bathroom key however, mutexes are only <em>conceptual</em>
locks, not <em>real</em> locks, and as such they operate on the honor
system.</p>
<p>If the programmer forgets to lock the mutex the system won't stop
them from accessing the data anyways, and even then there's no actual
link between the data being locked and the lock itself, we need to trust
the programmers to both <em>understand</em> and <em>respect</em> the
agreement. A risky prospect on both counts.</p>
<p>In this case, we've addressed the data-race within
<code>withdraw</code> and <code>deposit</code> by using mutexes, but
we've still got a problem within the <code>transfer</code> function.</p>
<p>What happens if a thread is pre-empted between the calls to
<code>withdraw</code> and <code>deposit</code> while running the
<code>transfer</code> function? It's possible that money will been
withdrawn from an account, but won't have yet been deposited in the
other. This is an inconsistent state of the system, the money has
temporarily disappeared, existing only in the operating memory of a
thread, but not visible in any externally observable state. This can
(and will) result in <em>very</em> strange behaviour.</p>
<p>As a concrete way to observe the strangeness let's write a
<code>report</code> function which prints out all account balances:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode go"><code class="sourceCode go"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">func</span> report<span class="op">()</span> <span class="op">{</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span> _<span class="op">,</span> account <span class="op">:=</span> <span class="kw">range</span> accounts <span class="op">{</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>        account<span class="op">.</span>mutex<span class="op">.</span>lock<span class="op">()</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>        fmt<span class="op">.</span>Println<span class="op">(</span>account<span class="op">.</span>balance<span class="op">)</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>        account<span class="op">.</span>mutex<span class="op">.</span>unlock<span class="op">()</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>If we run a <code>report</code> while transfers are ongoing we'll
likely see that the count of the total amount of money that exists
within the system is incorrect, and changes from report to report, which
should be impossible in a closed system like this! This inconsistency
occurs even if we obtain the locks for each individual account before
checking the balance.</p>
<p>In larger systems this sort of inconsistency problem can cause flaws
in even simple logic, since choices may be made against inconsistent
system states. The root of this issue is that the <code>transfer</code>
function requires holding multiple independent locks, but they're not
grouped in any way into an atomic operation.</p>
<h3 id="composing-critical-sections">Composing Critical Sections</h3>
<p>We need some way to make the entire transfer operation atomic, at
least from the perspective of other threads who are respecting our
mutexes.</p>
<p>Okay, well no problem, we can just lock both accounts, right?</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode go"><code class="sourceCode go"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="kw">func</span> transfer<span class="op">(</span>from <span class="op">*</span>Account<span class="op">,</span> to <span class="op">*</span>Account<span class="op">,</span> amount <span class="dt">int</span><span class="op">)</span> <span class="dt">bool</span> <span class="op">{</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>  from<span class="op">.</span>mutex<span class="op">.</span>lock<span class="op">()</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>  to<span class="op">.</span>mutex<span class="op">.</span>lock<span class="op">()</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>  <span class="cf">defer</span> from<span class="op">.</span>mutex<span class="op">.</span>unlock<span class="op">()</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>  <span class="cf">defer</span> to<span class="op">.</span>mutex<span class="op">.</span>unlock<span class="op">()</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="cf">if</span> <span class="op">(</span>from<span class="op">.</span>withdraw<span class="op">(</span>amount<span class="op">))</span> <span class="op">{</span></span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a>    to<span class="op">.</span>deposit<span class="op">(</span>amount<span class="op">)</span></span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="ot">true</span></span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="ot">false</span></span>
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb7-13"><a href="#cb7-13" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>I'm sure some readers have already seen a problem here, but have you
seen <em>two</em> problems here?</p>
<p>The first is obvious when you point it out, remember that
<code>withdraw</code> and <code>deposit</code> <em>also</em> lock the
mutex on the account, so we're trying to acquire the same lock twice in
the <em>same thread</em>.</p>
<p><code>transfer</code> won't even begin to run in this state, it will
block forever inside <code>withdraw</code> when it tries to lock the
<code>from.mutex</code> for the second time.</p>
<p>Some systems, like <em>re-entrant locks</em> and Java's
<code>synchronized</code> keyword do some additional book-keeping which
allow a single thread to lock the same mutex multiple times, so using a
re-entrant lock here would solve this particular problem. However other
systems, like golang, avoid providing re-entrant locks <a
href="https://groups.google.com/g/golang-nuts/c/XqW1qcuZgKg/m/Ui3nQkeLV80J">on
a matter of principle</a>.</p>
<p>So what can we do? I suppose we'll need to pull the locks <em>out
of</em> <code>withdraw</code> and <code>deposit</code> so we can lock
them in <code>transfer</code> instead.</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode go"><code class="sourceCode go"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">func</span> <span class="op">(</span>a <span class="op">*</span>Account<span class="op">)</span> deposit<span class="op">(</span>amount <span class="dt">int</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>  a<span class="op">.</span>balance <span class="op">+=</span> amount</span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a><span class="kw">func</span> <span class="op">(</span>a <span class="op">*</span>Account<span class="op">)</span> withdraw<span class="op">(</span>amount <span class="dt">int</span><span class="op">)</span> <span class="dt">bool</span> <span class="op">{</span></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a>  hasFunds <span class="op">:=</span> a<span class="op">.</span>balance <span class="op">&gt;=</span> amount </span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="op">(</span>hasFunds<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a>    balance <span class="op">-=</span> amount</span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="ot">true</span></span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="ot">false</span></span>
<span id="cb8-12"><a href="#cb8-12" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb8-13"><a href="#cb8-13" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb8-14"><a href="#cb8-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-15"><a href="#cb8-15" aria-hidden="true" tabindex="-1"></a><span class="kw">func</span> transfer<span class="op">(</span>from <span class="op">*</span>Account<span class="op">,</span> to <span class="op">*</span>Account<span class="op">,</span> amount <span class="dt">int</span><span class="op">)</span> <span class="dt">bool</span> <span class="op">{</span></span>
<span id="cb8-16"><a href="#cb8-16" aria-hidden="true" tabindex="-1"></a>  from<span class="op">.</span>mutex<span class="op">.</span>lock<span class="op">()</span></span>
<span id="cb8-17"><a href="#cb8-17" aria-hidden="true" tabindex="-1"></a>  to<span class="op">.</span>mutex<span class="op">.</span>lock<span class="op">()</span></span>
<span id="cb8-18"><a href="#cb8-18" aria-hidden="true" tabindex="-1"></a>  <span class="cf">defer</span> from<span class="op">.</span>mutex<span class="op">.</span>unlock<span class="op">()</span></span>
<span id="cb8-19"><a href="#cb8-19" aria-hidden="true" tabindex="-1"></a>  <span class="cf">defer</span> to<span class="op">.</span>mutex<span class="op">.</span>unlock<span class="op">()</span></span>
<span id="cb8-20"><a href="#cb8-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-21"><a href="#cb8-21" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="op">(</span>from<span class="op">.</span>withdraw<span class="op">(</span>amount<span class="op">))</span> <span class="op">{</span></span>
<span id="cb8-22"><a href="#cb8-22" aria-hidden="true" tabindex="-1"></a>    to<span class="op">.</span>deposit<span class="op">(</span>amount<span class="op">)</span></span>
<span id="cb8-23"><a href="#cb8-23" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="ot">true</span></span>
<span id="cb8-24"><a href="#cb8-24" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb8-25"><a href="#cb8-25" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="ot">false</span></span>
<span id="cb8-26"><a href="#cb8-26" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb8-27"><a href="#cb8-27" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Ugh, a correct <code>transfer</code> function should conceptually
just be the <em>composition</em> of our well encapsulated
<code>withdraw</code> and a <code>deposit</code> functions, but defining
it <em>correctly</em> has forced us to remove the locking from both
<code>withdraw</code> and <code>deposit</code>, making both of them
<em>less safe</em> to use. It has placed the burden of locking on the
caller (without <em>any</em> system-maintained guarantees), and even
worse, we now need to remember to go and <em>add</em> locking around
every existing <code>withdraw</code> and <code>deposit</code> call in
the entire codebase. Even if we try to encapsulate everything within the
module and only export "safe" operations we've caused duplication since
we now need synchronized and unsynchronized versions of our
<code>withdraw</code> and <code>deposit</code> operations. And we'd
still need to expose the mutexes if we want to allow callers to
synchronize operations with other non-<code>Account</code> data.</p>
<p>What I'm getting at is that mutexes don't <em>compose</em>! They
don't allow us to chain multiple critical sections into a single atomic
unit, they force us to break encapsulation and thrust the implementation
details of mutexes and locking onto the caller who shouldn't need to
know the details about which invariants must be maintained deep within
the implementation. Adding or removing access to synchronized variables
within an operation will also necessitate adding or removing locking to
<em>every call site</em>, and those call sites may be in a completely
different application or library. This is an absolute mess.</p>
<p>All that sounds pretty bad, but would you believe those aren't the
only problems here? It's not just composition that's broken here though,
in fixing <code>transfer</code> to make it an atomic operation we've
managed to introduce a new, extra-well-hidden deadlock bug.</p>
<h3 id="deadlockslivelocks">Deadlocks/Livelocks</h3>
<p>Recall that in our main loop we're accepting arbitrary transfer
requests and spawning them off in goroutines. What happens in our system
if we have two transfer requests, Alice is trying to Venmo Bob $25 for
the beanbag chair she just bought off him, meanwhile Bob remembers he
needs to Venmo Alice the $130 he owes her for Weird Al concert
tickets.</p>
<p>If by sheer coincidence they both submit their requests at the same
time, we have two <code>transfer</code> calls:</p>
<ul>
<li><code>transfer(aliceAccount, bobAccount, 25)</code></li>
<li><code>transfer(bobAccount, aliceAccount, 130)</code></li>
</ul>
<p>Each of these calls will attempt to lock their <code>from</code>
account and <em>then</em> their <code>to</code> account. If Alice and
Bob get very unlucky, the system will start the first
<code>transfer</code> and lock Alice's account, then get paused by the
scheduler. When the second <code>transfer</code> call comes in, it first
locks Bob's account, then tries to lock Alice's account, but can't
because it's already locked by the first <code>transfer</code> call.</p>
<p>This is a classic deadlock situation. Both threads will be stuck
forever, and worse, both Alice and Bob's accounts will be locked until
the system restarts.</p>
<p>This is a pretty disastrous consequence for a problem which is
relatively hard to spot even in this trivially simple example. In a real
system with dozens or hundreds of methods being parallelized in a
combinatorial explosion of ways it's <strong>very difficult</strong> to
reason about this, and can be a lot of work to ensure locks are obtained
in a safe and consistent order.</p>
<p>Golang gets some credit here in that it does provide <em>some</em>
runtime tools for detecting both dead-locks and data-races, which is
great, but these detections only help if your tests encounter the
problem; they don't prevent the problem from happening in the first
place. Most languages aren't so helpful, these issues can be very
difficult to track down in production systems.</p>
<h3 id="assessing-the-damage">Assessing the damage</h3>
<p>What a dumpster fire we've gotten ourselves into...</p>
<p>While it may be no accident that the example I've engineered happens
to hit all of the worst bugs at once, in my experience, given enough
time and complexity these sorts of problems will crop up any system
eventually. Solving them with mutexes is especially dangerous because it
will <em>seem</em> to be an effective solution at first. Mutexes work
fine in small localized use-cases, thus tempting us to use them, but as
the system grows organically we stretch them too far and they fail
catastrophically as the complexity of the system scales up, causing all
sorts of hacky workarounds. I'm of the opinion that crossing your
fingers and hoping for the best is not an adequate software-engineering
strategy.</p>
<p>So, we've seen that architecting a correct software system using
mutexes is <em>possible</em>, but <strong>very difficult</strong>. Every
attempt we've made to fix one problem has spawned a couple more.</p>
<p>Here's a summary of the problems we've encountered:</p>
<ul>
<li>Data races causing non-determinism and logic bugs</li>
<li>Lack of atomicity causing inconsistent system states</li>
<li>Lack of composition causing
<ul>
<li>Broken encapsulation</li>
<li>Code duplication</li>
<li>Cognitive overload on callers</li>
</ul></li>
<li>Deadlocks/livelocks causing system-wide freezes</li>
<li>New features may require changes to every call-site</li>
</ul>
<p>In my opinion, we've tried to stretch mutexes beyond their limits,
both in this blog post and in the industry as a whole. Mutexes work
great in small, well-defined scopes where you're locking a
<em>single</em> resource which is only ever accessed in a handful of
functions in the same module, but they're too hard to wrangle in larger
complex systems with many interacting components maintained by dozens or
hundreds of developers. We need to evolve our tools and come up with
more reliable solutions.</p>
<h2 id="cleaning-up-the-chaos">Cleaning up the Chaos</h2>
<p>Thankfully, despite an over-reliance on mutexes, we as an industry
have still learned a thing or two since the 1960s. Particularly I think
that enforcing <em>immutability by default</em> goes a <em>long</em> way
here. For many programmers this is a paradigm shift from what they're
used to, which usually causes some uneasiness. Seatbelts, too, were
often scorned in their early years for their restrictive nature, but
over time it has become the prevailing opinion that the mild
inconvenience is more than worth the provided safety.</p>
<p>More and more languages (Haskell, Clojure, Erlang, Gleam, Elixir,
Roc, Elm, Unison, ...) are realizing this and are adopting this as core
design principle. Obviously not every programmer can switch to an
immutable-first language over night, but I think it would behoove most
programmers to strongly consider an immutable language if parallelism is
a large part of their project's workload.</p>
<p>Using immutable data structures immediately prevents data-races,
full-stop. So stick with immutable data everywhere you can, but in a
world of immutability we'll still need some way to synchronize parallel
processes and for that most of these languages do still provide some
form of mutable reference. It's never the default, and there's typically
some additional ceremony or tracking in the type system which acts as an
immediate sign-post that shared-mutable state is involved; here there be
dragons.</p>
<p>Even better than mutable references, decades of research and
industrial research have provided us with a swath battle-tested
high-level concurrency patterns which are built on top of lower-level
synchronization primitives like mutexes or mutable references, typically
exposing much safer interfaces to the programmer.</p>
<h3 id="concurrency-patterns">Concurrency Patterns</h3>
<p>Actor systems and Communicating Sequential Processes (CSP) are some
of the most common concurrency orchestration patterns. Each of these
operate by defining independent sub-programs which have their own
isolated states which only they can access. Each actor or process
receives messages from other units and can respond to them in turn. Each
of these deserves a talk or blog post of their own so I won't dive too
deeply into them here, but please look into them deeper if this is the
first you're hearing of them.</p>
<p>These approaches work great for <em>task parallelism</em>, where
there are independent processes to run, and where your parallelism needs
are bounded by the number of tasks you'd like to run. As an example, I
used an actor-based system when building Unison's code-syncing protocol.
There was one actor responsible for loading and sending requests for
code, one for receiving and unpacking code, and one for validating the
hashes of received code. This system required <strong>exactly</strong> 3
workers to co-operate regardless of <em>how many things</em> I was
syncing. Actor and CSP systems are great choices when the number of
workers/tasks we need to co-ordinate is statically known, i.e. a fixed
number of workers, or a pre-defined map-reduce pipeline. These patterns
can scale well to many cores since each actor or process can run
independently on its own core without worrying about synchronizing
access to shared mutable state, and as a result can often scale to
multiple machines as well.</p>
<p>However, there are also problems where the parallelism is
<em>dynamic</em> or ad-hoc, meaning there could be any number of
runtime-spawned concurrent actors that must co-ordinate well with each
other. In those cases these systems tend to break down. I've seen
consultants describe complex patterns for dynamically introducing
actors, one-actor-per-resource systems, tree-based actor resource
hierarchies and other complex ideas but in my opinion these systems
quickly outgrow the ability of any one developer to understand and
debug.</p>
<p>So how then do we model a system like the bank account example? Even
if we were to limit the system to a fixed number of transfer-workers
they'd still be concurrently accessing the same data (the bank accounts)
and need some way to express <strong>atomic transfers</strong> between
them, which isn't easily accomplished with actors or CSP.</p>
<p>What's a guy to do?</p>
<h2 id="a-new-old-synchronization-primitive">A new (old) synchronization
primitive</h2>
<p>In the vast majority of cases using a streaming system, actors or CSP
is going to be most effective and understandable. However in cases where
we must synchronize individual chunks of data across many workers, and
require operations to affect multiple chunks of data atomically, there's
only one name in town that gets the job done right.</p>
<p>Software Transactional Memory (STM) is a criminally under-utilized
synchronization tool which solves all of the problems we've encountered
so far while providing more safety, better compositionality, and cleaner
abstractions. Did I mention they prevent most deadlocks and livelocks
too?</p>
<p>To understand how STM works, think of database transactions; in a
database transaction isolation provides you with a consistent view of
data in spite of concurrent access. Each transaction sees an isolated
view of the data, untampered by other reads and writes. After making all
your reads and writes you <em>commit</em> the transaction. Upon commit,
the transaction either succeeds completely and applies <em>ALL</em> the
changes you made to the data snapshot, or it may result in a
<em>conflict</em>. In cases of a conflict the transaction <em>fails</em>
and <em>rolls back</em> all your changes as though nothing happened,
then it can retry on the new data snapshot.</p>
<p>STM works in much the same way, but instead of the rows and columns
in a database, transactions operate on normal in-memory data structures
and variables.</p>
<p>To explore this technique let's convert our bank account example into
Haskell so we can use STM instead of mutexes.</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">data</span> <span class="dt">Account</span> <span class="ot">=</span> <span class="dt">Account</span> {</span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- Data that needs synchronization is stored in a </span></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- Transactional Variable, a.k.a. TVar</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a><span class="ot">  balanceVar ::</span> <span class="dt">TVar</span> <span class="dt">Int</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>}</span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a><span class="co">-- Deposit money into an account.</span></span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a><span class="ot">deposit ::</span> <span class="dt">Account</span> <span class="ot">-&gt;</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">STM</span> ()</span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a>deposit <span class="dt">Account</span>{balanceVar} amount <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb9-10"><a href="#cb9-10" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- We interact with the data using TVar operations which</span></span>
<span id="cb9-11"><a href="#cb9-11" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- build up an STM transaction.</span></span>
<span id="cb9-12"><a href="#cb9-12" aria-hidden="true" tabindex="-1"></a>  modifyTVar balanceVar (\existing <span class="ot">-&gt;</span> existing <span class="op">+</span> amount)</span>
<span id="cb9-13"><a href="#cb9-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-14"><a href="#cb9-14" aria-hidden="true" tabindex="-1"></a><span class="co">-- Withdraw money from an account</span></span>
<span id="cb9-15"><a href="#cb9-15" aria-hidden="true" tabindex="-1"></a><span class="co">-- Everything within the `do` block</span></span>
<span id="cb9-16"><a href="#cb9-16" aria-hidden="true" tabindex="-1"></a><span class="co">-- is part of the same transaction.</span></span>
<span id="cb9-17"><a href="#cb9-17" aria-hidden="true" tabindex="-1"></a><span class="co">-- This guarantees a consistent view of the TVars we </span></span>
<span id="cb9-18"><a href="#cb9-18" aria-hidden="true" tabindex="-1"></a><span class="co">-- access and mutate.</span></span>
<span id="cb9-19"><a href="#cb9-19" aria-hidden="true" tabindex="-1"></a><span class="ot">withdraw ::</span> <span class="dt">Account</span> <span class="ot">-&gt;</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">STM</span> <span class="dt">Bool</span></span>
<span id="cb9-20"><a href="#cb9-20" aria-hidden="true" tabindex="-1"></a>withdraw <span class="dt">Account</span>{balanceVar} amount <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb9-21"><a href="#cb9-21" aria-hidden="true" tabindex="-1"></a>  existing <span class="ot">&lt;-</span> readTVar balanceVar</span>
<span id="cb9-22"><a href="#cb9-22" aria-hidden="true" tabindex="-1"></a>  <span class="kw">if</span> existing <span class="op">&lt;=</span> amount</span>
<span id="cb9-23"><a href="#cb9-23" aria-hidden="true" tabindex="-1"></a>    <span class="kw">then</span> (<span class="fu">return</span> <span class="dt">False</span>)</span>
<span id="cb9-24"><a href="#cb9-24" aria-hidden="true" tabindex="-1"></a>    <span class="kw">else</span> <span class="kw">do</span></span>
<span id="cb9-25"><a href="#cb9-25" aria-hidden="true" tabindex="-1"></a>      writeTVar balanceVar (existing <span class="op">-</span> amount)</span>
<span id="cb9-26"><a href="#cb9-26" aria-hidden="true" tabindex="-1"></a>      <span class="fu">return</span> <span class="dt">True</span></span>
<span id="cb9-27"><a href="#cb9-27" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-28"><a href="#cb9-28" aria-hidden="true" tabindex="-1"></a><span class="co">-- Transfer money between two accounts atomically</span></span>
<span id="cb9-29"><a href="#cb9-29" aria-hidden="true" tabindex="-1"></a><span class="ot">transfer ::</span> <span class="dt">Account</span> <span class="ot">-&gt;</span> <span class="dt">Account</span> <span class="ot">-&gt;</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">STM</span> <span class="dt">Bool</span></span>
<span id="cb9-30"><a href="#cb9-30" aria-hidden="true" tabindex="-1"></a>transfer from to amount <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb9-31"><a href="#cb9-31" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- These two individual transactions seamlessly</span></span>
<span id="cb9-32"><a href="#cb9-32" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- compose into one larger transaction, guaranteeing</span></span>
<span id="cb9-33"><a href="#cb9-33" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- consistency without any need to change the individual</span></span>
<span id="cb9-34"><a href="#cb9-34" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- operations.</span></span>
<span id="cb9-35"><a href="#cb9-35" aria-hidden="true" tabindex="-1"></a>  withdrawalSuccessful <span class="ot">&lt;-</span> withdraw from amount</span>
<span id="cb9-36"><a href="#cb9-36" aria-hidden="true" tabindex="-1"></a>  <span class="kw">if</span> successful</span>
<span id="cb9-37"><a href="#cb9-37" aria-hidden="true" tabindex="-1"></a>    <span class="kw">then</span> <span class="kw">do</span></span>
<span id="cb9-38"><a href="#cb9-38" aria-hidden="true" tabindex="-1"></a>      deposit to amount</span>
<span id="cb9-39"><a href="#cb9-39" aria-hidden="true" tabindex="-1"></a>      <span class="fu">return</span> <span class="dt">True</span></span>
<span id="cb9-40"><a href="#cb9-40" aria-hidden="true" tabindex="-1"></a>    <span class="kw">else</span> </span>
<span id="cb9-41"><a href="#cb9-41" aria-hidden="true" tabindex="-1"></a>      <span class="fu">return</span> <span class="dt">False</span></span></code></pre></div>
<p>Let's do another lap over all the problems we had with mutexes to see
how this new approach fares.</p>
<h3 id="data-races-1">Data Races</h3>
<p>Data races are a problem which I believe are best solved at the
language level itself. As mentioned earlier, using immutable data by
default simply prevents data races from existing in the first place.
Since data in Haskell is all immutable by default, pre-emption can occur
at any point in normal code and <strong>we know</strong> we won't get a
data race.</p>
<p>When we need <em>mutable data</em>, it's made explicit by wrapping
that data in <code>TVar</code>s. The language further protects us by
only allowing us to mutate these variables within transactions, which we
compose into operations which are guaranteed a consistent uncorrupted
view of the data.</p>
<p>Let's convert <code>withdraw</code> to use STM and our
<code>balaceVar</code> TVar.</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="co">-- Withdraw money from an account</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="ot">withdraw ::</span> <span class="dt">Account</span> <span class="ot">-&gt;</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">STM</span> <span class="dt">Bool</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>withdraw <span class="dt">Account</span>{balanceVar} amount <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>  existing <span class="ot">&lt;-</span> readTVar balanceVar</span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">if</span> existing <span class="op">&lt;=</span> amount</span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">then</span> (<span class="fu">return</span> <span class="dt">False</span>)</span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">else</span> <span class="kw">do</span></span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a>      <span class="co">-- No data races here!</span></span>
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a>      writeTVar balanceVar (existing <span class="op">-</span> amount)</span>
<span id="cb10-10"><a href="#cb10-10" aria-hidden="true" tabindex="-1"></a>      <span class="fu">return</span> <span class="dt">True</span></span></code></pre></div>
<p>We can see that the code we wrote looks very much like the original
unsynchronized golang version, but while using STM it's perfectly safe
from data races! Even if it the thread is pre-empted in the middle of
the operation, the transaction-state is invisible to other threads until
the transaction commits.</p>
<h3 id="deadlocklivelock">Deadlock/Livelock</h3>
<p>STM is an <strong>optimistic concurrency system</strong>. This means
that threads <strong>never block waiting for locks</strong>. Instead,
each concurrent operation proceeds, possibly in parallel, on their own
independent transaction log. Each transaction tracks which pieces of
data it has accessed or mutated and if at commit time it is detected
that some other transaction has been committed and altered data which
this transaction also accessed, then the latter transaction is rolled
back and is simply retried.</p>
<p>This arrangement is fundamentally different from a lock-based
exclusive access system. In STM, you don't deal with locks at all, you
simply read and write data within a transaction as necessary. Our
<code>transfer</code> function reads and writes two different
<code>TVar</code>s, but since we're not obtaining exclusive
<em>locks</em> to these vars, we don't need to worry about deadlock
<em>at all</em>. If two threads happen to be running a
<code>transfer</code> on the same <code>TVars</code> at the same time,
whichever commits first will atomically apply its updates to both
accounts and the other transaction will detect this update at
commit-time and will retry against the new balances.</p>
<p>This <em>can</em> cause some contention and possibly even starvation
of any single transaction if many threads are trying to update the same
data at the same time, but since a conflict can only occur if some other
transaction has been committed, it does still have the guarantee that
the system will make progress on at least some work. In Haskell, STM
transactions must be <em>pure</em> code, and can't do IO, so most
transactions are relatively short-running and should proceed eventually.
This seems like a downside, but in practice it only surfaces as a rare
annoyance and can usually be worked around without too much trouble.</p>
<h3 id="composition">Composition</h3>
<p>It may not be immediately obvious from the types if you're not used
to Haskell code, but all three of <code>withdraw</code>,
<code>deposit</code>, and <code>transfer</code> are all functions which
return their results wrapped in the <code>STM</code> monad, which is
essentially a sequence of operations which we can ask to execute in a
transaction using the <code>atomically</code> function.</p>
<p>We can call out to any arbitrary methods which return something
wrapped in <code>STM</code> and it will automatically be joined in as
part of the current transaction.</p>
<p>Unlike our mutex setup, callers don't need to manually handle locks
when calling<code>withdraw</code> and <code>deposit</code>, nor do we
need to expose special <strong>synchronized</strong> versions of these
methods for things to be safe. We can define them exactly once and use
that one definition either on its own or within a more complex operation
like <code>transfer</code> without any additional work. The abstraction
is leak-proof, the caller doesn't need to know which synchronized data
is accessed or lock or unlock any mutexes. It simply runs the
transaction and the STM system happily handles the rest for you.</p>
<p>Here's what it looks like to actually run our STM transactions, which
we do using the <code>atomically</code> function:</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">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>  forever <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>    req <span class="ot">&lt;-</span> acceptTransferRequest</span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- Run each transfer on its own green-thread, in an atomic transaction.</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>    forkIO (atomically (transfer req<span class="op">.</span>from req<span class="op">.</span>to req<span class="op">.</span>amount)</span></code></pre></div>
<p>If we'd like to compile a report of all account balances as we did
previously, we can do that too. This time however we won't get a
potentially inconsistent snapshot of the system by accident, instead the
type-system forces us to make an explicit choice of which behaviour we'd
like.</p>
<p>We can either:</p>
<ul>
<li>Access and print each account balance individually as <em>separate
transaction</em> which means accounts may be edited in-between
transactions, leading to an inconsistent report like we saw
earlier.</li>
<li>Or, we can wrap the entire report into <strong>a single
transaction</strong>, reading all account balances in a single
transaction. This <em>will</em> provide a consistent snapshot of the
system, but due to the optimistic transaction system, the entire
transaction will be retried if any individual <em>transfers</em> commit
and edit accounts while we're collecting the report. It's possible that
if transfers are happening <strong>very</strong> frequently, the report
may be retried many times before it can complete.</li>
</ul>
<p>This is a legitimate tradeoff that the developer of the system should
be forced to consider.</p>
<p>Here's what those two different implementations look like:</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="co">-- Inconsistent report, may see money disappear/appear</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a><span class="ot">reportInconsistent ::</span> [<span class="dt">Account</span>] <span class="ot">-&gt;</span> <span class="dt">IO</span> ()</span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>reportInconsistent accounts <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>  for_ accounts <span class="op">$</span> \<span class="dt">Account</span>{balanceVar} <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a>    balance <span class="ot">&lt;-</span> atomically (readTVar balanceVar)</span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a>    <span class="fu">print</span> balance</span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a><span class="co">-- Consistent report, may be retried indefinitely </span></span>
<span id="cb12-9"><a href="#cb12-9" aria-hidden="true" tabindex="-1"></a><span class="co">-- if transfers are happening too frequently</span></span>
<span id="cb12-10"><a href="#cb12-10" aria-hidden="true" tabindex="-1"></a><span class="ot">reportConsistent ::</span> [<span class="dt">Account</span>] <span class="ot">-&gt;</span> <span class="dt">IO</span> ()</span>
<span id="cb12-11"><a href="#cb12-11" aria-hidden="true" tabindex="-1"></a>reportConsistent accounts <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb12-12"><a href="#cb12-12" aria-hidden="true" tabindex="-1"></a>  balances <span class="ot">&lt;-</span> atomically <span class="kw">do</span> </span>
<span id="cb12-13"><a href="#cb12-13" aria-hidden="true" tabindex="-1"></a>    for accounts <span class="op">$</span> \<span class="dt">Account</span>{balanceVar} <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb12-14"><a href="#cb12-14" aria-hidden="true" tabindex="-1"></a>      readTVar balanceVar</span>
<span id="cb12-15"><a href="#cb12-15" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- Now that we&#39;ve got a snapshot we can print it out</span></span>
<span id="cb12-16"><a href="#cb12-16" aria-hidden="true" tabindex="-1"></a>  for_ balances <span class="fu">print</span></span></code></pre></div>
<h2 id="smart-retries">Smart Retries</h2>
<p>One last benefit of STM which we haven't yet discussed is that it
supports <em>intelligent transaction retries</em> based on conditions of
the synchronized data itself. For instance, if we have a task to
withdraw $100 from Alice's account but it only has $50 in it, the
mutex-based system has no choice to but fail the withdrawal entirely and
return the failure up the stack. We can wrap that call with code to try
again later, but how will we know when it's reasonable to try again?
This would once again require the caller to understand the
<em>implementation details</em>, and which locks the method is
accessing.</p>
<p>STM, instead, supports failure and retrying as a first-class concept.
At any point in an STM transaction you can simply call
<code>retry</code>, this will record every <code>TVar</code> that the
transaction has accessed up until that point, then will abort the
current transaction and will sleep until any of those <code>TVar</code>s
has been modified by some other successful transaction. This avoids
busy-waiting, and allows writing some very simple and elegant code.</p>
<p>For example, here's a new version of our <code>withdraw</code>
function which instead of returning a failure will simply block the
current thread until sufficient funds are available, retrying only when
the balance of that account is changed by some other transaction's
success.</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="co">-- Withdraw money from an account, blocking until sufficient funds are available</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="ot">withdraw ::</span> <span class="dt">Account</span> <span class="ot">-&gt;</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">STM</span> ()</span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a>withdraw <span class="dt">Account</span>{balanceVar} amount <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>  existing <span class="ot">&lt;-</span> readTVar balanceVar</span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">if</span> existing <span class="op">&lt;=</span> amount</span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">then</span> retry</span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">else</span> <span class="kw">do</span></span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a>      writeTVar balanceVar (existing <span class="op">-</span> amount)</span></code></pre></div>
<p>You typically wouldn't use this to wait for an event which may take
days or weeks to occur like in this example; but it's a very elegant and
efficient solution for waiting on a channel, waiting for a future to
produce a result, or waiting on any other short-term condition to be
met.</p>
<p>Here's an example utility for zipping together two STM queues. The
transaction will only succeed and produce a result when a value is
available on both queues, and if that's not the case, it will only
bother retrying when one of the queues is modified since
<code>readTQueue</code> calls <code>retry</code> internally if the queue
is empty.</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">zipQueues ::</span> <span class="dt">TQueue</span> a <span class="ot">-&gt;</span> <span class="dt">TQueue</span> b <span class="ot">-&gt;</span> <span class="dt">STM</span> (a, b)</span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a>zipQueues q1 q2 <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a>  val1 <span class="ot">&lt;-</span> readTQueue q1</span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a>  val2 <span class="ot">&lt;-</span> readTQueue q2</span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a>  <span class="fu">return</span> (val1, val2)</span></code></pre></div>
<p>Nifty!</p>
<h1 id="conclusion">Conclusion</h1>
<p>We've covered a <em>lot</em> in this post, if there's only one thing
you can take away from it, I hope that you've taken the time to consider
whether mutexes with shared mutable state are providing you with utility
which outweighs their inherent costs and complexities. Unless you need
peak performance, you may want to think twice about using such dangerous
tools. Instead, consider using a concurrency pattern like actors, CSP,
streaming, or map-reduce if it matches your use-case.</p>
<p>If you need something which provides greater flexibility or
lower-level control, Software Transactional Memory (STM) is a fantastic
choice if it's available in your language of choice, though note that
not all languages support it, or if they do, may not be able to provide
sufficient safety guarantees due to mutable variables and data
structures.</p>
<p>If you're starting a new project for which concurrency or parallelism
is a first-class concern, consider trying out a language that supports
STM properly, I can recommend Unison or Haskell as great starting
points.</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Exploring Arrows for sequencing effects</title>
      <link href="https://chrispenner.ca/posts/arrow-effects"/>
      <id>https://chrispenner.ca/posts/arrow-effects</id>
      <updated>2025-10-16T00:00:00Z</updated>
      <summary>Monads are &lt;em&gt;one&lt;/em&gt; way to sequence effects, but they&#39;re not the
only way!</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/arrow.jpg" alt="Exploring Arrows for sequencing effects">
              <p><a href="https://chrispenner.ca/posts/expressiveness-spectrum">Last
time</a>, we explored common methods of sequencing effects into little
programs. If you haven't read it yet, I'd recommend starting with that,
but you can probably manage without it if you insist.</p>
<p>We examined Applicatives, Monads, and Selective Applicatives, and
each of these systems had its own trade-offs. We dug into how all
approaches exist on the spectrum between being
<strong>expressive</strong> or <strong>analyzable</strong> and at the
end of the post we were unfortunately left wanting something better.
Monads reign supreme when it comes to expressiveness as they can express
any possible programs we may want to write, but they offer essentially
no ability to analyze program they represent without executing it.</p>
<p>On the other hand, Applicatives and Selective Applicatives offered
reasonable program analysis, but are unable to express complex programs.
They can't even encode programs in which downstream effects materially
depend on the results of upstream effects.</p>
<p>These approaches are all based on the same Functor-Applicative-Monad
hierarchy, in this post we'll set that aside and rebuild on an
altogether different foundation to see if we can do even better.</p>
<h2 id="setting-the-goal-posts">Setting the goal posts</h2>
<p>Before putting in the work let's think critically about the what we
felt was missing from the Monad hierarchy and what we wish to gain from
a new system.</p>
<p>Here's my wish-list:</p>
<ul>
<li>I want to be able to list out every effect that program might
perform without executing anything.</li>
<li>I want to understand the <em>dependencies</em> between the effects
including the flow of data between them.</li>
<li>I want to be able to express programs in which downstream effects
can fully utilize the results of upstream effects.</li>
</ul>
<p>Looking at these requirements, the biggest problem with the Monadic
effects system is that it's far too rough-grained in how it handles the
results of previous effects. We can see this by reviewing the signature
of bind:</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">(&gt;&gt;=) ::</span> <span class="dt">Monad</span> m <span class="ot">=&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>We can see that the result from the previous effect is passed to an
arbitrary Haskell function whose job is to return the <em>entire</em>
continuation of the program! This permits that function to swap out the
<em>entire</em> rest of the program on any particular run, which I'd
argue is way more power than the vast majority of reasonable programs
require. This is quite frankly a dangerous amount of expressive power,
what sort of programs are you writing where you can't even statically
identify the possible code paths that <em>might</em> be taken? Even more
complex flows like branching, looping and recursion can be expressed in
a more structured way without resorting to this sledgehammer level of
dynamism.</p>
<p>This tells us we have some room to constrain our programs a bit, and
if we're economical about <em>how</em> we do it we can trade that power
for the benefits we desire.</p>
<p>We still need to utilize these past results, but we want to avoid
opening Pandora's box. That is, we must be careful not to allow the
creation of <em>new</em> effects by running arbitrary Haskell functions
at execution time. So, in order to use results without a
continuation-building function like Monads use, we must meaningfully
include the inputs and outputs for our effects in the <em>structure of
our effect system itself</em>. We also know that we need to be able to
chain these effects together, so we'll need some way to compose
them.</p>
<p>If it's not obvious already, this is a great fit for the Category
typeclass:</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">class</span> <span class="dt">Category</span> k <span class="kw">where</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="ot">  id ::</span> k a a</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="ot">  (.) ::</span> k b c <span class="ot">-&gt;</span> k a b <span class="ot">-&gt;</span> k a c</span></code></pre></div>
<p>This already gives us a lot of what we want. Unlike Monads which bake
outputs into the continuation of the program using function closures,
the Category structure routes inputs and outputs explicitly as part of
its structure. Unsurprisingly, it's quite a natural fit; after all, it's
called Category Theory, not Monad Theory...</p>
<h2 id="rebuilding-on-categories">Rebuilding on Categories</h2>
<p>Now let's begin to re-implement the examples from the previous post
using this new Category-based effect system. In order to save some time,
we're actually going to jump up the hierarchy a bit all the way to
<code>Arrow</code>s.</p>
<p>The <code>Arrow</code> class, if you're not familiar with it, looks
like 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">Category</span> a <span class="ot">=&gt;</span> <span class="dt">Arrow</span> (<span class="ot">a ::</span> <span class="dt">Type</span> <span class="ot">-&gt;</span> <span class="dt">Type</span> <span class="ot">-&gt;</span> <span class="dt">Type</span>) <span class="kw">where</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="ot">  arr ::</span> (b <span class="ot">-&gt;</span> c) <span class="ot">-&gt;</span> a b c</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="ot">  (***) ::</span> a b c <span class="ot">-&gt;</span> a b&#39; c&#39; <span class="ot">-&gt;</span> a (b, b&#39;) (c, c&#39;)</span></code></pre></div>
<p>There are a few other methods we get for free, but this is a minimal
set of methods we need to define.</p>
<p>Notice that it has a <code>Category</code> superclass, so we'll use
identity and composition from there. We can leverage <code>arr</code> to
lift pure Haskell functions into our Category structure. I know we just
said we wanted to avoid arbitrary Haskell functions, but note that in
this case, just like Applicatives, the function is pure, we can't
determine any effects or structure of the effects within the function.
No problems here.</p>
<p>We'll re-visit <code>(***)</code> in just a minute.</p>
<p>To get started, how about we re-implement the program we wrote using
<code>Applicative</code> in the previous post?</p>
<p>I'll save you from clicking over, here's a refresher on what we did
before:</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">import</span> <span class="dt">Control.Applicative</span> (liftA3)</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Monad.Writer</span> (<span class="dt">Writer</span>, runWriter, tell)</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 class="kw">class</span> (<span class="dt">Applicative</span> m) <span class="ot">=&gt;</span> <span class="dt">ReadWrite</span> m <span class="kw">where</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a><span class="ot">  readLine ::</span> m <span class="dt">String</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a><span class="ot">  writeLine ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> m ()</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Command</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>  <span class="ot">=</span> <span class="dt">ReadLine</span></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">WriteLine</span> <span class="dt">String</span></span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Show</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">-- | We can implement an instance which runs a dummy interpreter that simply records the commands</span></span>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a><span class="co">-- the program wants to run, without actually executing anything for real.</span></span>
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">ReadWrite</span> (<span class="dt">Writer</span> [<span class="dt">Command</span>]) <span class="kw">where</span></span>
<span id="cb4-16"><a href="#cb4-16" aria-hidden="true" tabindex="-1"></a>  readLine <span class="ot">=</span> tell [<span class="dt">ReadLine</span>] <span class="op">*&gt;</span> <span class="fu">pure</span> <span class="st">&quot;Simulated User Input&quot;</span></span>
<span id="cb4-17"><a href="#cb4-17" aria-hidden="true" tabindex="-1"></a>  writeLine msg <span class="ot">=</span> tell [<span class="dt">WriteLine</span> msg]</span>
<span id="cb4-18"><a href="#cb4-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-19"><a href="#cb4-19" aria-hidden="true" tabindex="-1"></a><span class="co">-- | A helper to run our program and get the list of commands it would execute</span></span>
<span id="cb4-20"><a href="#cb4-20" aria-hidden="true" tabindex="-1"></a><span class="ot">recordCommands ::</span> <span class="dt">Writer</span> [<span class="dt">Command</span>] <span class="dt">String</span> <span class="ot">-&gt;</span> [<span class="dt">Command</span>]</span>
<span id="cb4-21"><a href="#cb4-21" aria-hidden="true" tabindex="-1"></a>recordCommands w <span class="ot">=</span> <span class="fu">snd</span> (runWriter w)</span>
<span id="cb4-22"><a href="#cb4-22" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-23"><a href="#cb4-23" aria-hidden="true" tabindex="-1"></a><span class="co">-- | A simple program that greets the user.</span></span>
<span id="cb4-24"><a href="#cb4-24" aria-hidden="true" tabindex="-1"></a><span class="ot">myProgram ::</span> (<span class="dt">ReadWrite</span> m) <span class="ot">=&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> m <span class="dt">String</span></span>
<span id="cb4-25"><a href="#cb4-25" aria-hidden="true" tabindex="-1"></a>myProgram greeting <span class="ot">=</span></span>
<span id="cb4-26"><a href="#cb4-26" aria-hidden="true" tabindex="-1"></a>  liftA3</span>
<span id="cb4-27"><a href="#cb4-27" aria-hidden="true" tabindex="-1"></a>    (\_ name _ <span class="ot">-&gt;</span> name)</span>
<span id="cb4-28"><a href="#cb4-28" aria-hidden="true" tabindex="-1"></a>    (writeLine (greeting <span class="op">&lt;&gt;</span> <span class="st">&quot;, what is your name?&quot;</span>))</span>
<span id="cb4-29"><a href="#cb4-29" aria-hidden="true" tabindex="-1"></a>    readLine</span>
<span id="cb4-30"><a href="#cb4-30" aria-hidden="true" tabindex="-1"></a>    (writeLine <span class="st">&quot;Welcome!&quot;</span>)</span>
<span id="cb4-31"><a href="#cb4-31" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-32"><a href="#cb4-32" aria-hidden="true" tabindex="-1"></a><span class="co">-- We can now run our program in the Writer applicative to see what it would do!</span></span>
<span id="cb4-33"><a href="#cb4-33" aria-hidden="true" tabindex="-1"></a><span class="ot">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb4-34"><a href="#cb4-34" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb4-35"><a href="#cb4-35" aria-hidden="true" tabindex="-1"></a>  <span class="kw">let</span> commands <span class="ot">=</span> recordCommands (myProgram <span class="st">&quot;Hello&quot;</span>)</span>
<span id="cb4-36"><a href="#cb4-36" aria-hidden="true" tabindex="-1"></a>  <span class="fu">print</span> commands</span>
<span id="cb4-37"><a href="#cb4-37" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-38"><a href="#cb4-38" aria-hidden="true" tabindex="-1"></a><span class="co">-- [WriteLine &quot;Hello, what is your name?&quot;, ReadLine, WriteLine &quot;Welcome!&quot;]</span></span></code></pre></div>
<p>The key aspects of this <code>Applicative</code> version were that we
could analyze any program which required only an
<code>Applicative</code> constraint to get the full list of sequential
effects that the program would perform.</p>
<p>Here's the same program, but this time we'll encode the effects using
<code>Arrow</code> constraints instead.</p>
<p>But first, a disclaimer: writing Arrow-based programs looks ugly, but
don't worry, bear with me for a bit and we'll address that later.</p>
<p>Just like the Applicative version, we'll define a typeclass as the
interface to our set of <code>ReadWrite</code> effects, but this time
will assume an <code>Arrow</code> constraint:</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="kw">import</span> <span class="dt">Control.Arrow</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Category</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Prelude</span> <span class="kw">hiding</span> (id)</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> (<span class="dt">Arrow</span> k) <span class="ot">=&gt;</span> <span class="dt">ReadWrite</span> k <span class="kw">where</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- Readline has no interesting input, so we use () as input type.</span></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a><span class="ot">  readLine ::</span> k () <span class="dt">String</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="co">-- We track the inputs for the writeLine directly in the Category structure.</span></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a><span class="ot">  writeLine ::</span> k <span class="dt">String</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="co">-- Helper for embedding a static Haskell value directly into an Arrow</span></span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a><span class="ot">constA ::</span> (<span class="dt">Arrow</span> k) <span class="ot">=&gt;</span> b <span class="ot">-&gt;</span> k a b</span>
<span id="cb5-14"><a href="#cb5-14" aria-hidden="true" tabindex="-1"></a>constA b <span class="ot">=</span> arr (\_ <span class="ot">-&gt;</span> b)</span>
<span id="cb5-15"><a href="#cb5-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-16"><a href="#cb5-16" aria-hidden="true" tabindex="-1"></a><span class="co">-- | A simple program which uses a statically provided message to greet the user.</span></span>
<span id="cb5-17"><a href="#cb5-17" aria-hidden="true" tabindex="-1"></a><span class="ot">myProgram ::</span> (<span class="dt">ReadWrite</span> k) <span class="ot">=&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> k () ()</span>
<span id="cb5-18"><a href="#cb5-18" aria-hidden="true" tabindex="-1"></a>myProgram greeting <span class="ot">=</span></span>
<span id="cb5-19"><a href="#cb5-19" aria-hidden="true" tabindex="-1"></a>  constA (greeting <span class="op">&lt;&gt;</span> <span class="st">&quot;, what is your name?&quot;</span>)</span>
<span id="cb5-20"><a href="#cb5-20" aria-hidden="true" tabindex="-1"></a>    <span class="op">&gt;&gt;&gt;</span> writeLine</span>
<span id="cb5-21"><a href="#cb5-21" aria-hidden="true" tabindex="-1"></a>    <span class="op">&gt;&gt;&gt;</span> readLine</span>
<span id="cb5-22"><a href="#cb5-22" aria-hidden="true" tabindex="-1"></a>    <span class="op">&gt;&gt;&gt;</span> constA <span class="st">&quot;Welcome!&quot;</span></span>
<span id="cb5-23"><a href="#cb5-23" aria-hidden="true" tabindex="-1"></a>    <span class="op">&gt;&gt;&gt;</span> writeLine</span></code></pre></div>
<p>Great, that should feel pretty straight-forward, it's trivial to
convert sequential <code>Applicative</code> programs like this.</p>
<p>In order to run it, we still need to use the IO monad, since that's
just how <code>base</code> does IO, but we can use the nifty
<code>Kleisli</code> newtype wrapper which turns <em>any</em> monadic
computation into a valid Arrow by embedding the monadic effects into the
Arrow structure.</p>
<p>Here's how we implement the <code>ReadWrite</code> instance for
<code>Kleisli IO</code>:</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="kw">instance</span> <span class="dt">ReadWrite</span> (<span class="dt">Kleisli</span> <span class="dt">IO</span>) <span class="kw">where</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>  readLine <span class="ot">=</span> <span class="dt">Kleisli</span> <span class="op">$</span> \() <span class="ot">-&gt;</span> <span class="fu">getLine</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>  writeLine <span class="ot">=</span> <span class="dt">Kleisli</span> <span class="op">$</span> \msg <span class="ot">-&gt;</span> <span class="fu">putStrLn</span> msg</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="ot">run ::</span> <span class="dt">Kleisli</span> <span class="dt">IO</span> i o <span class="ot">-&gt;</span> i <span class="ot">-&gt;</span> <span class="dt">IO</span> o</span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>run prog i <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a>  runKleisli prog i</span></code></pre></div>
<p>And it runs just fine:</p>
<pre><code>&gt;&gt;&gt; run (myProgram &quot;Hello&quot;) ()
Hello, what is your name?
Chris
Welcome!</code></pre>
<p>Let's look a little closer at <code>Kleisli</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="kw">newtype</span> <span class="dt">Kleisli</span> m a b <span class="ot">=</span> <span class="dt">Kleisli</span> {<span class="ot"> runKleisli ::</span> a <span class="ot">-&gt;</span> m b }</span></code></pre></div>
<p>Look familiar? It's just the continuation function from monadic bind
hiding in there.</p>
<p>There's a difference though, now that arbitrary function is part of
our <em>implementation</em>, not our interface!</p>
<p>This is important, because it means we can invent a different
implementation of our <code>ReadWrite</code> interface that just tracks
the effects that doesn't have to deal with arbitrary binds like
this.</p>
<p>Let's implement a command-recorder that does exactly that.</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">data</span> <span class="dt">Command</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>  <span class="ot">=</span> <span class="dt">ReadLine</span></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">WriteLine</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Show</span>)</span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a><span class="co">-- Just like the applicative we create a custom implementation of the interface which for static analysis.</span></span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a><span class="co">-- The parameters are phantom, we won&#39;t be running anything, so we only care about</span></span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a><span class="co">-- the structure of the effects for now.</span></span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">CommandRecorder</span> i o <span class="ot">=</span> <span class="dt">CommandRecorder</span> [<span class="dt">Command</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 class="co">-- We need a Category instance since it&#39;s a pre-requisite for Arrow:</span></span>
<span id="cb9-12"><a href="#cb9-12" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Category</span> <span class="dt">CommandRecorder</span> <span class="kw">where</span></span>
<span id="cb9-13"><a href="#cb9-13" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- The identity command does nothing, so it records no commands.</span></span>
<span id="cb9-14"><a href="#cb9-14" aria-hidden="true" tabindex="-1"></a>  <span class="fu">id</span> <span class="ot">=</span> <span class="dt">CommandRecorder</span> []</span>
<span id="cb9-15"><a href="#cb9-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-16"><a href="#cb9-16" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- Composition of two CommandRecorders just collects their command lists.</span></span>
<span id="cb9-17"><a href="#cb9-17" aria-hidden="true" tabindex="-1"></a>  (<span class="dt">CommandRecorder</span> cmds2) <span class="op">.</span> (<span class="dt">CommandRecorder</span> cmds1) <span class="ot">=</span> <span class="dt">CommandRecorder</span> (cmds1 <span class="op">&lt;&gt;</span> cmds2)</span>
<span id="cb9-18"><a href="#cb9-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-19"><a href="#cb9-19" aria-hidden="true" tabindex="-1"></a><span class="co">-- Now the Arrow instance.</span></span>
<span id="cb9-20"><a href="#cb9-20" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Arrow</span> <span class="dt">CommandRecorder</span> <span class="kw">where</span></span>
<span id="cb9-21"><a href="#cb9-21" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- We know this function must be pure (barring errors), so we don&#39;t</span></span>
<span id="cb9-22"><a href="#cb9-22" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- need to track any effects from it.</span></span>
<span id="cb9-23"><a href="#cb9-23" aria-hidden="true" tabindex="-1"></a>  arr _ <span class="ot">=</span> <span class="dt">CommandRecorder</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 class="co">-- Don&#39;t worry about this combinator yet, we&#39;ll come back to it.</span></span>
<span id="cb9-26"><a href="#cb9-26" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- For now we&#39;ll collect the effects from both sides.</span></span>
<span id="cb9-27"><a href="#cb9-27" aria-hidden="true" tabindex="-1"></a>  (<span class="dt">CommandRecorder</span> cmds1) <span class="op">***</span> (<span class="dt">CommandRecorder</span> cmds2) <span class="ot">=</span> <span class="dt">CommandRecorder</span> (cmds1 <span class="op">&lt;&gt;</span> cmds2)</span>
<span id="cb9-28"><a href="#cb9-28" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-29"><a href="#cb9-29" aria-hidden="true" tabindex="-1"></a><span class="co">-- | Now implementing the ReadWrite instance is just a matter of collecting the commands</span></span>
<span id="cb9-30"><a href="#cb9-30" aria-hidden="true" tabindex="-1"></a><span class="co">-- the program is running.</span></span>
<span id="cb9-31"><a href="#cb9-31" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">ReadWrite</span> <span class="dt">CommandRecorder</span> <span class="kw">where</span></span>
<span id="cb9-32"><a href="#cb9-32" aria-hidden="true" tabindex="-1"></a>  readLine <span class="ot">=</span> <span class="dt">CommandRecorder</span> [<span class="dt">ReadLine</span>]</span>
<span id="cb9-33"><a href="#cb9-33" aria-hidden="true" tabindex="-1"></a>  writeLine <span class="ot">=</span> <span class="dt">CommandRecorder</span> [<span class="dt">WriteLine</span>]</span>
<span id="cb9-34"><a href="#cb9-34" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-35"><a href="#cb9-35" aria-hidden="true" tabindex="-1"></a><span class="co">-- | A helper to run our program and get the list of commands it would execute</span></span>
<span id="cb9-36"><a href="#cb9-36" aria-hidden="true" tabindex="-1"></a><span class="ot">recordCommands ::</span> <span class="dt">CommandRecorder</span> i o <span class="ot">-&gt;</span> [<span class="dt">Command</span>]</span>
<span id="cb9-37"><a href="#cb9-37" aria-hidden="true" tabindex="-1"></a>recordCommands (<span class="dt">CommandRecorder</span> cmds) <span class="ot">=</span> cmds</span>
<span id="cb9-38"><a href="#cb9-38" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-39"><a href="#cb9-39" aria-hidden="true" tabindex="-1"></a><span class="co">-- | Here&#39;s a helper for printing out the effects a program will run.</span></span>
<span id="cb9-40"><a href="#cb9-40" aria-hidden="true" tabindex="-1"></a><span class="ot">analyze ::</span> <span class="dt">CommandRecorder</span> i o <span class="ot">-&gt;</span> <span class="dt">IO</span> ()</span>
<span id="cb9-41"><a href="#cb9-41" aria-hidden="true" tabindex="-1"></a>analyze prog <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb9-42"><a href="#cb9-42" aria-hidden="true" tabindex="-1"></a>  <span class="kw">let</span> commands <span class="ot">=</span> recordCommands prog</span>
<span id="cb9-43"><a href="#cb9-43" aria-hidden="true" tabindex="-1"></a>  <span class="fu">print</span> commands</span></code></pre></div>
<p>We can analyze our program and it'll show us which effects it will
run if we were to execute it:</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="op">&gt;&gt;&gt;</span> analyze (myProgram <span class="st">&quot;Hello&quot;</span>)</span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>[<span class="dt">WriteLine</span>,<span class="dt">ReadLine</span>,<span class="dt">WriteLine</span>]</span></code></pre></div>
<p>Okay, we've achieved the ability to analyze and execute our program
at parity with the Applicative version, but isn't it silly that we're
asking the user their name and simply ignoring it? As it turns out, our
Arrow interface is quantifiably more expressive: we can use results of
past effects in future effects! Since we're now allowing
<code>writeLine</code> to take it's input dynamically we no longer track
the output in the structure of the command itself. This bit might seem
like a step back, but if you still wanted the old version you could of
course still define it:
<code>writeLineStatic :: String -&gt; k () ()</code>. Arrows allow us
the flexibility to choose which we prefer. We'll chat a bit more about
this later in the article.</p>
<p>Here's something we couldn't do with the Applicative version, we can
rewrite the program to greet the user by the name they provide. While
we're at it, why not receive the greeting message as an input too?</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="co">-- | This program uses the name provided by the user in the response.</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="ot">myProgram2 ::</span> (<span class="dt">ReadWrite</span> k) <span class="ot">=&gt;</span> k <span class="dt">String</span> ()</span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>myProgram2 <span class="ot">=</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>  arr (\greeting <span class="ot">-&gt;</span> greeting <span class="op">&lt;&gt;</span> <span class="st">&quot;, what is your name?&quot;</span>)</span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">&gt;&gt;&gt;</span> writeLine</span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">&gt;&gt;&gt;</span> readLine</span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">&gt;&gt;&gt;</span> arr (\name <span class="ot">-&gt;</span> <span class="st">&quot;Welcome, &quot;</span> <span class="op">&lt;&gt;</span> name <span class="op">&lt;&gt;</span> <span class="st">&quot;!&quot;</span>)</span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a>    <span class="op">&gt;&gt;&gt;</span> writeLine</span></code></pre></div>
<p>Composing arrows lets us route data from one effect to the next, and
<code>arr</code> let's us map over values to change them just like
<code>fmap</code> does for Functors. The structure of the effects are
still <em>statically defined</em>, so even when routing input we can
still analyze the entire program ahead of time:</p>
<pre><code>&gt;&gt;&gt; analyze myProgram2
[WriteLine, ReadLine, WriteLine]

&gt;&gt;&gt; run myProgram2 &quot;Hello&quot;
Hello, what is your name?
Chris
Welcome, Chris!</code></pre>
<p>Nifty!</p>
<h2 id="levelling-up">Levelling Up</h2>
<p>We're off to a great start, the ability to use the results of past
effects is already better than we could get from Selective Applicative,
without sacrificing any of the analysis capabilities we had in the
Applicative version.</p>
<p>However, at the moment our programs are all still just linear
sequences of commands. What happens if we want to route results from an
earlier effect down to one far later in the program?</p>
<p>We need a bit more power, time to call back to that
<code>(***)</code> we ignored earlier, and while we're at it, let's look
at <code>(&amp;&amp;&amp;)</code> too, which we get for free when we
implement <code>(***)</code>.</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">(***) ::</span> <span class="dt">Arrow</span> k <span class="ot">=&gt;</span> k a b <span class="ot">-&gt;</span> k c d <span class="ot">-&gt;</span> k (a, c) (b, d)</span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="ot">(&amp;&amp;&amp;) ::</span> <span class="dt">Arrow</span> k <span class="ot">=&gt;</span> k a b <span class="ot">-&gt;</span> k a c <span class="ot">-&gt;</span> k a (b, c)</span></code></pre></div>
<p>These operators allow us to take two independent programs in our
arrow interface and compose them <em>in parallel</em> to one another,
rather than sequentially. What <em>parallel</em> means is going to be up
to the implementation (within the scope of the <code>Arrow</code> laws),
but the key part is that these two sides don't depend on each other,
which is distinct from the normal sequential composition we've been
doing with <code>(&gt;&gt;&gt;)</code>.</p>
<p>With these we can write a now write a <em>slightly</em> more complex
program which routes values around, and can forward values from earlier
effects to later ones.</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="kw">import</span> <span class="dt">UnliftIO.Directory</span> <span class="kw">qualified</span> <span class="kw">as</span> <span class="dt">Directory</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="co">-- The effects we&#39;ll need for this example</span></span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> (<span class="dt">Arrow</span> k) <span class="ot">=&gt;</span> <span class="dt">FileCopy</span> k <span class="kw">where</span></span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a><span class="ot">  readLine ::</span> k () <span class="dt">String</span></span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a><span class="ot">  writeLine ::</span> k <span class="dt">String</span> ()</span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a><span class="ot">  copyFile ::</span> k (<span class="dt">String</span>, <span class="dt">String</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">data</span> <span class="dt">Command</span></span>
<span id="cb14-10"><a href="#cb14-10" aria-hidden="true" tabindex="-1"></a>  <span class="ot">=</span> <span class="dt">ReadLine</span></span>
<span id="cb14-11"><a href="#cb14-11" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">WriteLine</span></span>
<span id="cb14-12"><a href="#cb14-12" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">CopyFile</span></span>
<span id="cb14-13"><a href="#cb14-13" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Show</span>)</span>
<span id="cb14-14"><a href="#cb14-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-15"><a href="#cb14-15" aria-hidden="true" tabindex="-1"></a><span class="co">-- Here&#39;s the real executable implementation</span></span>
<span id="cb14-16"><a href="#cb14-16" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">FileCopy</span> (<span class="dt">Kleisli</span> <span class="dt">IO</span>) <span class="kw">where</span></span>
<span id="cb14-17"><a href="#cb14-17" aria-hidden="true" tabindex="-1"></a>  readLine <span class="ot">=</span> <span class="dt">Kleisli</span> <span class="op">$</span> \() <span class="ot">-&gt;</span> <span class="fu">getLine</span></span>
<span id="cb14-18"><a href="#cb14-18" aria-hidden="true" tabindex="-1"></a>  writeLine <span class="ot">=</span> <span class="dt">Kleisli</span> <span class="op">$</span> \msg <span class="ot">-&gt;</span> <span class="fu">putStrLn</span> msg</span>
<span id="cb14-19"><a href="#cb14-19" aria-hidden="true" tabindex="-1"></a>  copyFile <span class="ot">=</span> <span class="dt">Kleisli</span> <span class="op">$</span> \(src, dest) <span class="ot">-&gt;</span> Directory.copyFile src dest</span>
<span id="cb14-20"><a href="#cb14-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-21"><a href="#cb14-21" aria-hidden="true" tabindex="-1"></a><span class="co">-- Helper prompting the user for input.</span></span>
<span id="cb14-22"><a href="#cb14-22" aria-hidden="true" tabindex="-1"></a><span class="ot">prompt ::</span> (<span class="dt">FileCopy</span> cat) <span class="ot">=&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> cat a <span class="dt">String</span></span>
<span id="cb14-23"><a href="#cb14-23" aria-hidden="true" tabindex="-1"></a>prompt msg <span class="ot">=</span></span>
<span id="cb14-24"><a href="#cb14-24" aria-hidden="true" tabindex="-1"></a>  pureC msg</span>
<span id="cb14-25"><a href="#cb14-25" aria-hidden="true" tabindex="-1"></a>    <span class="op">&gt;&gt;&gt;</span> writeLine</span>
<span id="cb14-26"><a href="#cb14-26" aria-hidden="true" tabindex="-1"></a>    <span class="op">&gt;&gt;&gt;</span> readLine</span>
<span id="cb14-27"><a href="#cb14-27" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-28"><a href="#cb14-28" aria-hidden="true" tabindex="-1"></a><span class="ot">fileCopyProgram ::</span> (<span class="dt">FileCopy</span> k) <span class="ot">=&gt;</span> k () ()</span>
<span id="cb14-29"><a href="#cb14-29" aria-hidden="true" tabindex="-1"></a>fileCopyProgram <span class="ot">=</span></span>
<span id="cb14-30"><a href="#cb14-30" aria-hidden="true" tabindex="-1"></a>  ( prompt <span class="st">&quot;Select a file to copy&quot;</span></span>
<span id="cb14-31"><a href="#cb14-31" aria-hidden="true" tabindex="-1"></a>      <span class="op">&amp;&amp;&amp;</span> prompt <span class="st">&quot;Select the destination&quot;</span></span>
<span id="cb14-32"><a href="#cb14-32" aria-hidden="true" tabindex="-1"></a>  )</span>
<span id="cb14-33"><a href="#cb14-33" aria-hidden="true" tabindex="-1"></a>    <span class="op">&gt;&gt;&gt;</span> copyFile</span></code></pre></div>
<p>This program prompts the user for a source file and a destination
file, then copies the source file to the destination. Notably, each
prompt is independent of one another, that is, they don't have any
<strong>data-dependencies</strong> on one another. But,
<code>copyFile</code> takes <em>two</em> arguments, the results of each
prompt. <code>(&amp;&amp;&amp;)</code> allows us to express this.</p>
<p>Let's run it:</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> run fileCopyProgram ()</span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Select</span> a file to copy</span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a>ShoppingList.md</span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Select</span> the destination</span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a>ShoppingList.backup</span></code></pre></div>
<p>Uhh, okay so you can't see the result, but trust me it works!
Kleisli's implementation of <code>(***)</code> just runs the left side,
<em>then</em> the right side; but if, for other applications, you wanted
real parallel execution you could write your implementation which runs
each pair of parallel operations using <code>Concurrently</code> or
something like it and your program will magically become as parallel as
your data-dependencies allow! Caveat emptor, but at least having the
option is nice, we don't get that from the Monadic interface where
data-dependencies are hidden from us.</p>
<p>Now for the analysis.</p>
<p>We could, of course, still collect and print out the <em>list</em> of
effects that would be run, but I'm bored of that, so let's level that up
too. Now that we have both sequential and parallel composition, our
programs are a <em>tree</em> of operations, so our analysis tools should
probably follow suite.</p>
<p>Here's a rewrite of our <code>CommandRecorder</code> which tracks the
whole tree of effects:</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">-- | We can represent the effects in our computations as a tree now.</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">CommandTree</span> eff</span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a>  <span class="ot">=</span> <span class="dt">Effect</span> eff</span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">Identity</span></span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">Composed</span> (<span class="dt">CommandTree</span> eff <span class="co">{- &gt;&gt;&gt; -}</span>) (<span class="dt">CommandTree</span> eff)</span>
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="co">-- (***)</span></span>
<span id="cb16-7"><a href="#cb16-7" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Parallel</span></span>
<span id="cb16-8"><a href="#cb16-8" aria-hidden="true" tabindex="-1"></a>      (<span class="dt">CommandTree</span> eff) <span class="co">-- First</span></span>
<span id="cb16-9"><a href="#cb16-9" aria-hidden="true" tabindex="-1"></a>      (<span class="dt">CommandTree</span> eff) <span class="co">-- Second</span></span>
<span id="cb16-10"><a href="#cb16-10" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>, <span class="dt">Ord</span>, <span class="dt">Functor</span>, <span class="dt">Traversable</span>, <span class="dt">Foldable</span>)</span>
<span id="cb16-11"><a href="#cb16-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-12"><a href="#cb16-12" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">CommandRecorder</span> eff i o <span class="ot">=</span> <span class="dt">CommandRecorder</span> (<span class="dt">CommandTree</span> eff)</span>
<span id="cb16-13"><a href="#cb16-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-14"><a href="#cb16-14" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Category</span> (<span class="dt">CommandRecorder</span> eff) <span class="kw">where</span></span>
<span id="cb16-15"><a href="#cb16-15" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- The identity command does nothing, so it records no commands.</span></span>
<span id="cb16-16"><a href="#cb16-16" aria-hidden="true" tabindex="-1"></a>  <span class="fu">id</span> <span class="ot">=</span> <span class="dt">CommandRecorder</span> <span class="dt">Identity</span></span>
<span id="cb16-17"><a href="#cb16-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-18"><a href="#cb16-18" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- I collapse redundant &#39;Identity&#39;s for clarity.</span></span>
<span id="cb16-19"><a href="#cb16-19" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- The category laws make this safe to do.</span></span>
<span id="cb16-20"><a href="#cb16-20" aria-hidden="true" tabindex="-1"></a>  (<span class="dt">CommandRecorder</span> <span class="dt">Identity</span>) <span class="op">.</span> (<span class="dt">CommandRecorder</span> cmds1) <span class="ot">=</span> <span class="dt">CommandRecorder</span> cmds1</span>
<span id="cb16-21"><a href="#cb16-21" aria-hidden="true" tabindex="-1"></a>  (<span class="dt">CommandRecorder</span> cmds2) <span class="op">.</span> (<span class="dt">CommandRecorder</span> <span class="dt">Identity</span>) <span class="ot">=</span> <span class="dt">CommandRecorder</span> cmds2</span>
<span id="cb16-22"><a href="#cb16-22" aria-hidden="true" tabindex="-1"></a>  (<span class="dt">CommandRecorder</span> cmds2) <span class="op">.</span> (<span class="dt">CommandRecorder</span> cmds1) <span class="ot">=</span> <span class="dt">CommandRecorder</span> (<span class="dt">Composed</span> cmds1 cmds2)</span>
<span id="cb16-23"><a href="#cb16-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-24"><a href="#cb16-24" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Arrow</span> (<span class="dt">CommandRecorder</span> eff) <span class="kw">where</span></span>
<span id="cb16-25"><a href="#cb16-25" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- We don&#39;t bother tracking pure functions, so arr is a no-op.</span></span>
<span id="cb16-26"><a href="#cb16-26" aria-hidden="true" tabindex="-1"></a>  arr _f <span class="ot">=</span> <span class="dt">CommandRecorder</span> <span class="dt">Identity</span></span>
<span id="cb16-27"><a href="#cb16-27" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-28"><a href="#cb16-28" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- Track when we fork into parallel execution paths as part of the tree.</span></span>
<span id="cb16-29"><a href="#cb16-29" aria-hidden="true" tabindex="-1"></a>  (<span class="dt">CommandRecorder</span> cmdsL) <span class="op">***</span> (<span class="dt">CommandRecorder</span> cmdsR) <span class="ot">=</span> <span class="dt">CommandRecorder</span> (<span class="dt">Parallel</span> cmdsL cmdsR)</span>
<span id="cb16-30"><a href="#cb16-30" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-31"><a href="#cb16-31" aria-hidden="true" tabindex="-1"></a><span class="co">-- | The interface implementation just tracks the commands</span></span>
<span id="cb16-32"><a href="#cb16-32" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">FileCopy</span> (<span class="dt">CommandRecorder</span> <span class="dt">Command</span>) <span class="kw">where</span></span>
<span id="cb16-33"><a href="#cb16-33" aria-hidden="true" tabindex="-1"></a>  readLine <span class="ot">=</span> <span class="dt">CommandRecorder</span> (<span class="dt">Effect</span> <span class="dt">ReadLine</span>)</span>
<span id="cb16-34"><a href="#cb16-34" aria-hidden="true" tabindex="-1"></a>  writeLine <span class="ot">=</span> <span class="dt">CommandRecorder</span> (<span class="dt">Effect</span> <span class="dt">WriteLine</span>)</span>
<span id="cb16-35"><a href="#cb16-35" aria-hidden="true" tabindex="-1"></a>  copyFile <span class="ot">=</span> <span class="dt">CommandRecorder</span> (<span class="dt">Effect</span> <span class="dt">CopyFile</span>)</span>
<span id="cb16-36"><a href="#cb16-36" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-37"><a href="#cb16-37" aria-hidden="true" tabindex="-1"></a><span class="ot">analyze ::</span> <span class="dt">CommandRecorder</span> <span class="dt">Command</span> i o <span class="ot">-&gt;</span> <span class="dt">IO</span> ()</span>
<span id="cb16-38"><a href="#cb16-38" aria-hidden="true" tabindex="-1"></a>analyze prog <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb16-39"><a href="#cb16-39" aria-hidden="true" tabindex="-1"></a>  <span class="kw">let</span> commands <span class="ot">=</span> recordCommands prog</span>
<span id="cb16-40"><a href="#cb16-40" aria-hidden="true" tabindex="-1"></a>  <span class="fu">putStrLn</span> <span class="op">$</span> renderCommandTree commands</span></code></pre></div>
<p>Now we can build the tree of effects, let's take advantage of that
and render it as a tree too!</p>
<p>Here's a function that renders any program tree down into a
flow-chart description using the <code>mermaid</code> diagramming
language.</p>
<p>Don't judge me for the implementation of my mermaid renderer... In
fact, if you have a nicer one please send it to me :)</p>
<p>(It's not terribly important, so feel free to skip it)</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="ot">diagram ::</span> <span class="dt">CommandRecorder</span> <span class="dt">Command</span> i o <span class="ot">-&gt;</span> <span class="dt">IO</span> ()</span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a>diagram prog <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">let</span> commands <span class="ot">=</span> recordCommands prog</span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a>  <span class="fu">putStrLn</span> <span class="op">$</span> commandTreeToMermaid commands</span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a><span class="co">-- | A helper to render our command tree as a flow-chart style mermaid diagram.</span></span>
<span id="cb17-7"><a href="#cb17-7" aria-hidden="true" tabindex="-1"></a><span class="ot">commandTreeToMermaid ::</span> <span class="kw">forall</span> eff<span class="op">.</span> (<span class="dt">Show</span> eff) <span class="ot">=&gt;</span> <span class="dt">CommandTree</span> eff <span class="ot">-&gt;</span> <span class="dt">String</span></span>
<span id="cb17-8"><a href="#cb17-8" aria-hidden="true" tabindex="-1"></a>commandTreeToMermaid cmdTree <span class="ot">=</span></span>
<span id="cb17-9"><a href="#cb17-9" aria-hidden="true" tabindex="-1"></a>  <span class="kw">let</span> preamble <span class="ot">=</span> <span class="st">&quot;flowchart TD\n&quot;</span></span>
<span id="cb17-10"><a href="#cb17-10" aria-hidden="true" tabindex="-1"></a>      (outputNodes, links) <span class="ot">=</span></span>
<span id="cb17-11"><a href="#cb17-11" aria-hidden="true" tabindex="-1"></a>        renderNode cmdTree</span>
<span id="cb17-12"><a href="#cb17-12" aria-hidden="true" tabindex="-1"></a>          <span class="op">&amp;</span> <span class="fu">flip</span> runReaderT ([<span class="st">&quot;Input&quot;</span>]<span class="ot"> ::</span> [<span class="dt">String</span>])</span>
<span id="cb17-13"><a href="#cb17-13" aria-hidden="true" tabindex="-1"></a>          <span class="op">&amp;</span> <span class="fu">flip</span> evalState (<span class="dv">0</span><span class="ot"> ::</span> <span class="dt">Int</span>)</span>
<span id="cb17-14"><a href="#cb17-14" aria-hidden="true" tabindex="-1"></a>   <span class="kw">in</span> preamble</span>
<span id="cb17-15"><a href="#cb17-15" aria-hidden="true" tabindex="-1"></a>        <span class="op">&lt;&gt;</span> <span class="fu">unlines</span></span>
<span id="cb17-16"><a href="#cb17-16" aria-hidden="true" tabindex="-1"></a>          ( links</span>
<span id="cb17-17"><a href="#cb17-17" aria-hidden="true" tabindex="-1"></a>              <span class="op">&lt;&gt;</span> ((\output <span class="ot">-&gt;</span> output <span class="op">&lt;&gt;</span> <span class="st">&quot; --&gt; Output&quot;</span>) <span class="op">&lt;$&gt;</span> outputNodes)</span>
<span id="cb17-18"><a href="#cb17-18" aria-hidden="true" tabindex="-1"></a>          )</span>
<span id="cb17-19"><a href="#cb17-19" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb17-20"><a href="#cb17-20" aria-hidden="true" tabindex="-1"></a><span class="ot">    newNodeId ::</span> (<span class="dt">MonadState</span> <span class="dt">Int</span> m) <span class="ot">=&gt;</span> m <span class="dt">Int</span></span>
<span id="cb17-21"><a href="#cb17-21" aria-hidden="true" tabindex="-1"></a>    newNodeId <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb17-22"><a href="#cb17-22" aria-hidden="true" tabindex="-1"></a>      n <span class="ot">&lt;-</span> get</span>
<span id="cb17-23"><a href="#cb17-23" aria-hidden="true" tabindex="-1"></a>      put (n <span class="op">+</span> <span class="dv">1</span>)</span>
<span id="cb17-24"><a href="#cb17-24" aria-hidden="true" tabindex="-1"></a>      <span class="fu">return</span> n</span>
<span id="cb17-25"><a href="#cb17-25" aria-hidden="true" tabindex="-1"></a><span class="ot">    renderNode ::</span> <span class="dt">CommandTree</span> eff <span class="ot">-&gt;</span> <span class="dt">ReaderT</span> [<span class="dt">String</span>] (<span class="dt">State</span> <span class="dt">Int</span>) ([<span class="dt">String</span>], [<span class="dt">String</span>])</span>
<span id="cb17-26"><a href="#cb17-26" aria-hidden="true" tabindex="-1"></a>    renderNode <span class="ot">=</span> \<span class="kw">case</span></span>
<span id="cb17-27"><a href="#cb17-27" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Effect</span> cmd <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb17-28"><a href="#cb17-28" aria-hidden="true" tabindex="-1"></a>        prev <span class="ot">&lt;-</span> ask</span>
<span id="cb17-29"><a href="#cb17-29" aria-hidden="true" tabindex="-1"></a>        nodeId <span class="ot">&lt;-</span> newNodeId</span>
<span id="cb17-30"><a href="#cb17-30" aria-hidden="true" tabindex="-1"></a>        <span class="kw">let</span> cmdLabel <span class="ot">=</span> <span class="fu">show</span> cmd</span>
<span id="cb17-31"><a href="#cb17-31" aria-hidden="true" tabindex="-1"></a>            nodeDef <span class="ot">=</span> <span class="fu">show</span> nodeId <span class="op">&lt;&gt;</span> <span class="st">&quot;[&quot;</span> <span class="op">&lt;&gt;</span> cmdLabel <span class="op">&lt;&gt;</span> <span class="st">&quot;]&quot;</span></span>
<span id="cb17-32"><a href="#cb17-32" aria-hidden="true" tabindex="-1"></a>            links <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb17-33"><a href="#cb17-33" aria-hidden="true" tabindex="-1"></a>              x <span class="ot">&lt;-</span> prev</span>
<span id="cb17-34"><a href="#cb17-34" aria-hidden="true" tabindex="-1"></a>              <span class="fu">pure</span> <span class="op">$</span> x <span class="op">&lt;&gt;</span> (<span class="st">&quot; --&gt; &quot;</span> <span class="op">&lt;&gt;</span> nodeDef)</span>
<span id="cb17-35"><a href="#cb17-35" aria-hidden="true" tabindex="-1"></a>        <span class="fu">pure</span> ([nodeDef], links)</span>
<span id="cb17-36"><a href="#cb17-36" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Identity</span> <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb17-37"><a href="#cb17-37" aria-hidden="true" tabindex="-1"></a>        nodeId <span class="ot">&lt;-</span> newNodeId</span>
<span id="cb17-38"><a href="#cb17-38" aria-hidden="true" tabindex="-1"></a>        prev <span class="ot">&lt;-</span> ask</span>
<span id="cb17-39"><a href="#cb17-39" aria-hidden="true" tabindex="-1"></a>        <span class="kw">let</span> nodeDef <span class="ot">=</span> <span class="fu">show</span> nodeId <span class="op">&lt;&gt;</span> (<span class="st">&quot;[Identity]&quot;</span>)</span>
<span id="cb17-40"><a href="#cb17-40" aria-hidden="true" tabindex="-1"></a>        <span class="kw">let</span> links <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb17-41"><a href="#cb17-41" aria-hidden="true" tabindex="-1"></a>              x <span class="ot">&lt;-</span> prev</span>
<span id="cb17-42"><a href="#cb17-42" aria-hidden="true" tabindex="-1"></a>              <span class="fu">pure</span> <span class="op">$</span> x <span class="op">&lt;&gt;</span> (<span class="st">&quot; --&gt; &quot;</span> <span class="op">&lt;&gt;</span> nodeDef)</span>
<span id="cb17-43"><a href="#cb17-43" aria-hidden="true" tabindex="-1"></a>        <span class="fu">pure</span> ([nodeDef], links)</span>
<span id="cb17-44"><a href="#cb17-44" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Composed</span> cmds1 cmds2 <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb17-45"><a href="#cb17-45" aria-hidden="true" tabindex="-1"></a>        (leftIds, leftNode) <span class="ot">&lt;-</span> renderNode cmds1</span>
<span id="cb17-46"><a href="#cb17-46" aria-hidden="true" tabindex="-1"></a>        (rightIds, rightNode) <span class="ot">&lt;-</span> local (<span class="fu">const</span> leftIds) <span class="op">$</span> renderNode cmds2</span>
<span id="cb17-47"><a href="#cb17-47" aria-hidden="true" tabindex="-1"></a>        <span class="fu">pure</span> (rightIds, leftNode <span class="op">&lt;&gt;</span> rightNode)</span>
<span id="cb17-48"><a href="#cb17-48" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Parallel</span> cmds1 cmds2 <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb17-49"><a href="#cb17-49" aria-hidden="true" tabindex="-1"></a>        prev <span class="ot">&lt;-</span> ask</span>
<span id="cb17-50"><a href="#cb17-50" aria-hidden="true" tabindex="-1"></a>        nodeId <span class="ot">&lt;-</span> newNodeId</span>
<span id="cb17-51"><a href="#cb17-51" aria-hidden="true" tabindex="-1"></a>        <span class="kw">let</span> nodeDef <span class="ot">=</span> <span class="fu">show</span> nodeId <span class="op">&lt;&gt;</span> (<span class="st">&quot;[Parallel]&quot;</span>)</span>
<span id="cb17-52"><a href="#cb17-52" aria-hidden="true" tabindex="-1"></a>        (leftIds, leftNode) <span class="ot">&lt;-</span> local (<span class="fu">const</span> [nodeDef]) <span class="op">$</span> renderNode cmds1</span>
<span id="cb17-53"><a href="#cb17-53" aria-hidden="true" tabindex="-1"></a>        (rightIds, rightNode) <span class="ot">&lt;-</span> local (<span class="fu">const</span> [nodeDef]) <span class="op">$</span> renderNode cmds2</span>
<span id="cb17-54"><a href="#cb17-54" aria-hidden="true" tabindex="-1"></a>        <span class="kw">let</span> thisLink <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb17-55"><a href="#cb17-55" aria-hidden="true" tabindex="-1"></a>              x <span class="ot">&lt;-</span> prev</span>
<span id="cb17-56"><a href="#cb17-56" aria-hidden="true" tabindex="-1"></a>              <span class="fu">pure</span> <span class="op">$</span> x <span class="op">&lt;&gt;</span> (<span class="st">&quot; --&gt; &quot;</span> <span class="op">&lt;&gt;</span> nodeDef)</span>
<span id="cb17-57"><a href="#cb17-57" aria-hidden="true" tabindex="-1"></a>            links <span class="ot">=</span></span>
<span id="cb17-58"><a href="#cb17-58" aria-hidden="true" tabindex="-1"></a>              thisLink</span>
<span id="cb17-59"><a href="#cb17-59" aria-hidden="true" tabindex="-1"></a>                <span class="op">&lt;&gt;</span> leftNode</span>
<span id="cb17-60"><a href="#cb17-60" aria-hidden="true" tabindex="-1"></a>                <span class="op">&lt;&gt;</span> rightNode</span>
<span id="cb17-61"><a href="#cb17-61" aria-hidden="true" tabindex="-1"></a>        <span class="fu">pure</span> (leftIds <span class="op">&lt;&gt;</span> rightIds, links)</span></code></pre></div>
<p>Here's what the diagram output for our <code>fileCopyProgram</code>
looks like:</p>
<pre class="mermaid"><code>&gt;&gt;&gt; diagram fileCopyProgram
flowchart TD
Input --&gt; 0[Parallel]
0[Parallel] --&gt; 1[WriteLine]
1[WriteLine] --&gt; 2[ReadLine]
0[Parallel] --&gt; 3[WriteLine]
3[WriteLine] --&gt; 4[ReadLine]
2[ReadLine] --&gt; 5[CopyFile]
4[ReadLine] --&gt; 5[CopyFile]
5[CopyFile] --&gt; Output</code></pre>
<p>And rendered:</p>
<p><img src="/images/arrow-effects/filecopyprogram.png"
alt="fileCopyProgram" /></p>
<p>Pretty cool eh?</p>
<p>Diagramming is just one thing you can do with our
<code>CommandTree</code>, it's just data, you can fold over it to get
all the effects, analyze which effects depend on which others, all sorts
of things. This provides more clarity into what's happening than
Selective's <code>Over</code> and <code>Under</code> newtypes.</p>
<p>This was a very simple example, but I promise you, with combinations
of <code>arr</code>, <code>(***)</code> and
<code>first</code>/<code>second</code> you can do any possible routing
of values that you might like.</p>
<p>What you can't do yet, however, is to branch between possible
execution paths, then run only one of them.</p>
<p>Let's add that.</p>
<h2 id="branching-with-arrowchoice">Branching with ArrowChoice</h2>
<p>Luckily for us, adding branching is pretty straight-forward. There's
an aptly named <code>ArrowChoice</code> in <code>base</code> that we'll
go ahead and implement.</p>
<p><code>ArrowChoice</code> adds a new combinator:</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="ot">(+++) ::</span> <span class="dt">ArrowChoice</span> k <span class="ot">=&gt;</span> k a b <span class="ot">-&gt;</span> k c d <span class="ot">-&gt;</span> k (<span class="dt">Either</span> a c) (<span class="dt">Either</span> b d)</span></code></pre></div>
<p>Similar to how <code>(***)</code> lets us represent two parallel and
independent programs and fuse them into a single arrow which runs
<em>both</em>, <code>(+++)</code> lets us introduce a conditional branch
to our program, <em>only one path</em> will be executed based on whether
the input value is a <code>Left</code> or a <code>Right</code>.</p>
<p>By implementing <code>(+++)</code> we also get the similar
<code>(|||)</code> for free:</p>
<div class="sourceCode" id="cb20"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="ot">(|||) ::</span> <span class="dt">ArrowChoice</span> k <span class="ot">=&gt;</span> k a c <span class="ot">-&gt;</span> k b c <span class="ot">-&gt;</span> k (<span class="dt">Either</span> a b) c</span></code></pre></div>
<p>Let's add a <code>Branch</code> case to our <code>CommandTree</code>
and implement <code>ArrowChoice</code> for our
<code>CommandRecorder</code>.</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="kw">data</span> <span class="dt">CommandTree</span> eff</span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a>  <span class="ot">=</span> <span class="dt">Effect</span> eff</span>
<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">Identity</span></span>
<span id="cb21-4"><a href="#cb21-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">Composed</span> (<span class="dt">CommandTree</span> eff <span class="co">{- &gt;&gt;&gt; -}</span>) (<span class="dt">CommandTree</span> eff)</span>
<span id="cb21-5"><a href="#cb21-5" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">Parallel</span></span>
<span id="cb21-6"><a href="#cb21-6" aria-hidden="true" tabindex="-1"></a>      (<span class="dt">CommandTree</span> eff) <span class="co">-- First</span></span>
<span id="cb21-7"><a href="#cb21-7" aria-hidden="true" tabindex="-1"></a>      (<span class="dt">CommandTree</span> eff) <span class="co">-- Second</span></span>
<span id="cb21-8"><a href="#cb21-8" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">Branch</span></span>
<span id="cb21-9"><a href="#cb21-9" aria-hidden="true" tabindex="-1"></a>      (<span class="dt">CommandTree</span> eff) <span class="co">-- Left</span></span>
<span id="cb21-10"><a href="#cb21-10" aria-hidden="true" tabindex="-1"></a>      (<span class="dt">CommandTree</span> eff) <span class="co">-- Right</span></span>
<span id="cb21-11"><a href="#cb21-11" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>, <span class="dt">Ord</span>, <span class="dt">Functor</span>, <span class="dt">Traversable</span>, <span class="dt">Foldable</span>)</span>
<span id="cb21-12"><a href="#cb21-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-13"><a href="#cb21-13" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">ArrowChoice</span> (<span class="dt">CommandRecorder</span> eff) <span class="kw">where</span></span>
<span id="cb21-14"><a href="#cb21-14" aria-hidden="true" tabindex="-1"></a>  (<span class="dt">CommandRecorder</span> cmds1) <span class="op">+++</span> (<span class="dt">CommandRecorder</span> cmds2) <span class="ot">=</span> <span class="dt">CommandRecorder</span> (<span class="dt">Branch</span> cmds1 cmds2)</span></code></pre></div>
<p>No problem. As a reminder, here's the branching program we expressed
using Selective Applicatives last time:</p>
<div class="sourceCode" id="cb22"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- | A program using Selective effects</span></span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a><span class="ot">myProgram ::</span> (<span class="dt">ReadWriteDelete</span> m) <span class="ot">=&gt;</span> m <span class="dt">String</span></span>
<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a>myProgram <span class="ot">=</span></span>
<span id="cb22-4"><a href="#cb22-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">let</span> msgKind <span class="ot">=</span></span>
<span id="cb22-5"><a href="#cb22-5" aria-hidden="true" tabindex="-1"></a>        Selective.matchS</span>
<span id="cb22-6"><a href="#cb22-6" aria-hidden="true" tabindex="-1"></a>          <span class="co">-- The list of values our program has explicit branches for.</span></span>
<span id="cb22-7"><a href="#cb22-7" aria-hidden="true" tabindex="-1"></a>          <span class="co">-- These are the values which will be used to crawl codepaths when</span></span>
<span id="cb22-8"><a href="#cb22-8" aria-hidden="true" tabindex="-1"></a>          <span class="co">-- analysing your program using `Over`.</span></span>
<span id="cb22-9"><a href="#cb22-9" aria-hidden="true" tabindex="-1"></a>          (Selective.cases [<span class="st">&quot;friendly&quot;</span>, <span class="st">&quot;mean&quot;</span>])</span>
<span id="cb22-10"><a href="#cb22-10" aria-hidden="true" tabindex="-1"></a>          <span class="co">-- The action we run to get the input</span></span>
<span id="cb22-11"><a href="#cb22-11" aria-hidden="true" tabindex="-1"></a>          readLine</span>
<span id="cb22-12"><a href="#cb22-12" aria-hidden="true" tabindex="-1"></a>          <span class="co">-- What to do with each input</span></span>
<span id="cb22-13"><a href="#cb22-13" aria-hidden="true" tabindex="-1"></a>          ( \<span class="kw">case</span></span>
<span id="cb22-14"><a href="#cb22-14" aria-hidden="true" tabindex="-1"></a>              <span class="st">&quot;friendly&quot;</span> <span class="ot">-&gt;</span> writeLine (<span class="st">&quot;Hello! what is your name?&quot;</span>) <span class="op">*&gt;</span> readLine</span>
<span id="cb22-15"><a href="#cb22-15" aria-hidden="true" tabindex="-1"></a>              <span class="st">&quot;mean&quot;</span> <span class="ot">-&gt;</span></span>
<span id="cb22-16"><a href="#cb22-16" aria-hidden="true" tabindex="-1"></a>                <span class="kw">let</span> msg <span class="ot">=</span> <span class="fu">unlines</span> [ <span class="st">&quot;Hey doofus, what do you want?&quot;</span></span>
<span id="cb22-17"><a href="#cb22-17" aria-hidden="true" tabindex="-1"></a>                                  , <span class="st">&quot;Too late. I deleted your hard-drive.&quot;</span></span>
<span id="cb22-18"><a href="#cb22-18" aria-hidden="true" tabindex="-1"></a>                                  , <span class="st">&quot;How do you feel about that?&quot;</span></span>
<span id="cb22-19"><a href="#cb22-19" aria-hidden="true" tabindex="-1"></a>                                  ]</span>
<span id="cb22-20"><a href="#cb22-20" aria-hidden="true" tabindex="-1"></a>                 <span class="kw">in</span> writeLine msg <span class="op">*&gt;</span> deleteMyHardDrive <span class="op">*&gt;</span> readLine</span>
<span id="cb22-21"><a href="#cb22-21" aria-hidden="true" tabindex="-1"></a>              <span class="co">-- This can&#39;t actually happen.</span></span>
<span id="cb22-22"><a href="#cb22-22" aria-hidden="true" tabindex="-1"></a>              _ <span class="ot">-&gt;</span> <span class="fu">error</span> <span class="st">&quot;impossible&quot;</span></span>
<span id="cb22-23"><a href="#cb22-23" aria-hidden="true" tabindex="-1"></a>          )</span>
<span id="cb22-24"><a href="#cb22-24" aria-hidden="true" tabindex="-1"></a>      prompt <span class="ot">=</span> writeLine <span class="st">&quot;Select your mood: friendly or mean&quot;</span></span>
<span id="cb22-25"><a href="#cb22-25" aria-hidden="true" tabindex="-1"></a>      fallback <span class="ot">=</span></span>
<span id="cb22-26"><a href="#cb22-26" aria-hidden="true" tabindex="-1"></a>        (writeLine <span class="st">&quot;That was unexpected. You&#39;re an odd one aren&#39;t you?&quot;</span>)</span>
<span id="cb22-27"><a href="#cb22-27" aria-hidden="true" tabindex="-1"></a>          <span class="op">&lt;&amp;&gt;</span> \() actualInput <span class="ot">-&gt;</span> <span class="st">&quot;Got unknown input: &quot;</span> <span class="op">&lt;&gt;</span> actualInput</span>
<span id="cb22-28"><a href="#cb22-28" aria-hidden="true" tabindex="-1"></a>   <span class="kw">in</span> prompt</span>
<span id="cb22-29"><a href="#cb22-29" aria-hidden="true" tabindex="-1"></a>        <span class="op">*&gt;</span> Selective.branch</span>
<span id="cb22-30"><a href="#cb22-30" aria-hidden="true" tabindex="-1"></a>          msgKind</span>
<span id="cb22-31"><a href="#cb22-31" aria-hidden="true" tabindex="-1"></a>          fallback</span>
<span id="cb22-32"><a href="#cb22-32" aria-hidden="true" tabindex="-1"></a>          (<span class="fu">pure</span> <span class="fu">id</span>)</span></code></pre></div>
<p>This example was always a bit forced just because of how limited
Selective Applicatives are, but let's copy it over into our Arrow setup
anyways.</p>
<p>First we'll implement <code>ArrowChoice</code> for our
<code>CommandRecorder</code>.</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="co">-- Define our effects</span></span>
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> (<span class="dt">Arrow</span> k) <span class="ot">=&gt;</span> <span class="dt">ReadWriteDelete</span> k <span class="kw">where</span></span>
<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a><span class="ot">  readLine ::</span> k () <span class="dt">String</span></span>
<span id="cb23-4"><a href="#cb23-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb23-5"><a href="#cb23-5" aria-hidden="true" tabindex="-1"></a><span class="ot">  writeLine ::</span> k <span class="dt">String</span> ()</span>
<span id="cb23-6"><a href="#cb23-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb23-7"><a href="#cb23-7" aria-hidden="true" tabindex="-1"></a><span class="ot">  deleteMyHardDrive ::</span> k () ()</span>
<span id="cb23-8"><a href="#cb23-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb23-9"><a href="#cb23-9" aria-hidden="true" tabindex="-1"></a><span class="co">-- New commands for the new effects</span></span>
<span id="cb23-10"><a href="#cb23-10" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Command</span></span>
<span id="cb23-11"><a href="#cb23-11" aria-hidden="true" tabindex="-1"></a>  <span class="ot">=</span> <span class="dt">ReadLine</span></span>
<span id="cb23-12"><a href="#cb23-12" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">WriteLine</span></span>
<span id="cb23-13"><a href="#cb23-13" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">DeleteMyHardDrive</span></span>
<span id="cb23-14"><a href="#cb23-14" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Show</span>)</span>
<span id="cb23-15"><a href="#cb23-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb23-16"><a href="#cb23-16" aria-hidden="true" tabindex="-1"></a><span class="co">-- Track the effects</span></span>
<span id="cb23-17"><a href="#cb23-17" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">ReadWriteDelete</span> <span class="dt">CommandRecorder</span> <span class="kw">where</span></span>
<span id="cb23-18"><a href="#cb23-18" aria-hidden="true" tabindex="-1"></a>  readLine <span class="ot">=</span> <span class="dt">CommandRecorder</span> (<span class="dt">Pure</span> <span class="dt">ReadLine</span>)</span>
<span id="cb23-19"><a href="#cb23-19" aria-hidden="true" tabindex="-1"></a>  writeLine <span class="ot">=</span> <span class="dt">CommandRecorder</span> (<span class="dt">Pure</span> <span class="dt">WriteLine</span>)</span>
<span id="cb23-20"><a href="#cb23-20" aria-hidden="true" tabindex="-1"></a>  deleteMyHardDrive <span class="ot">=</span> <span class="dt">CommandRecorder</span> (<span class="dt">Pure</span> <span class="dt">DeleteMyHardDrive</span>)</span>
<span id="cb23-21"><a href="#cb23-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb23-22"><a href="#cb23-22" aria-hidden="true" tabindex="-1"></a><span class="co">-- Here&#39;s the runnable implementation</span></span>
<span id="cb23-23"><a href="#cb23-23" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">ReadWriteDelete</span> (<span class="dt">Kleisli</span> <span class="dt">IO</span>) <span class="kw">where</span></span>
<span id="cb23-24"><a href="#cb23-24" aria-hidden="true" tabindex="-1"></a>  readLine <span class="ot">=</span> <span class="dt">Kleisli</span> <span class="op">$</span> \() <span class="ot">-&gt;</span> <span class="fu">getLine</span></span>
<span id="cb23-25"><a href="#cb23-25" aria-hidden="true" tabindex="-1"></a>  writeLine <span class="ot">=</span> <span class="dt">Kleisli</span> <span class="op">$</span> \msg <span class="ot">-&gt;</span> <span class="fu">putStrLn</span> msg</span>
<span id="cb23-26"><a href="#cb23-26" aria-hidden="true" tabindex="-1"></a>  deleteMyHardDrive <span class="ot">=</span> <span class="dt">Kleisli</span> <span class="op">$</span> \() <span class="ot">-&gt;</span> <span class="fu">putStrLn</span> <span class="st">&quot;Deleting hard drive... Just kidding!&quot;</span></span></code></pre></div>
<p>And here's our program which uses <code>ArrowChoice</code>:</p>
<div class="sourceCode" id="cb24"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="ot">branchingProgram ::</span> (<span class="dt">ReadWriteDelete</span> k, <span class="dt">ArrowChoice</span> k) <span class="ot">=&gt;</span> k () ()</span>
<span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a>branchingProgram <span class="ot">=</span></span>
<span id="cb24-3"><a href="#cb24-3" aria-hidden="true" tabindex="-1"></a>  pureC <span class="st">&quot;Select your mood: friendly or mean&quot;</span></span>
<span id="cb24-4"><a href="#cb24-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">&gt;&gt;&gt;</span> writeLine</span>
<span id="cb24-5"><a href="#cb24-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">&gt;&gt;&gt;</span> readLine</span>
<span id="cb24-6"><a href="#cb24-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">&gt;&gt;&gt;</span> mapC</span>
<span id="cb24-7"><a href="#cb24-7" aria-hidden="true" tabindex="-1"></a>      ( \<span class="kw">case</span></span>
<span id="cb24-8"><a href="#cb24-8" aria-hidden="true" tabindex="-1"></a>          <span class="st">&quot;mean&quot;</span> <span class="ot">-&gt;</span> <span class="dt">Left</span> ()</span>
<span id="cb24-9"><a href="#cb24-9" aria-hidden="true" tabindex="-1"></a>          <span class="st">&quot;friendly&quot;</span> <span class="ot">-&gt;</span> <span class="dt">Right</span> ()</span>
<span id="cb24-10"><a href="#cb24-10" aria-hidden="true" tabindex="-1"></a>          <span class="co">-- Just default to friendly</span></span>
<span id="cb24-11"><a href="#cb24-11" aria-hidden="true" tabindex="-1"></a>          _ <span class="ot">-&gt;</span> <span class="dt">Right</span> ()</span>
<span id="cb24-12"><a href="#cb24-12" aria-hidden="true" tabindex="-1"></a>      )</span>
<span id="cb24-13"><a href="#cb24-13" aria-hidden="true" tabindex="-1"></a>    <span class="op">&gt;&gt;&gt;</span> <span class="kw">let</span> friendly <span class="ot">=</span></span>
<span id="cb24-14"><a href="#cb24-14" aria-hidden="true" tabindex="-1"></a>              pureC <span class="st">&quot;Hello! what is your name?&quot;</span></span>
<span id="cb24-15"><a href="#cb24-15" aria-hidden="true" tabindex="-1"></a>                <span class="op">&gt;&gt;&gt;</span> writeLine</span>
<span id="cb24-16"><a href="#cb24-16" aria-hidden="true" tabindex="-1"></a>                <span class="op">&gt;&gt;&gt;</span> readLine</span>
<span id="cb24-17"><a href="#cb24-17" aria-hidden="true" tabindex="-1"></a>                <span class="op">&gt;&gt;&gt;</span> mapC (\name <span class="ot">-&gt;</span> <span class="st">&quot;Lovely to meet you, &quot;</span> <span class="op">&lt;&gt;</span> name <span class="op">&lt;&gt;</span> <span class="st">&quot;!&quot;</span>)</span>
<span id="cb24-18"><a href="#cb24-18" aria-hidden="true" tabindex="-1"></a>                <span class="op">&gt;&gt;&gt;</span> writeLine</span>
<span id="cb24-19"><a href="#cb24-19" aria-hidden="true" tabindex="-1"></a>            mean <span class="ot">=</span></span>
<span id="cb24-20"><a href="#cb24-20" aria-hidden="true" tabindex="-1"></a>              pureC</span>
<span id="cb24-21"><a href="#cb24-21" aria-hidden="true" tabindex="-1"></a>                ( <span class="fu">unlines</span></span>
<span id="cb24-22"><a href="#cb24-22" aria-hidden="true" tabindex="-1"></a>                    [ <span class="st">&quot;Hey doofus, what do you want?&quot;</span>,</span>
<span id="cb24-23"><a href="#cb24-23" aria-hidden="true" tabindex="-1"></a>                      <span class="st">&quot;Too late. I deleted your hard-drive.&quot;</span>,</span>
<span id="cb24-24"><a href="#cb24-24" aria-hidden="true" tabindex="-1"></a>                      <span class="st">&quot;How do you feel about that?&quot;</span></span>
<span id="cb24-25"><a href="#cb24-25" aria-hidden="true" tabindex="-1"></a>                    ]</span>
<span id="cb24-26"><a href="#cb24-26" aria-hidden="true" tabindex="-1"></a>                )</span>
<span id="cb24-27"><a href="#cb24-27" aria-hidden="true" tabindex="-1"></a>                <span class="op">&gt;&gt;&gt;</span> writeLine</span>
<span id="cb24-28"><a href="#cb24-28" aria-hidden="true" tabindex="-1"></a>                <span class="op">&gt;&gt;&gt;</span> deleteMyHardDrive</span>
<span id="cb24-29"><a href="#cb24-29" aria-hidden="true" tabindex="-1"></a>         <span class="kw">in</span> mean <span class="op">|||</span> friendly</span></code></pre></div>
<p>Notice again, this version is actually more expressive than the
Selective Applicative version, it actually greets the user by the name
they provided, how kind.</p>
<p>I'll elide the edits to the mermaid renderer, Branch is very similar
to the implementation of Parallel.</p>
<p>Let's make a mermaid chart like before:</p>
<div class="sourceCode" id="cb25"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> diagram branchingProgram</span>
<span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a>flowchart <span class="dt">TD</span></span>
<span id="cb25-3"><a href="#cb25-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Input</span> <span class="op">--&gt;</span> <span class="dv">0</span>[<span class="dt">WriteLine</span>]</span>
<span id="cb25-4"><a href="#cb25-4" aria-hidden="true" tabindex="-1"></a><span class="dv">0</span>[<span class="dt">WriteLine</span>] <span class="op">--&gt;</span> <span class="dv">1</span>[<span class="dt">ReadLine</span>]</span>
<span id="cb25-5"><a href="#cb25-5" aria-hidden="true" tabindex="-1"></a><span class="dv">1</span>[<span class="dt">ReadLine</span>] <span class="op">--&gt;</span> <span class="dv">2</span>[<span class="dt">Branch</span>]</span>
<span id="cb25-6"><a href="#cb25-6" aria-hidden="true" tabindex="-1"></a><span class="dv">2</span>[<span class="dt">Branch</span>] <span class="op">--&gt;</span> <span class="dv">3</span>[<span class="dt">WriteLine</span>]</span>
<span id="cb25-7"><a href="#cb25-7" aria-hidden="true" tabindex="-1"></a><span class="dv">3</span>[<span class="dt">WriteLine</span>] <span class="op">--&gt;</span> <span class="dv">4</span>[<span class="dt">DeleteMyHardDrive</span>]</span>
<span id="cb25-8"><a href="#cb25-8" aria-hidden="true" tabindex="-1"></a><span class="dv">2</span>[<span class="dt">Branch</span>] <span class="op">--&gt;</span> <span class="dv">5</span>[<span class="dt">WriteLine</span>]</span>
<span id="cb25-9"><a href="#cb25-9" aria-hidden="true" tabindex="-1"></a><span class="dv">5</span>[<span class="dt">WriteLine</span>] <span class="op">--&gt;</span> <span class="dv">6</span>[<span class="dt">ReadLine</span>]</span>
<span id="cb25-10"><a href="#cb25-10" aria-hidden="true" tabindex="-1"></a><span class="dv">6</span>[<span class="dt">ReadLine</span>] <span class="op">--&gt;</span> <span class="dv">7</span>[<span class="dt">WriteLine</span>]</span>
<span id="cb25-11"><a href="#cb25-11" aria-hidden="true" tabindex="-1"></a><span class="dv">4</span>[<span class="dt">DeleteMyHardDrive</span>] <span class="op">--&gt;</span> <span class="dt">Output</span></span>
<span id="cb25-12"><a href="#cb25-12" aria-hidden="true" tabindex="-1"></a><span class="dv">7</span>[<span class="dt">WriteLine</span>] <span class="op">--&gt;</span> <span class="dt">Output</span></span></code></pre></div>
<p><img src="/images/arrow-effects/branching-program.png"
alt="Branching Program" /></p>
<p>See how it's now clear that the effects on one branch differ from
another?</p>
<p>And of course we can run it just as you'd expect:</p>
<pre><code>&gt;&gt;&gt; run branchingProgram
Select your mood: friendly or mean
friendly
Hello! what is your name?
Joe
Lovely to meet you, Joe!

&gt;&gt;&gt; run branchingProgram
Select your mood: friendly or mean
mean
Hey doofus, what do you want?
Too late. I deleted your hard-drive.
How do you feel about that?

Deleting hard drive... Just kidding!</code></pre>
<p>Okay, so the syntax of that last example was starting to get pretty
hairy, if only there was something like do-notation, but for
arrows...</p>
<h2 id="arrow-notation">Arrow Notation</h2>
<p>By enabling the <code>{-# LANGUAGE Arrows #-}</code> pragma we can
use a form of do-notation with arrows. It will automatically route your
inputs wherever you need them using combinators from the
<code>Arrow</code> class and will even translate <code>if</code> and
<code>case</code> statements into <code>ArrowChoice</code> combinators,
it's very impressive.</p>
<p>I won't explain Arrow Notation deeply here, so go ahead and check out
the <a
href="https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/arrows.html">GHC
Manual</a> for a more detailed look.</p>
<p>Here's what our branching program looks like when we translate
it:</p>
<div class="sourceCode" id="cb27"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a><span class="ot">branchingProgramArrowNotation ::</span> (<span class="dt">ReadWriteDelete</span> k, <span class="dt">ArrowChoice</span> k) <span class="ot">=&gt;</span> k () ()</span>
<span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a>branchingProgramArrowNotation <span class="ot">=</span> proc () <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb27-3"><a href="#cb27-3" aria-hidden="true" tabindex="-1"></a>  writeLine <span class="op">-&lt;</span> <span class="st">&quot;Select your mood: friendly or mean&quot;</span></span>
<span id="cb27-4"><a href="#cb27-4" aria-hidden="true" tabindex="-1"></a>  mood <span class="ot">&lt;-</span> readLine <span class="op">-&lt;</span> ()</span>
<span id="cb27-5"><a href="#cb27-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">case</span> mood <span class="kw">of</span></span>
<span id="cb27-6"><a href="#cb27-6" aria-hidden="true" tabindex="-1"></a>    <span class="st">&quot;mean&quot;</span> <span class="ot">-&gt;</span> mean <span class="op">-&lt;</span> ()</span>
<span id="cb27-7"><a href="#cb27-7" aria-hidden="true" tabindex="-1"></a>    <span class="st">&quot;friendly&quot;</span> <span class="ot">-&gt;</span> friendly <span class="op">-&lt;</span> ()</span>
<span id="cb27-8"><a href="#cb27-8" aria-hidden="true" tabindex="-1"></a>    _ <span class="ot">-&gt;</span> friendly <span class="op">-&lt;</span> ()</span>
<span id="cb27-9"><a href="#cb27-9" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb27-10"><a href="#cb27-10" aria-hidden="true" tabindex="-1"></a>    friendly <span class="ot">=</span> proc () <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb27-11"><a href="#cb27-11" aria-hidden="true" tabindex="-1"></a>      writeLine <span class="op">-&lt;</span> <span class="st">&quot;Hello! what is your name?&quot;</span></span>
<span id="cb27-12"><a href="#cb27-12" aria-hidden="true" tabindex="-1"></a>      name <span class="ot">&lt;-</span> readLine <span class="op">-&lt;</span> ()</span>
<span id="cb27-13"><a href="#cb27-13" aria-hidden="true" tabindex="-1"></a>      writeLine <span class="op">-&lt;</span> <span class="st">&quot;Lovely to meet you, &quot;</span> <span class="op">&lt;&gt;</span> name <span class="op">&lt;&gt;</span> <span class="st">&quot;!&quot;</span></span>
<span id="cb27-14"><a href="#cb27-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb27-15"><a href="#cb27-15" aria-hidden="true" tabindex="-1"></a>    mean <span class="ot">=</span> proc () <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb27-16"><a href="#cb27-16" aria-hidden="true" tabindex="-1"></a>      writeLine</span>
<span id="cb27-17"><a href="#cb27-17" aria-hidden="true" tabindex="-1"></a>        <span class="op">-&lt;</span></span>
<span id="cb27-18"><a href="#cb27-18" aria-hidden="true" tabindex="-1"></a>          <span class="fu">unlines</span></span>
<span id="cb27-19"><a href="#cb27-19" aria-hidden="true" tabindex="-1"></a>            [ <span class="st">&quot;Hey doofus, what do you want?&quot;</span>,</span>
<span id="cb27-20"><a href="#cb27-20" aria-hidden="true" tabindex="-1"></a>              <span class="st">&quot;Too late. I deleted your hard-drive.&quot;</span>,</span>
<span id="cb27-21"><a href="#cb27-21" aria-hidden="true" tabindex="-1"></a>              <span class="st">&quot;How do you feel about that?&quot;</span></span>
<span id="cb27-22"><a href="#cb27-22" aria-hidden="true" tabindex="-1"></a>            ]</span>
<span id="cb27-23"><a href="#cb27-23" aria-hidden="true" tabindex="-1"></a>      deleteMyHardDrive <span class="op">-&lt;</span> ()</span></code></pre></div>
<p>It takes a bit of getting used to, but it's not so bad.</p>
<p>Here's the diagram, so we can get an idea of how it's being
translated:</p>
<p><img src="/images/arrow-effects/arrow-notation-messy.png"
alt="Arrow Notation Messy" /></p>
<p>It's not quite as pretty, the translation introduces a lot of
unnecessary calls to <code>Parallel</code> where it's just inserting
<code>Identity</code> on the other side, this is perfectly valid, since
the Category laws require that the <code>Identity</code> won't affect
behaviour, but in our case it's messy and is clogging up our diagram, so
let's clean it up.</p>
<p>The command tree we build as an intermediate step is just a value, so
we can transform it to clean it up no problem.</p>
<p>If you derive <code>Data</code> and <code>Plated</code> for our
<code>Command</code> and <code>CommandTree</code> types then we can do
this with a simple <a
href="https://hackage-content.haskell.org/package/lens-5.3.5/docs/Control-Lens-Plated.html#v:transform">transform</a>
on the tree. <code>transform</code> will rebuild the tree from the
bottom up removing any redundant <code>Identity</code> nodes as it
goes.</p>
<div class="sourceCode" id="cb28"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb28-1"><a href="#cb28-1" aria-hidden="true" tabindex="-1"></a><span class="ot">unredundify ::</span> (<span class="dt">Data</span> eff) <span class="ot">=&gt;</span> <span class="dt">CommandTree</span> eff <span class="ot">-&gt;</span> <span class="dt">CommandTree</span> eff</span>
<span id="cb28-2"><a href="#cb28-2" aria-hidden="true" tabindex="-1"></a>unredundify <span class="ot">=</span> transform \<span class="kw">case</span></span>
<span id="cb28-3"><a href="#cb28-3" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Parallel</span> <span class="dt">Identity</span> right <span class="ot">-&gt;</span> right</span>
<span id="cb28-4"><a href="#cb28-4" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Parallel</span> left <span class="dt">Identity</span> <span class="ot">-&gt;</span> left</span>
<span id="cb28-5"><a href="#cb28-5" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Composed</span> <span class="dt">Identity</span> right <span class="ot">-&gt;</span> right</span>
<span id="cb28-6"><a href="#cb28-6" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Composed</span> left <span class="dt">Identity</span> <span class="ot">-&gt;</span> left</span>
<span id="cb28-7"><a href="#cb28-7" aria-hidden="true" tabindex="-1"></a>  other <span class="ot">-&gt;</span> other</span></code></pre></div>
<p>Diagramming the <code>unredundified</code> version looks much
cleaner:</p>
<p><img src="/images/arrow-effects/arrow-notation-cleaner.png"
alt="Arrow Notation Cleaner" /></p>
<p>We can see here that the with multiple arms are getting collapsed
into a sequence of binary branches, which is perfectly correct of
course, but if you wanted to diagram it as a single branch you could
rewrite the <code>Branch</code> constructor to have a list of options
and collapse them all down with another rewrite rule. Same for
<code>Parallel</code>s of course. You can really do whatever is most
useful for your use-case.</p>
<p>Arrow notation has its quirks, but it's still a substantial
improvement over doing argument routing completely manually.</p>
<h2 id="static-vs-dynamic-data">Static vs Dynamic data</h2>
<p>It's worth a quick note on the difference between static and dynamic
data with Arrows. With Applicatives, all the data needed to define an
effect's behaviour was static, that is, it must be known at the time the
program was constructed, though this might still be at runtime for the
greater Haskell program.</p>
<p>With Arrows it's possible to interleave static and dynamic data, it's
up to the author of the interface.</p>
<p>For example, if one were constructing a build-system they might have
an interface like this:</p>
<div class="sourceCode" id="cb29"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb29-1"><a href="#cb29-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> (<span class="dt">Arrow</span> k) <span class="ot">=&gt;</span> <span class="dt">Builder</span> k <span class="kw">where</span></span>
<span id="cb29-2"><a href="#cb29-2" aria-hidden="true" tabindex="-1"></a><span class="ot">  dynamicReadFile ::</span> k <span class="dt">FilePath</span> <span class="dt">String</span></span>
<span id="cb29-3"><a href="#cb29-3" aria-hidden="true" tabindex="-1"></a><span class="ot">  staticReadFile ::</span> <span class="dt">FilePath</span> <span class="ot">-&gt;</span> k () <span class="dt">String</span></span></code></pre></div>
<p><code>dynamicReadFile</code> takes its <code>FilePath</code> as a
dynamic input, so we won't know which file we're going to read until
execution time, however <code>staticReadFile</code> takes its
<code>FilePath</code> as a static input. You pass it a single
<code>FilePath</code> as a Haskell value when you construct the program.
In this case we can embed the <code>FilePath</code> into the structure
of the effect itself so that it's available during analysis.</p>
<p>While this is a bit more of an advanced use-case, it can be very
useful. In the build-system case you could provide any statically known
dependency files using <code>staticReadFile</code> and the build-system
could check if those files have changed since the last run and safely
replace some subtrees of the build with cached results if no
dependencies in that subtree have changed.</p>
<p>This sort of thing takes careful thought and design, but provides a
lot of flexibility which can unlock whole new programming
techniques.</p>
<p>Folks may well have heard of Haxl, it's a Haskell library for
analyzing programs and batching and caching requests to remote data
sources. The implementation and interface for Haxl is moderately
complex, and is limited in what it can do by the fact that it uses
Monads. I'm curious how effective an Arrow-based version could be.</p>
<h2 id="whats-next">What's next?</h2>
<p>We explored enough classes to enable most basic programs here. At
this point you can branch, express independence between computations,
and route input anywhere you need it. In case you're still hankering for
a bit more expressive power we'll do a lightning quick tour of a few
more classes.</p>
<p>There's <code>ArrowLoop</code> which encodes fixed-point style
recursion.</p>
<div class="sourceCode" id="cb30"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb30-1"><a href="#cb30-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Arrow</span> a <span class="ot">=&gt;</span> <span class="dt">ArrowLoop</span> a <span class="kw">where</span></span>
<span id="cb30-2"><a href="#cb30-2" aria-hidden="true" tabindex="-1"></a><span class="ot">  loop ::</span> a (b, d) (c, d) <span class="ot">-&gt;</span> a b c</span></code></pre></div>
<p>Interestingly, this is actually just another name for
<code>Costrong</code>, as you can see by comparing with <a
href="https://hackage-content.haskell.org/package/profunctors-5.6.3/docs/Data-Profunctor.html#t:Costrong"><code>Costrong</code></a>
from the <code>profunctors</code> package.</p>
<p>If you really really need to be able to completely restructure your
program on the fly you can do so using the <code>ArrowApply</code>
class, which enables applying arbitrary runtime-created arrows.</p>
<div class="sourceCode" id="cb31"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb31-1"><a href="#cb31-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Arrow</span> a <span class="ot">=&gt;</span> <span class="dt">ArrowApply</span> a <span class="kw">where</span></span>
<span id="cb31-2"><a href="#cb31-2" aria-hidden="true" tabindex="-1"></a><span class="ot">    app ::</span> a (a b c, b) c</span></code></pre></div>
<p>This gives you the wildly expressive power to define entirely new
code-paths at runtime. I'd still argue that reasonable programs that
actually <em>need</em> to do this are pretty rare, but sometimes it's a
useful shortcut to avoid some tedium. Note that if you use
<code>app</code>, any effects within the dynamically applied arrow will
be hidden from analysis, but you can still analyze the non-dynamic
parts.</p>
<p>There are a few additional interesting classes which are strangely
missing from <code>base</code>; but they have counterparts in
<code>profunctors</code>. One example would be an arrow counterpart to
<a
href="https://hackage-content.haskell.org/package/profunctors-5.6.3/docs/Data-Profunctor.html#t:Cochoice"><code>Cochoice</code></a>,
which, if it existed, would look something like this:</p>
<div class="sourceCode" id="cb32"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb32-1"><a href="#cb32-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> (<span class="dt">Arrow</span> k) <span class="ot">=&gt;</span> <span class="dt">ArrowCochoice</span> k <span class="kw">where</span></span>
<span id="cb32-2"><a href="#cb32-2" aria-hidden="true" tabindex="-1"></a><span class="ot">  unright ::</span> k (<span class="dt">Either</span> d a) (<span class="dt">Either</span> d b) <span class="ot">-&gt;</span> k a b</span>
<span id="cb32-3"><a href="#cb32-3" aria-hidden="true" tabindex="-1"></a><span class="ot">  unleft ::</span> k (<span class="dt">Either</span> a d) (<span class="dt">Either</span> b d) <span class="ot">-&gt;</span> k a b</span></code></pre></div>
<p>While the behaviour ultimately depends on the implementation, you can
use this to implement things like recursive loops and while-loops, which
avoids one of the more common needs for <code>ArrowApply</code> while
preserving analysis over the contents of the loop.</p>
<p>There's some other good stuff in <code>profunctors</code> so I'd
recommend just browsing around over there, (Thanks Ed). <a
href="https://hackage-content.haskell.org/package/profunctors-5.6.3/docs/Data-Profunctor-Traversing.html#t:Traversing"><code>Traversing</code></a>
lets you apply a profunctor to elements of a Traversable container, <a
href="https://hackage-content.haskell.org/package/profunctors-5.6.3/docs/Data-Profunctor.html#t:Mapping"><code>Mapping</code></a>
does the same for Functors.</p>
<p>Anyways, you can see that most behaviours you take for granted when
writing Haskell code with arbitrary functions in do-notation binds can
generally be decomposed into some combination of Arrow typeclasses which
accomplish the same thing. Using the principal of least-power is a good
rule of thumb here. Generally you should use the lowest-power
abstraction you can reasonably encode your program with, that will
ensure you'll have the strongest potential for analysis.</p>
<h2 id="in-summary">In Summary</h2>
<p>We've discovered that by switching from the Functor-Applicative-Monad
effect system to a Category and Arrow hierarchy we can express
significantly more complex and expressive programs while maintaining the
ability to deeply introspect the programs we create.</p>
<p>We learned how we can collect additional typeclasses to gain more
expressive power, and how we can implement custom instances to analyze
and even diagram our programs.</p>
<p>Lastly we took a look at Arrow notation and how it improves the
burden of syntax for writing these sorts of programs.</p>
<p>So, should we all abandon Monads and write everything using Arrows
instead? Truthfully, I do believe they comprise a better foundation; so
while the current Haskell ecosystem is all-in on Monads, if you the
reader happen to be designing the effects system for a brand new
functional programming language, why not give Arrows a try?</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANkAAAAzCAYAAAAaYa2SAAAABGdBTUEAALGPC/xhBQAAC8VJREFUeAHtXQmwFMUZ/npmFpHzcQgBRSFcAnIfcimICEFEEFAEj5SlUMYkVTEKJpgQSSmSUGWMFimJUEQTFa8UEdAkGENEi0MBBQQMgiCX3Icc8t7MdP6/Z2d2dt/bdd/bHdis/Vc9tqePv3u+7r//ayzF2XvHSmjSCGgEIkPAiIyzZqwR0AgoBLSQ6YOgEYgYAS1kEQOs2WsEtJDpM6ARiBgBLWQRA6zZawS0kOkzoBGIGAEtZBEDrNlrBLSQ6TOgEYgYAS1kEQOs2WsEtJDpM6ARiBgBLWQRA6zZawS0kOkzoBGIGAEtZBEDrNlrBLSQ6TOgEYgYAS1kEQOs2WsErFwhKFlxKmAx+eIYHr60WvAcFBo3hXn1UBjtOgIlDYCyMsj9e+CuWwX3vbfpuTToqgsagWJDIGchs90EJE6iGJTMEeNgDL0JwjSDOlwIiDp1YbRuDzlkJOy5v4PctiXRrksagSJCIFJz0Rw/Eeb1Y5MFLAU8UVIf1k+mQbRql9KiHzUCxYFAZEImuvYmE3FIVigJKwbrnvuBC6pn1f+cd2rYGIK0LupfRCpYZJ6e3kU0awHRvFXhvk/mN/j/bi1A/HM2F9PtiDXilnRNFdaLuvVgkFC6S9+osD1TpfXwLBiXNE/qItnPO3yQ/L6VcP6xEDj7NdCoCapNfyqpX/jBWbEMzvOzvSrDhDl8LIxBwyGqk30bJ3nkEJxFL8Nducyv8n7rNYQ1YSJE+84QNJZJSgm5/b9wXpwDuXeX14/+Da9XOg7KptwNnE74tubNd8EcdH3Q3573JNwP36/c+oPRyQVz+M0wb/D2Rp46ibKfTQRsO7lTypPxvdGwRo5PqpUuOQeHDsD9dAOcxa8CJ44F7enmEC1aIzZlRtAvXaH0wbtgXDWk/JyEFY4egvv5VjhLaM79exMsqoi/vfAFuHw+4mQMHQVr1G3qqfQ+won2MFeKRpNRoEM0aVbptRldrqz0mPAA3nh5aD/kscMQsWoQ37kY5rAxsO68L9xNlaVjQ5Lghf9gl3n9DAPWA9M9U5cETLou5NdnVJuoT8L0/R/CuGZYwFM0vRSxaU/AuKKbEjB58ivI40dJ6QkYLdvC+vlvINp1CvqHC+yrGh27h6vKPSc1xh8yrr+iAfE6o8/AoFXUrAWjU8/gOZsCC6b86jhpdAOCLi2ThCE25TGgRs1geK5zBIziBcaS9xW0D4KsCrNnf8Qeehxo0Ej1yAV/ky4Q0AUfJUWiyfhwV4WqOi6Y6/gxlP3yR94jbUaMNBxrIdG5F2Amv6q77O9wXnsuGBouGAOHwfhuW1XlrF5OmuiPKgIqOnSBNfEBJcDm6DvgkuYDCZ85YZKah7WS86enPa1Do8XlHWFNehDiwhqk5Sah7Nc/TYqk8mEVtSkA1KUX3FXvqvlEk0sgLmoMeYLaKDiUjjKtP90YNnkFHUx1Ga1fo+Y1+lwDd+2KdEPK1duzZ0CSJgGt27r1Hhjdeiueis+/FiuzOt0ccuc2lE4mrR2n2CO/Bws6ayb7DzP9aoAEOUz2nFnenHRxmjfeCnPwCIWp2W8QnDcWVBl/noPPhzn6djjznw5PmddyJJqMfawqkZUsCFXi4Q86fAA4c1o9STYrSHNlSyaZiEwsBM5fnvFMTdZmG9YqYZBnTkHu3K6EQVzWUmkr7u+u+k8gYGr8lg1w6eAx8Q2cqrHUYeW29l0AOkCqX1yryR10kPNMLAhMPK+zOi7U7UnD1imp/EyMTchk5ouBKeMchCFOnkj8+aYY7024Pt1qyAVwN65NtNaohZzw/3KP4mX2uhoifqkmmOevlMdTnViUPHIw8VCZEvk7ORFpDPOm28npoeBD2ysg6jWA8qFenV+OrdGha7nD5S57C3LPFxTgaKj6q7RCSg7PeWkunBfmBPyM3gODsty8Pij7BZcEzfeBRFMyoUNaw6WbnQ8J+6NsTsr1H5L51kMNdT9ZF5R9XuHftOsnH7BCoqASax0md80KyI3rlKksuP7KAeQL/63CYWkra9WB2XdQ0Cz37laBnrzO4XOnfQULFGl5k9JBPrmbPkpySyqN/56dEHQBG517whx3N+yZD/ms8/objZDt2Ab2S0St2pVaLB+sXEipfsq7hYk3Ihx08NuUv5Zi1soNayApAMG+FJPyPfwB/i87/GGKCyRXVdQ/qS7UV7Ggm9wlwTKvuk5ttLPtU4gWbSBLz1JAYWN4lnLltOtPI2QGRXtZoDgYo8xD1go8N/k3Jvlp2QqZdS8dRNY8fDGQ78okSSNwIMjo1icvc6S+bOzHv0itgrP8n5CfkJBRoMKnJKzjlUl1KfgLCNivP48YuQHGpS1g9Bvss8rrbyRCRkY/nHeWwCL7OVuSFHRwSJPkQuzHsM/AxBqCE+Fm/8EUkOiKsqk/SGLNX5s47y1NqpO7d3qmYbxW1KWvU1KJ0wwc5fKDJOyQx4lzfqmxKNZSPinn3X+I/7off+AJGWkwuXWTOris/VBK0dEMlHb9acYYfT1Tkc0yX/uKmGfWKz/wslZkAn+WZnSoujq9P5t9ZDK7FL2VW9ZDRW/pYsjbHKHpuOiy6Ux4GG06qBbPT37W65Uj/jj4Jdy3F4EDIOaN4+C+m3wmvEly+zcaIaM1cSje7dQdRvPWWa3QWfiiCgln1TldJ44YfrFdtfKv4M+5rr0Bgj7lEi0vp2DCsWAkm7Ry08fBc7ggj1J0kkxN0aa9MlNw+mTQbI65kw7TIDIrd8JZMA9yXyI0L9ifigcw/AFhP6wijSopBM6RS0Hml+/PuOT7fRNlWn+5sQ0bBcl+DrRYoyaU68IRQScLIbOfnO4FIVI55HGOVNbOK/PVnNb9jyhB40CRU7c+cPxIzvjzXM5bf6WLZ4A6J0afAanT5/zs6fuc2VTAgG56e/ZMuN/wuRSbLzZFiPwAQQWcqlZFiWOO7iUoVcckWlJLzr/fVFVsfqokOQkcKChjdO+rtACH3dlcYwGTu3ZAaR4awSaZ0f86UqOeuSlIOxkDhipebFJx4KQcUY7KF3b/pnY3rinXLZcKk/xGNoE5FWGTP2k/Nzv4C9beo596x6rOcy7m4Pwkk6h2AVkpt6hyzvgzF9LCzut/VvwEf3CQZ4pMk6l1kmliP/ErsnWvhUl5pXDujM1DdlSdJa9lZ6Zk8+J1SxB7nIISdKDCZppLWk1u3wrQbesTJ5nDuS6ul+QH2U89CvedN+H26O/Z6RSQqDbjGUj6qNk3r7iv89KzKnzPZXvBXMQmP0rh6NqwbpsEOeYOleD1fVJOjNucBkgT4XTXf5AISuz6HDh2BKDkaibKtP7UcXxLM3EgR32QHerAkVKDLiM/Z1aZcH6IjdIEUc8hP9usLjRer9K8ZOaBLq9c8ed1c7LfpY8h+HvafFO0QqZW78JdvlT9KWeZv8K3SyHpawH1FUYe30h9aUF+ERPnrEBhfJdMQmfxK4RicsBCBTeEmTS7pASrIhIGe9ZUstHHk2YarHIyvoBxOoC/EpAfrU6MpTrOgXHeSHSkhDRpQCaVj9q62ROwA/sS/VNKbB5yX16/DIeoU/qFHzOuP9RRkB/DeSsmd+3KUItX5OCBMldpzSrXFYp+luucpuJczOFP7Sxa4F0KhJU1cgI4h8ZffuSCf8D75XkQU3+r9sGvy8evyPV/nVTr/cTnQFOaxTCtov/UJR8rPZ882PQsqQdJjj7o64OMRBE39gXZvJT7KA/jB0gyDtKNeUOgAPGPXpPlDb3zyIiDJNnm/jhpvW/3eVzst3zqAsQ/usDHt3yv9etrBHwEtJD5SOhfjUBECORsLp7sVzOipWm2GoHiQEBrsuLYR/0WBYyAFrIC3hy9tOJAQAtZceyjfosCRkALWQFvjl5acSCghaw49lG/RQEjoIWsgDdHL604ENBCVhz7qN+igBHQQlbAm6OXVhwIaCErjn3Ub1HACGghK+DN0UsrDgS0kBXHPuq3KGAEtJAV8ObopRUHAlrIimMf9VsUMAJayAp4c/TSigMBLWTFsY/6LQoYgf8BIVTf3IgGuLEAAAAASUVORK5CYII=" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Monads are too powerful: The Expressiveness Spectrum</title>
      <link href="https://chrispenner.ca/posts/expressiveness-spectrum"/>
      <id>https://chrispenner.ca/posts/expressiveness-spectrum</id>
      <updated>2025-09-24T00:00:00Z</updated>
      <summary>Monads are a useful tool, but what costs do we pay for their expressive
power?</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/power-small.jpg" alt="Monads are too powerful: The Expressiveness Spectrum">
              <p>Okay, so you and I both know monads are great, they allow us to
sequence effects in a structured way and are in many ways a super-power
in the functional-programming toolkit. It's likely none of us would have
even heard of Haskell without them.</p>
<p>It's my opinion, though, that monads are actually <em>too</em>
powerful for their own good. Or to be more clear, monads are more
<strong>expressive</strong> than they need to be, and that we're paying
hidden costs to gain expressive power that we rarely, if ever, actually
use.</p>
<p>In this post we'll take a look at how different approaches to effects
lie on the spectrum between expressiveness and strong static analysis,
and how, just like Dynamic vs Statically typed programming languages,
there's a benefit to limiting the number of programs you can write by
adding more structure and constraints to your effects system.</p>
<h2 id="the-status-quo">The Status Quo</h2>
<p>A defining feature of the Monadic interface is that it allows the
dynamic selection of effects based on <strong>the results of previous
effects</strong>.</p>
<p>This is a huge boon, and is what allowed the construction of
<em>real</em> programs in Haskell without compromising on its goals of
purity and laziness. This ability is what allows us to express normal
programming workflows like fetching input from a user before deciding
which command to run next, or fetching IDs from the database and then
resolving those IDs with subsequent database calls. This form of choice
is necessary for writing most moderately complex programs.</p>
<p>Alas, as it turns out, this expressiveness isn't free! It exists on a
spectrum. As anyone who's maintained any relatively complex JavaScript
or Python codebase can tell you, the <em>ability</em> to do anything at
any time comes at a cost of readability, perhaps more relevant to the
current discussion, at the cost of static analysis.</p>
<p>Allow me to present, in all its glory, the Expressiveness
Spectrum:</p>
<pre><code>Strong Static Analysis &lt;+---------+---------+&gt; Embarrassingly Expressive Code</code></pre>
<p>As you can clearly see, as you gain more expressive power you begin
to lose the ability to know what the heck your program could possibly do
when it runs.</p>
<p>This has fueled a good many debates among programming language
connoisseurs, and it turns out that there's a similar version of the
debate to be had within the realm of effect systems themselves.</p>
<p>In their essence, effect systems are just methods of expressing
miniature programs <strong>within</strong> your programming language of
choice. These mini programs can be constructed, analysed, and executed
at runtime within the framework of the larger programming language, and
the same Expressiveness Spectrum applies independently to them as well.
That is, the more programs you allow your effect system to express, the
less you can know about any individual program before you run it.</p>
<p>In the effect-system microcosm there are similar mini <em>compile
time</em> and <em>run time</em> stages. As an example here's a simple
Haskell program which constructs a chain of effects using a DSL:</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="co">-- The common way to express effects in Haskell </span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- is with a Monadic typeclass interface.</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Monad</span> m <span class="ot">=&gt;</span> <span class="dt">ReadWrite</span> m <span class="kw">where</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="ot">  readLine ::</span> m <span class="dt">String</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="ot">  writeLine ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> m ()</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a><span class="co">-- We can write a little program builder which depends on </span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a><span class="co">-- input that may only be known at runtime.</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a><span class="ot">greetUser ::</span> <span class="dt">ReadWrite</span> m <span class="ot">=&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> m () </span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>greetUser greeting <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a>  writeLine (greeting <span class="op">&lt;&gt;</span> <span class="st">&quot;, what is your name?&quot;</span>)</span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a>  name <span class="ot">&lt;-</span> readLine</span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a>  writeLine (<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>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-15"><a href="#cb2-15" aria-hidden="true" tabindex="-1"></a><span class="co">-- We can, at run time, construct a new mini-program </span></span>
<span id="cb2-16"><a href="#cb2-16" aria-hidden="true" tabindex="-1"></a><span class="co">-- that the world has never seen before!</span></span>
<span id="cb2-17"><a href="#cb2-17" aria-hidden="true" tabindex="-1"></a><span class="ot">mkSimpleGreeting ::</span> <span class="dt">ReadWrite</span> m <span class="ot">=&gt;</span> <span class="dt">IO</span> (m ())</span>
<span id="cb2-18"><a href="#cb2-18" aria-hidden="true" tabindex="-1"></a>mkSimpleGreeting <span class="ot">=</span> <span class="kw">do</span> </span>
<span id="cb2-19"><a href="#cb2-19" aria-hidden="true" tabindex="-1"></a>  greeting <span class="ot">&lt;-</span> <span class="fu">readFile</span> <span class="st">&quot;greeting.txt&quot;</span></span>
<span id="cb2-20"><a href="#cb2-20" aria-hidden="true" tabindex="-1"></a>  <span class="fu">pure</span> (greetUser greeting)</span></code></pre></div>
<p>In this simplified example we clearly see that we can use our host
languages features arbitrarily to construct a smaller program within our
ReadWrite DSL. Our simple program here just reads a line of input from
the user and then greets them by name.</p>
<p>This is all well and good in such a simple case, however if we expand
our simple <code>ReadWrite</code> effect slightly by adding a new
effect:</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">Monad</span> m <span class="ot">=&gt;</span> <span class="dt">ReadWriteDelete</span> m <span class="kw">where</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="ot">  readLine ::</span> m <span class="dt">String</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="ot">  writeLine ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> m ()</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="ot">  deleteMyHardDrive ::</span> m ()</span></code></pre></div>
<p>Well now, if we're constructing or parsing programs of the
<code>ReadWriteDelete</code> effect type at runtime, we probably want to
be able to <em>know</em> whether or not the program we're about to run
contains a call to <code>deleteMyHardDrive</code> <em>before</em> we
actually run it.</p>
<p>We could of course simply abort execution or ignore requests to
delete everything when we're running the effects in our host language,
which is nice, but the fact remains that if our app is handed an
arbitrary <code>ReadWriteDelete m =&gt; m ()</code> program at runtime,
there's <em>no</em> way to know whether or not it could possibly contain
a call to <code>deleteMyHardDrive</code> without actually running the
program, and even then, there's no way to know whether there's some
<strong>other</strong> possible execution path that we missed which
<em>does</em> call <code>deleteMyHardDrive</code>.</p>
<p>We'd really love to be able to <em>analyse</em> the program and all
of its possible effects <em>before</em> we run anything at all.</p>
<h2 id="the-benefits-of-static-analysis">The Benefits of Static
Analysis</h2>
<p>Most programmers are familiar with the benefits of static analysis
when applied to regular everyday programming languages. It can catch
basic errors like type-mismatches, incorrect function calls, and in some
cases things like memory unsafety or race conditions.</p>
<p>We're typically after different kinds of benefits when analysing
programs in our effect systems, but they are similarly useful!</p>
<p>For instance, given enough understanding of an effectful program we
can perform code transformations like removing redundant calls,
parallelizing independent workflows, caching results, and optimizing
workflows into more efficient ones.</p>
<p>We can also gain useful knowledge, like creating a call graph for
developers to better understand what's about to happen. Or perhaps
analyzing the use of sensitive resources like the file system or network
such that we can ask for approval before even beginning execution.</p>
<p>But as I've already mentioned, we can't do <em>most</em> of these
techniques in a Monadic effect system. The monad interface itself makes
it clear why this is the case:</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="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-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="ot">  return ::</span> a <span class="ot">-&gt;</span> m a</span></code></pre></div>
<p>We can see from <code>Bind</code> (<code>&gt;&gt;=</code>) that in
order to know which effects (<code>m b</code>) will be executed next, we
need to first execute the previous effect (<code>m a</code>) and then we
need the host language (Haskell) to execute an arbitrary Haskell
function. There's no way at all for us to gain insight about what the
results of that function might be without running it first.</p>
<p>Let's move a step towards the analysis side of the spectrum and talk
about Applicatives...</p>
<h2 id="the-origin-of-applicatives">The origin of Applicatives</h2>
<p>Applicatives are another interface for expressing effectful
operations.</p>
<p>As far as I can determine, the first widespread introduction of
Applicatives to programming was in <a
href="https://www.staff.city.ac.uk/~ross/papers/Applicative.pdf">Applicative
Programming with Effects</a>, a 2008 paper by Conor McBride and Ross
Paterson.</p>
<p>Take note that this paper was written <em>after</em> Monads were
already in widespread use, and Applicatives are, by their very
definition, <strong>less expressive</strong> than Monads. To be precise,
Applicatives can express <em>fewer effectful programs</em> than Monads
can. This is shown by the fact that every <strong>Monad</strong>
implements the <strong>Applicative</strong> interface, but not every
<strong>Applicative</strong> is a Monad.</p>
<p>Despite being <em>less expressive</em> Applicatives are still very
useful. They allow us to express programs with effects that aren't valid
monads, but they also provide us with the ability to better analyse
which effects are part of an effectful program before running it.</p>
<p>Take a look at the Applicative interface:</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="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="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="ot">  pure ::</span> a <span class="ot">-&gt;</span> f a</span>
<span id="cb5-3"><a href="#cb5-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>Notice how the interface <em>does</em> contain an arrow
<code>f (a -&gt; b)</code>, but this arrow can only affect the
<em>pure</em> aspect of the computation. Unlike monadic bind, there's no
way to use the <code>a</code> result from running effects to select or
build new effects to run.</p>
<p>The sequence of effects is determined entirely by the host language
before we start to run the effects, and thus the sequence of effects can
be reliably inspected in advance.</p>
<p>This <em>limitation</em>, if you can even call it that, gives us a
ton of utility in program analysis. For any given sequence of
Applicative Effects we can analyse it and produce a list of all the
planned effects before running any of them, then could ask the end-user
for permission before running potentially harmful effects.</p>
<p>Let's see what this looks like for our ReadWrite effect.</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="kw">import</span> <span class="dt">Control.Applicative</span> (liftA3)</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Monad.Writer</span> (<span class="dt">Writer</span>, runWriter, tell)</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="co">-- | We only require the Applicative interface now</span></span>
<span id="cb6-5"><a href="#cb6-5" 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">ReadWrite</span> m <span class="kw">where</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a><span class="ot">  readLine ::</span> m <span class="dt">String</span></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a><span class="ot">  writeLine ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> m ()</span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Command</span></span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a>  <span class="ot">=</span> <span class="dt">ReadLine</span></span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">WriteLine</span> <span class="dt">String</span></span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Show</span>)</span>
<span id="cb6-13"><a href="#cb6-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-14"><a href="#cb6-14" aria-hidden="true" tabindex="-1"></a><span class="co">-- | We can implement an instance which runs a dummy interpreter that simply records the commands</span></span>
<span id="cb6-15"><a href="#cb6-15" aria-hidden="true" tabindex="-1"></a><span class="co">-- the program wants to run, without actually executing anything for real.</span></span>
<span id="cb6-16"><a href="#cb6-16" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">ReadWrite</span> (<span class="dt">Writer</span> [<span class="dt">Command</span>]) <span class="kw">where</span></span>
<span id="cb6-17"><a href="#cb6-17" aria-hidden="true" tabindex="-1"></a>  readLine <span class="ot">=</span> tell [<span class="dt">ReadLine</span>] <span class="op">*&gt;</span> <span class="fu">pure</span> <span class="st">&quot;Simulated User Input&quot;</span></span>
<span id="cb6-18"><a href="#cb6-18" aria-hidden="true" tabindex="-1"></a>  writeLine msg <span class="ot">=</span> tell [<span class="dt">WriteLine</span> msg]</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 class="co">-- | A helper to run our program and get the list of commands it would execute</span></span>
<span id="cb6-21"><a href="#cb6-21" aria-hidden="true" tabindex="-1"></a><span class="ot">recordCommands ::</span> <span class="dt">Writer</span> [<span class="dt">Command</span>] <span class="dt">String</span> <span class="ot">-&gt;</span> [<span class="dt">Command</span>]</span>
<span id="cb6-22"><a href="#cb6-22" aria-hidden="true" tabindex="-1"></a>recordCommands w <span class="ot">=</span> <span class="fu">snd</span> (runWriter w)</span>
<span id="cb6-23"><a href="#cb6-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-24"><a href="#cb6-24" aria-hidden="true" tabindex="-1"></a><span class="co">-- | A simple program that greets the user.</span></span>
<span id="cb6-25"><a href="#cb6-25" aria-hidden="true" tabindex="-1"></a><span class="ot">myProgram ::</span> (<span class="dt">ReadWrite</span> m) <span class="ot">=&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> m <span class="dt">String</span></span>
<span id="cb6-26"><a href="#cb6-26" aria-hidden="true" tabindex="-1"></a>myProgram greeting <span class="ot">=</span></span>
<span id="cb6-27"><a href="#cb6-27" aria-hidden="true" tabindex="-1"></a>  liftA3</span>
<span id="cb6-28"><a href="#cb6-28" aria-hidden="true" tabindex="-1"></a>    (\_ name _ <span class="ot">-&gt;</span> name)</span>
<span id="cb6-29"><a href="#cb6-29" aria-hidden="true" tabindex="-1"></a>    (writeLine (greeting <span class="op">&lt;&gt;</span> <span class="st">&quot;, what is your name?&quot;</span>))</span>
<span id="cb6-30"><a href="#cb6-30" aria-hidden="true" tabindex="-1"></a>    readLine</span>
<span id="cb6-31"><a href="#cb6-31" aria-hidden="true" tabindex="-1"></a>    (writeLine <span class="st">&quot;Welcome!&quot;</span>)</span>
<span id="cb6-32"><a href="#cb6-32" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-33"><a href="#cb6-33" aria-hidden="true" tabindex="-1"></a><span class="co">-- We can now run our program in the Writer applicative to see what it would do!</span></span>
<span id="cb6-34"><a href="#cb6-34" aria-hidden="true" tabindex="-1"></a><span class="ot">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb6-35"><a href="#cb6-35" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb6-36"><a href="#cb6-36" aria-hidden="true" tabindex="-1"></a>  <span class="kw">let</span> commands <span class="ot">=</span> recordCommands (myProgram <span class="st">&quot;Hello&quot;</span>)</span>
<span id="cb6-37"><a href="#cb6-37" aria-hidden="true" tabindex="-1"></a>  <span class="fu">print</span> commands</span>
<span id="cb6-38"><a href="#cb6-38" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-39"><a href="#cb6-39" aria-hidden="true" tabindex="-1"></a><span class="co">-- [WriteLine &quot;Hello, what is your name?&quot;,ReadLine,WriteLine &quot;Welcome!&quot;]</span></span></code></pre></div>
<p>Since this interface doesn't provide us with a <code>bind</code>, we
can't use results from <code>readLine</code> in a future
<code>writeLine</code> effect, which is a bummer. It's clear that
Applicatives are less <strong>expressive</strong> in this way, but we
<em>can</em> run an analysis of a program written in the Applicative
<code>ReadWrite</code> to see <strong>exactly</strong> which effects it
will run, and which arguments each of them are provided with, before we
execute anything for real.</p>
<p>I hope that's enough ink to convince you that it's not a simple
matter of "more expressive is always better", but rather that
expressiveness exists on a continuum between ease of program analysis
and expressiveness.</p>
<p>Expressive power comes at a cost, specifically the cost of
analysis.</p>
<h2 id="closer-to-the-sweet-spot">Closer to the Sweet Spot</h2>
<p>So clearly Applicatives are nice, but they're a pretty strong
limitation and prevent us from writing a lot of useful programs. What if
there was an interface somewhere on the spectrum between the two?</p>
<p><strong>Selective Applicatives</strong> fit nicely between
Applicatives and Monads.</p>
<p>If you haven't heard of them, this isn't a tutorial on Selective
itself, so go read up on them <a
href="https://hackage.haskell.org/package/selective">here</a> if you
like.</p>
<p>The interface for Selective Applicatives is similar to Applicatives,
but they allow us to specify a known set of branching codepaths that our
program <em>may</em> choose between when executing. Unlike the monadic
interface, these branching paths need to be known and enumerated in
advance, we can't make them up on the fly while running our effects.</p>
<p>This interface gets us <em>much</em> closer to matching the level of
expressiveness we actually need for everyday programming while still
granting us most of the best benefits of program analysis.</p>
<p>Here's an example of what it looks like to analyse a
<code>ReadWriteDelete</code> program using Selective Applicatives:</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="kw">import</span> <span class="dt">Control.Monad.Writer</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Selective</span> <span class="kw">as</span> <span class="dt">Selective</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Either</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Functor</span> ((&lt;&amp;&gt;))</span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a><span class="co">-- We require the Selective interface now</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> (<span class="dt">Selective</span> m) <span class="ot">=&gt;</span> <span class="dt">ReadWriteDelete</span> m <span class="kw">where</span></span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a><span class="ot">  readLine ::</span> m <span class="dt">String</span></span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a><span class="ot">  writeLine ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> m ()</span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a><span class="ot">  deleteMyHardDrive ::</span> m ()</span>
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Command</span></span>
<span id="cb7-13"><a href="#cb7-13" aria-hidden="true" tabindex="-1"></a>  <span class="ot">=</span> <span class="dt">ReadLine</span></span>
<span id="cb7-14"><a href="#cb7-14" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">WriteLine</span> <span class="dt">String</span></span>
<span id="cb7-15"><a href="#cb7-15" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">DeleteMyHardDrive</span></span>
<span id="cb7-16"><a href="#cb7-16" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Show</span>)</span>
<span id="cb7-17"><a href="#cb7-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-18"><a href="#cb7-18" aria-hidden="true" tabindex="-1"></a><span class="co">-- | &quot;Under&quot; is a helper for collecting the </span></span>
<span id="cb7-19"><a href="#cb7-19" aria-hidden="true" tabindex="-1"></a><span class="co">-- *minimum* set of effects we might run.</span></span>
<span id="cb7-20"><a href="#cb7-20" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">ReadWriteDelete</span> (<span class="dt">Under</span> [<span class="dt">Command</span>]) <span class="kw">where</span></span>
<span id="cb7-21"><a href="#cb7-21" aria-hidden="true" tabindex="-1"></a>  readLine <span class="ot">=</span> <span class="dt">Under</span> [<span class="dt">ReadLine</span>]</span>
<span id="cb7-22"><a href="#cb7-22" aria-hidden="true" tabindex="-1"></a>  writeLine msg <span class="ot">=</span> <span class="dt">Under</span> [<span class="dt">WriteLine</span> msg]</span>
<span id="cb7-23"><a href="#cb7-23" aria-hidden="true" tabindex="-1"></a>  deleteMyHardDrive <span class="ot">=</span> <span class="dt">Under</span> [<span class="dt">DeleteMyHardDrive</span>]</span>
<span id="cb7-24"><a href="#cb7-24" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-25"><a href="#cb7-25" aria-hidden="true" tabindex="-1"></a><span class="co">-- | &quot;Over&quot; is a helper which collects *all* possible effects we might run.</span></span>
<span id="cb7-26"><a href="#cb7-26" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">ReadWriteDelete</span> (<span class="dt">Over</span> [<span class="dt">Command</span>]) <span class="kw">where</span></span>
<span id="cb7-27"><a href="#cb7-27" aria-hidden="true" tabindex="-1"></a>  readLine <span class="ot">=</span> <span class="dt">Over</span> [<span class="dt">ReadLine</span>]</span>
<span id="cb7-28"><a href="#cb7-28" aria-hidden="true" tabindex="-1"></a>  writeLine msg <span class="ot">=</span> <span class="dt">Over</span> [<span class="dt">WriteLine</span> msg]</span>
<span id="cb7-29"><a href="#cb7-29" aria-hidden="true" tabindex="-1"></a>  deleteMyHardDrive <span class="ot">=</span> <span class="dt">Over</span> [<span class="dt">DeleteMyHardDrive</span>]</span>
<span id="cb7-30"><a href="#cb7-30" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-31"><a href="#cb7-31" aria-hidden="true" tabindex="-1"></a><span class="co">-- | A &quot;real&quot; IO instance</span></span>
<span id="cb7-32"><a href="#cb7-32" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">ReadWriteDelete</span> <span class="dt">IO</span> <span class="kw">where</span></span>
<span id="cb7-33"><a href="#cb7-33" aria-hidden="true" tabindex="-1"></a>  readLine <span class="ot">=</span> <span class="fu">getLine</span></span>
<span id="cb7-34"><a href="#cb7-34" aria-hidden="true" tabindex="-1"></a>  writeLine msg <span class="ot">=</span> <span class="fu">putStrLn</span> msg</span>
<span id="cb7-35"><a href="#cb7-35" aria-hidden="true" tabindex="-1"></a>  deleteMyHardDrive <span class="ot">=</span> <span class="fu">putStrLn</span> <span class="st">&quot;Deleting hard drive... Just kidding!&quot;</span></span>
<span id="cb7-36"><a href="#cb7-36" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-37"><a href="#cb7-37" aria-hidden="true" tabindex="-1"></a><span class="co">-- | A program using Selective effects</span></span>
<span id="cb7-38"><a href="#cb7-38" aria-hidden="true" tabindex="-1"></a><span class="ot">myProgram ::</span> (<span class="dt">ReadWriteDelete</span> m) <span class="ot">=&gt;</span> m <span class="dt">String</span></span>
<span id="cb7-39"><a href="#cb7-39" aria-hidden="true" tabindex="-1"></a>myProgram <span class="ot">=</span></span>
<span id="cb7-40"><a href="#cb7-40" aria-hidden="true" tabindex="-1"></a>  <span class="kw">let</span> msgKind <span class="ot">=</span></span>
<span id="cb7-41"><a href="#cb7-41" aria-hidden="true" tabindex="-1"></a>        Selective.matchS</span>
<span id="cb7-42"><a href="#cb7-42" aria-hidden="true" tabindex="-1"></a>          <span class="co">-- The list of values our program has explicit branches for.</span></span>
<span id="cb7-43"><a href="#cb7-43" aria-hidden="true" tabindex="-1"></a>          <span class="co">-- These are the values which will be used to crawl codepaths when</span></span>
<span id="cb7-44"><a href="#cb7-44" aria-hidden="true" tabindex="-1"></a>          <span class="co">-- analysing your program using `Over`.</span></span>
<span id="cb7-45"><a href="#cb7-45" aria-hidden="true" tabindex="-1"></a>          (Selective.cases [<span class="st">&quot;friendly&quot;</span>, <span class="st">&quot;mean&quot;</span>])</span>
<span id="cb7-46"><a href="#cb7-46" aria-hidden="true" tabindex="-1"></a>          <span class="co">-- The action we run to get the input</span></span>
<span id="cb7-47"><a href="#cb7-47" aria-hidden="true" tabindex="-1"></a>          readLine</span>
<span id="cb7-48"><a href="#cb7-48" aria-hidden="true" tabindex="-1"></a>          <span class="co">-- What to do with each input</span></span>
<span id="cb7-49"><a href="#cb7-49" aria-hidden="true" tabindex="-1"></a>          ( \<span class="kw">case</span></span>
<span id="cb7-50"><a href="#cb7-50" aria-hidden="true" tabindex="-1"></a>              <span class="st">&quot;friendly&quot;</span> <span class="ot">-&gt;</span> writeLine (<span class="st">&quot;Hello! what is your name?&quot;</span>) <span class="op">*&gt;</span> readLine</span>
<span id="cb7-51"><a href="#cb7-51" aria-hidden="true" tabindex="-1"></a>              <span class="st">&quot;mean&quot;</span> <span class="ot">-&gt;</span> </span>
<span id="cb7-52"><a href="#cb7-52" aria-hidden="true" tabindex="-1"></a>                <span class="kw">let</span> msg <span class="ot">=</span> <span class="fu">unlines</span> [ <span class="st">&quot;Hey doofus, what do you want?&quot;</span></span>
<span id="cb7-53"><a href="#cb7-53" aria-hidden="true" tabindex="-1"></a>                                  , <span class="st">&quot;Too late. I deleted your hard-drive.&quot;</span></span>
<span id="cb7-54"><a href="#cb7-54" aria-hidden="true" tabindex="-1"></a>                                  , <span class="st">&quot;How do you feel about that?&quot;</span></span>
<span id="cb7-55"><a href="#cb7-55" aria-hidden="true" tabindex="-1"></a>                                  ]</span>
<span id="cb7-56"><a href="#cb7-56" aria-hidden="true" tabindex="-1"></a>                 <span class="kw">in</span> writeLine msg <span class="op">*&gt;</span> deleteMyHardDrive <span class="op">*&gt;</span> readLine</span>
<span id="cb7-57"><a href="#cb7-57" aria-hidden="true" tabindex="-1"></a>              <span class="co">-- This can&#39;t actually happen.</span></span>
<span id="cb7-58"><a href="#cb7-58" aria-hidden="true" tabindex="-1"></a>              _ <span class="ot">-&gt;</span> <span class="fu">error</span> <span class="st">&quot;impossible&quot;</span></span>
<span id="cb7-59"><a href="#cb7-59" aria-hidden="true" tabindex="-1"></a>          )</span>
<span id="cb7-60"><a href="#cb7-60" aria-hidden="true" tabindex="-1"></a>      prompt <span class="ot">=</span> writeLine <span class="st">&quot;Select your mood: friendly or mean&quot;</span></span>
<span id="cb7-61"><a href="#cb7-61" aria-hidden="true" tabindex="-1"></a>      fallback <span class="ot">=</span></span>
<span id="cb7-62"><a href="#cb7-62" aria-hidden="true" tabindex="-1"></a>        (writeLine <span class="st">&quot;That was unexpected. You&#39;re an odd one aren&#39;t you?&quot;</span>)</span>
<span id="cb7-63"><a href="#cb7-63" aria-hidden="true" tabindex="-1"></a>          <span class="op">&lt;&amp;&gt;</span> \() actualInput <span class="ot">-&gt;</span> <span class="st">&quot;Got unknown input: &quot;</span> <span class="op">&lt;&gt;</span> actualInput</span>
<span id="cb7-64"><a href="#cb7-64" aria-hidden="true" tabindex="-1"></a>   <span class="kw">in</span> prompt</span>
<span id="cb7-65"><a href="#cb7-65" aria-hidden="true" tabindex="-1"></a>        <span class="op">*&gt;</span> Selective.branch</span>
<span id="cb7-66"><a href="#cb7-66" aria-hidden="true" tabindex="-1"></a>          msgKind</span>
<span id="cb7-67"><a href="#cb7-67" aria-hidden="true" tabindex="-1"></a>          fallback</span>
<span id="cb7-68"><a href="#cb7-68" aria-hidden="true" tabindex="-1"></a>          (<span class="fu">pure</span> <span class="fu">id</span>)</span>
<span id="cb7-69"><a href="#cb7-69" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-70"><a href="#cb7-70" aria-hidden="true" tabindex="-1"></a><span class="ot">allPossibleCommands ::</span> <span class="dt">Over</span> [<span class="dt">Command</span>] x <span class="ot">-&gt;</span> [<span class="dt">Command</span>]</span>
<span id="cb7-71"><a href="#cb7-71" aria-hidden="true" tabindex="-1"></a>allPossibleCommands (<span class="dt">Over</span> cmds) <span class="ot">=</span> cmds</span>
<span id="cb7-72"><a href="#cb7-72" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-73"><a href="#cb7-73" aria-hidden="true" tabindex="-1"></a><span class="ot">minimumPossibleCommands ::</span> <span class="dt">Under</span> [<span class="dt">Command</span>] x <span class="ot">-&gt;</span> [<span class="dt">Command</span>]</span>
<span id="cb7-74"><a href="#cb7-74" aria-hidden="true" tabindex="-1"></a>minimumPossibleCommands (<span class="dt">Under</span> cmds) <span class="ot">=</span> cmds</span>
<span id="cb7-75"><a href="#cb7-75" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-76"><a href="#cb7-76" aria-hidden="true" tabindex="-1"></a><span class="ot">runIO ::</span> <span class="dt">IO</span> <span class="dt">String</span></span>
<span id="cb7-77"><a href="#cb7-77" aria-hidden="true" tabindex="-1"></a>runIO <span class="ot">=</span> myProgram</span>
<span id="cb7-78"><a href="#cb7-78" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-79"><a href="#cb7-79" aria-hidden="true" tabindex="-1"></a><span class="co">-- | We can now run our program in the Writer applicative to see what it would do!</span></span>
<span id="cb7-80"><a href="#cb7-80" aria-hidden="true" tabindex="-1"></a><span class="ot">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb7-81"><a href="#cb7-81" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb7-82"><a href="#cb7-82" aria-hidden="true" tabindex="-1"></a>  <span class="kw">let</span> allCommands <span class="ot">=</span> allPossibleCommands myProgram</span>
<span id="cb7-83"><a href="#cb7-83" aria-hidden="true" tabindex="-1"></a>  <span class="kw">let</span> minimumCommands <span class="ot">=</span> minimumPossibleCommands myProgram</span>
<span id="cb7-84"><a href="#cb7-84" aria-hidden="true" tabindex="-1"></a>  <span class="fu">putStrLn</span> <span class="st">&quot;All possible commands:&quot;</span></span>
<span id="cb7-85"><a href="#cb7-85" aria-hidden="true" tabindex="-1"></a>  <span class="fu">print</span> allCommands</span>
<span id="cb7-86"><a href="#cb7-86" aria-hidden="true" tabindex="-1"></a>  <span class="fu">putStrLn</span> <span class="st">&quot;Minimum possible commands:&quot;</span></span>
<span id="cb7-87"><a href="#cb7-87" aria-hidden="true" tabindex="-1"></a>  <span class="fu">print</span> minimumCommands</span>
<span id="cb7-88"><a href="#cb7-88" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-89"><a href="#cb7-89" aria-hidden="true" tabindex="-1"></a><span class="co">-- All possible commands:</span></span>
<span id="cb7-90"><a href="#cb7-90" aria-hidden="true" tabindex="-1"></a><span class="co">-- [ WriteLine &quot;Select your mood: friendly or mean&quot;</span></span>
<span id="cb7-91"><a href="#cb7-91" aria-hidden="true" tabindex="-1"></a><span class="co">-- , ReadLine</span></span>
<span id="cb7-92"><a href="#cb7-92" aria-hidden="true" tabindex="-1"></a><span class="co">-- , WriteLine &quot;Hey doofus, what do you want?\nToo late. I deleted your hard-drive.\nHow do you feel about that?&quot;</span></span>
<span id="cb7-93"><a href="#cb7-93" aria-hidden="true" tabindex="-1"></a><span class="co">-- , DeleteMyHardDrive</span></span>
<span id="cb7-94"><a href="#cb7-94" aria-hidden="true" tabindex="-1"></a><span class="co">-- , ReadLine</span></span>
<span id="cb7-95"><a href="#cb7-95" aria-hidden="true" tabindex="-1"></a><span class="co">-- , WriteLine &quot;Hello! what is your name?&quot;</span></span>
<span id="cb7-96"><a href="#cb7-96" aria-hidden="true" tabindex="-1"></a><span class="co">-- , ReadLine</span></span>
<span id="cb7-97"><a href="#cb7-97" aria-hidden="true" tabindex="-1"></a><span class="co">-- , WriteLine &quot;That was unexpected. You&#39;re an odd one aren&#39;t you?&quot;</span></span>
<span id="cb7-98"><a href="#cb7-98" aria-hidden="true" tabindex="-1"></a><span class="co">-- ]</span></span>
<span id="cb7-99"><a href="#cb7-99" aria-hidden="true" tabindex="-1"></a><span class="co">--</span></span>
<span id="cb7-100"><a href="#cb7-100" aria-hidden="true" tabindex="-1"></a><span class="co">-- Minimum possible commands:</span></span>
<span id="cb7-101"><a href="#cb7-101" aria-hidden="true" tabindex="-1"></a><span class="co">-- [ WriteLine &quot;Select your mood: friendly or mean&quot;</span></span>
<span id="cb7-102"><a href="#cb7-102" aria-hidden="true" tabindex="-1"></a><span class="co">-- , ReadLine</span></span>
<span id="cb7-103"><a href="#cb7-103" aria-hidden="true" tabindex="-1"></a><span class="co">-- ]</span></span></code></pre></div>
<p>Okay, so now you've read a program which uses the full power of
Selective applicative to <em>branch</em> based on the results of
previous effects.</p>
<p>We can branch on user input to select either a friendly or mean
greeting style, so it's clearly more expressive than the Applicative
version, but it's also pretty obvious that this is the clunkiest option
available. It's a bit tricky to write, and is also pretty tough to
read.</p>
<p>We can now <em>branch</em> on user input, but since we need to
pre-configure an explicit branch for every possible input we want to
handle, we can't even write a simple program which echos back whatever
the user types in, or even one that greets them by name. There are
clearly still some substantial limitations on which programs we can
express here.</p>
<p>However, let's look on the bright side for a bit, similar to our
approach with Applicatives we can analyse the commands our program may
run. This time however, we've got branching paths in our program.</p>
<p>The selective interface gives us two methods to analyse our
program:</p>
<ul>
<li>The <code>Under</code> newtype will let us collect the minimum
possible sequence of of effects that our program will run no matter what
inputs it receives.</li>
<li>The <code>Over</code> newtype instead collects the list of
<em>all</em> possible effects that our program could possibly encounter
if it were to run through all of its branching paths.</li>
</ul>
<p>This isn't as usful as receiving, say, a graph representing the
possible execution paths, but it does give us enough information to give
users a warning aobut what a program might possibly do, we can let them
know that hey, I don't know exactly what will cause it, but this program
has the ability to delete your hard-drive.</p>
<p>You can of course write additional Selective interfaces, or use the
Free Selective to re-write Selective computations in order to optimize
or memoize them as you wish just like you can with Applicatives.</p>
<p>It's clear at this point that Selectives are another good tool, but
the limitations are still too severe:</p>
<ul>
<li>We can't use results from previous effects in future effects.</li>
<li>We can't express things like loops or recursion which require
effects</li>
<li>Branching logic like case-statements are expressible, but very
cumbersome.</li>
<li>The syntax for writing programs using Selective Applicatives is a
bit rough, and there's no do-notation equivalent.</li>
</ul>
<h2 id="in-search-of-the-true-sweet-spot">In search of the true sweet
spot</h2>
<p>This isn't a solved problem yet, but don't worry, there are yet more
methods of sequencing effects to explore!</p>
<p>It may take me another 5 years to finally finish it, but at some
point we'll continue this journey and explore how we can sequence
effects using the hierarchy of Category classes instead. Perhaps you've
wondered why Arrows don't get more love, we'll dive into that too! We'll
seek to find a more tenable middle-ground on our Expressiveness
Spectrum, a place where we can analyze possible execution paths without
sacrificing the ability to write the programs we need.</p>
<p>I hope this blog post helps others to understand that while Monads
were a huge discovery to the benefit of functional programming, that we
should keep looking for abstractions which are a better fit for the
problems we generally face in day-to-day programming.</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>You should add debug views to your DB</title>
      <link href="https://chrispenner.ca/posts/views-for-debugging"/>
      <id>https://chrispenner.ca/posts/views-for-debugging</id>
      <updated>2025-08-13T00:00:00Z</updated>
      <summary>A nifty trick for debugging your tables easier.</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/window.jpg" alt="You should add debug views to your DB">
              <p>This one will be quick.</p>
<p>Imagine this, you get a report from your bug tracker:</p>
<blockquote>
<p>Sophie got an error when viewing the diff after her most recent push
to her contribution to the <code>@unison/cloud</code> project on Unison
Share</p>
</blockquote>
<p>(BTW, contributions are like pull requests, but for Unison code)</p>
<p>Okay, this is great, we have something to start with, let's go look
up that contribution and see if any of the data there is suspicious.</p>
<p>Uhhh, okay, I know the error is related to one of Sophie's
contributions, but how do I actually <strong>find it</strong>?</p>
<p>I know Sophie's username from the bug report, that helps, but I don't
know which project she was working on, or what the contribution ID is,
which branches are involved, etc. Okay no problem, our data is
relational, so I can dive in and figure it out with a query:</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode sql"><code class="sourceCode sql"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> <span class="kw">SELECT</span> </span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>  contribution.<span class="op">*</span> </span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">FROM</span> contributions <span class="kw">AS</span> contribution</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">JOIN</span> projects <span class="kw">AS</span> project </span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">ON</span> contribution.project_id <span class="op">=</span> project.<span class="kw">id</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">JOIN</span> users <span class="kw">AS</span> unison_user </span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">ON</span> project.owner <span class="op">=</span> unison_user.<span class="kw">id</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>  <span class="kw">JOIN</span> users <span class="kw">AS</span> contribution_author </span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>    <span class="kw">ON</span> contribution.author_id <span class="op">=</span> contribution_author.<span class="kw">id</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>  <span class="kw">JOIN</span> branches <span class="kw">AS</span> source_branch </span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>    <span class="kw">ON</span> contribution.source_branch <span class="op">=</span> source_branch.<span class="kw">id</span></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a>  <span class="kw">WHERE</span> contribution_author.username <span class="op">=</span> <span class="st">&#39;sophie&#39;</span></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a>    <span class="kw">AND</span> project.name <span class="op">=</span> <span class="st">&#39;cloud&#39;</span></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a>    <span class="kw">AND</span> unison_user.username <span class="op">=</span> <span class="st">&#39;unison&#39;</span></span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a>  <span class="kw">ORDER</span> <span class="kw">BY</span> source_branch.updated_at <span class="kw">DESC</span></span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a><span class="op">-</span>[ <span class="dt">RECORD</span> <span class="dv">1</span> ]<span class="co">--------+----------------------------------------------------</span></span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a><span class="kw">id</span>                   | C<span class="op">-</span><span class="dv">4567</span></span>
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a>project_id           | P<span class="op">-</span><span class="dv">9999</span></span>
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a>contribution_number  | <span class="dv">21</span></span>
<span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a>title                | Fix bug</span>
<span id="cb1-22"><a href="#cb1-22" aria-hidden="true" tabindex="-1"></a>description          | Prevent <span class="kw">the</span> app <span class="kw">from</span> deleting <span class="kw">the</span> User<span class="st">&#39;s hard drive</span></span>
<span id="cb1-23"><a href="#cb1-23" aria-hidden="true" tabindex="-1"></a><span class="st">status               | open</span></span>
<span id="cb1-24"><a href="#cb1-24" aria-hidden="true" tabindex="-1"></a><span class="st">source_branch        | B-1111</span></span>
<span id="cb1-25"><a href="#cb1-25" aria-hidden="true" tabindex="-1"></a><span class="st">target_branch        | B-2222</span></span>
<span id="cb1-26"><a href="#cb1-26" aria-hidden="true" tabindex="-1"></a><span class="st">created_at           | 2025-05-28 13:06:09.532103+00</span></span>
<span id="cb1-27"><a href="#cb1-27" aria-hidden="true" tabindex="-1"></a><span class="st">updated_at           | 2025-05-28 13:54:23.954913+00</span></span>
<span id="cb1-28"><a href="#cb1-28" aria-hidden="true" tabindex="-1"></a><span class="st">author_id            | U-1234</span></span></code></pre></div>
<p>It's not the worst query I've ever had to write out, but if you're
doing this a couple times a day on a couple different tables, writing
out the joins gets pretty old <strong>real fast</strong>. Especially so
if you're writing it in a CLI interface where's it's a royal pain to
edit the middle of a query.</p>
<p>Even after we get the data we get a very ID heavy view of what's
going on, what's the actual project name? What are the branch names?
Etc.</p>
<p>We can solve both of these problems by writing a bunch of joins
<strong>ONCE</strong> by creating a debugging view over the table we're
interested in. Something like this:</p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode sql"><code class="sourceCode sql"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">CREATE</span> <span class="kw">VIEW</span> debug_contributions <span class="kw">AS</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="kw">SELECT</span> </span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>  contribution.<span class="kw">id</span> <span class="kw">AS</span> contribution_id,</span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>  contribution.project_id,</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>  contribution.contribution_number,</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>  contribution.title,</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>  contribution.description,</span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>  contribution.status,</span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>  contribution.source_branch <span class="kw">as</span> source_branch_id,</span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>  source_branch.name <span class="kw">AS</span> source_branch_name,</span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a>  source_branch.updated_at <span class="kw">AS</span> source_branch_updated_at,</span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a>  contribution.target_branch <span class="kw">as</span> target_branch_id,</span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a>  target_branch.name <span class="kw">AS</span> target_branch_name,</span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a>  target_branch.updated_at <span class="kw">AS</span> target_branch_updated_at,</span>
<span id="cb2-15"><a href="#cb2-15" aria-hidden="true" tabindex="-1"></a>  contribution.created_at,</span>
<span id="cb2-16"><a href="#cb2-16" aria-hidden="true" tabindex="-1"></a>  contribution.updated_at,</span>
<span id="cb2-17"><a href="#cb2-17" aria-hidden="true" tabindex="-1"></a>  contribution.author_id,</span>
<span id="cb2-18"><a href="#cb2-18" aria-hidden="true" tabindex="-1"></a>  author.username <span class="kw">AS</span> author_username,</span>
<span id="cb2-19"><a href="#cb2-19" aria-hidden="true" tabindex="-1"></a>  author.display_name <span class="kw">AS</span> author_name,</span>
<span id="cb2-20"><a href="#cb2-20" aria-hidden="true" tabindex="-1"></a>  project.name <span class="kw">AS</span> project_name,</span>
<span id="cb2-21"><a href="#cb2-21" aria-hidden="true" tabindex="-1"></a>  <span class="st">&#39;@&#39;</span><span class="op">||</span> project_owner.username <span class="op">||</span> <span class="st">&#39;/&#39;</span> <span class="op">||</span> project.name <span class="kw">AS</span> project_shorthand,</span>
<span id="cb2-22"><a href="#cb2-22" aria-hidden="true" tabindex="-1"></a>  project.owner <span class="kw">AS</span> project_owner_id,</span>
<span id="cb2-23"><a href="#cb2-23" aria-hidden="true" tabindex="-1"></a>  project_owner.username <span class="kw">AS</span> project_owner_username</span>
<span id="cb2-24"><a href="#cb2-24" aria-hidden="true" tabindex="-1"></a><span class="kw">FROM</span> contributions <span class="kw">AS</span> contribution</span>
<span id="cb2-25"><a href="#cb2-25" aria-hidden="true" tabindex="-1"></a><span class="kw">JOIN</span> projects <span class="kw">AS</span> project <span class="kw">ON</span> contribution.project_id <span class="op">=</span> project.<span class="kw">id</span></span>
<span id="cb2-26"><a href="#cb2-26" aria-hidden="true" tabindex="-1"></a><span class="kw">JOIN</span> users <span class="kw">AS</span> author <span class="kw">ON</span> contribution.author_id <span class="op">=</span> author.<span class="kw">id</span></span>
<span id="cb2-27"><a href="#cb2-27" aria-hidden="true" tabindex="-1"></a><span class="kw">JOIN</span> users <span class="kw">AS</span> project_owner <span class="kw">ON</span> project.owner <span class="op">=</span> project_owner.<span class="kw">id</span></span>
<span id="cb2-28"><a href="#cb2-28" aria-hidden="true" tabindex="-1"></a><span class="kw">JOIN</span> branches <span class="kw">AS</span> source_branch <span class="kw">ON</span> contribution.source_branch <span class="op">=</span> source_branch.<span class="kw">id</span></span>
<span id="cb2-29"><a href="#cb2-29" aria-hidden="true" tabindex="-1"></a><span class="kw">JOIN</span> branches <span class="kw">AS</span> target_branch <span class="kw">ON</span> contribution.target_branch <span class="op">=</span> target_branch.<span class="kw">id</span>;</span></code></pre></div>
<p>Okay, that's a lot to write out at once, but we never need to write
that again. Now if we need to answer the same question we did above we
do:</p>
<div class="sourceCode" id="cb3"><pre
class="sourceCode sql"><code class="sourceCode sql"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">from</span> debug_contributions </span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">WHERE</span> author.username <span class="op">=</span> <span class="st">&#39;sophie&#39;</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">AND</span> project_shorthand <span class="op">=</span> <span class="st">&#39;@unison/cloud&#39;</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">ORDER</span> <span class="kw">BY</span> source_branch_updated_at <span class="kw">DESC</span>;</span></code></pre></div>
<p>Which is <em>considerably</em> easier on both my brain and my
fingers. I also get all the information I could possibly want in the
result!</p>
<p>You can craft one of these debug tables for whatever your needs are
for each and every table you work with, and since it's just a view, it's
trivial to update or delete, and doesn't take any space in the DB
itself.</p>
<p>Obviously querying over
<code>project_shorthand = '@unison/cloud'</code> isn't going to be able
to use an index, so isn't going to be the most performant query; but
these are one off queries, so it's not a concern (to me at least). If
you care about that sort of thing you can leave out the computed columns
so you won't have to worry about that.</p>
<p>Anyways, that's it, that's the whole trick. Go make some debugging
views and save your future self some time.</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Save memory and CPU with an interning cache</title>
      <link href="https://chrispenner.ca/posts/intern-cache"/>
      <id>https://chrispenner.ca/posts/intern-cache</id>
      <updated>2025-08-12T00:00:00Z</updated>
      <summary>Weak Caching for Strong Apps</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/filing-cabinet.jpg" alt="Save memory and CPU with an interning cache">
              <p>This post will introduce a simple caching strategy, with a small
twist, which depending on your app may help you not only improve
performance, but might also drastically reduce the memory residency of
your program.</p>
<p>I had originally written this post in 2022, but looks like I got busy
and failed to release it, so just pretend you're reading this in 2022,
okay? It was a simpler time.</p>
<p>In case you're wondering, we continued to optimize storage since and
modern UCM uses even less memory than back in 2022 😎.</p>
<p>Spoiler warning, with about 80 lines of code, I was able to reduce
both the memory residency and start-up times by a whopping ~95%! From
90s -&gt; 4s startup time, and from 2.73GB -&gt; 148MB. All of these
gains were realized by tweaking our app to enforce <em>sharing</em>
between identical objects in memory.</p>
<h2 id="case-study">Case Study</h2>
<p>I help build the <a href="https://www.unison-lang.org/">Unison
Language</a>. One unique thing about the language is that programmers
interact with the language through the Unison Codebase Manager (a.k.a.
<code>ucm</code>), which is an interactive shell. Some users have
started to amass larger codebases, and lately we've been noticing that
the memory usage of <code>ucm</code> was growing to unacceptable
levels.</p>
<p>Loading one specific codebase, which I'll use for testing throughout
this article, required <strong>2.73GB</strong> and took about <strong>90
seconds</strong> to load from SQLite. This is far larger and slower than
we'd like.</p>
<p>There are 2 important facets of how Unison stores code that will be
important to know as we go forward, and will help you understand whether
this technique might work for you.</p>
<ul>
<li><strong>Unison codebases are append-only, and codebase definitions
are referenced by a content-based hash.</strong></li>
</ul>
<p>A Unison codebase is a tree with many branches, each branch contains
many definitions and also has references its history. In Unison, once a
definition is added to the codebase it is immutable, this is similar to
how commits work in git; commits can be built upon, and branches can
change which commit they point to, but once a commit is created it
cannot be changed and is uniquely identified by its hash.</p>
<ul>
<li><strong>A given Unison codebase is likely to refer to subtrees of
code like libraries many times across different Unison branches. E.g.
most projects contain a reference to the <code>base</code>
library.</strong></li>
</ul>
<p>A Unison project can pull in the libraries it depends on by simply
mounting that dependency into its <code>lib</code> namespace. Doing so
is inexpensive because in effect we simply copy the hash which refers to
a given snapshot of the library, we don't need to make copies of any of
the underlying code. However, when loading the codebase into memory
<code>ucm</code> was hydrating each and every library reference into a
full in-memory representation of that code. No good!</p>
<h2 id="what-is-sharing-and-why-do-i-want-it">What is sharing and why do
I want it?</h2>
<p>Sharing is a very simple concept at its core: rather than having
multiple copies of the same identical object in memory, we should just
have one. It's dead simple if you say it like that, but there are many
ways we can end up with duplicates of values in memory. For example, if
I load the same codebase from SQLite several times then SQLite won't
know that the object I'm loading already exists in memory and will make
a whole new copy.</p>
<p>In a language where data is mutable by default you'll want to think
long and hard about whether sharing is sensible or even possible for
your use-case, but luckily for me, everything in Haskell is immutable by
default so there's absolutely no reason to make copies of identical
values.</p>
<p>There's an additional benefit to sharing beyond just saving memory:
equality checks may be optimized! Some Haskell types like
<code>ByteString</code>s include <a
href="https://hackage-content.haskell.org/package/bytestring-0.12.2.0/docs/src/Data.ByteString.Internal.Type.html#eq">an
optimization</a> in their <code>Eq</code> instance which short circuits
the whole check if the two values are pointer-equal. Typically testing
equality on string-like values is actually <em>most</em> expensive when
the two strings are actually equal since the check must examine every
single byte to see if any of them differ. By interning our values using
a cache we can reduce these checks become a single pointer equality
check rather than an expensive byte-by-byte check.</p>
<h2 id="implementation">Implementation</h2>
<p>One issue with caches like this is that they can grow to eventually
consume unbounded amounts of memory, we certainly don't want every value
we've ever cached to stay there forever. Haskell is a garbage collected
language, so naturally the ideal situation would be for a value to live
in the cache up until it is garbage collected, but how can we know
that?</p>
<p>GHC implements <a
href="https://hackage.haskell.org/package/base-4.21.0.0/docs/System-Mem-Weak.html#t:Weak">weak
pointers</a>! This nifty feature allows us to do two helpful things:</p>
<ol>
<li>We can attach a finalizer to the values we return from the cache,
such that values will automatically <strong>evict themselves</strong>
from the cache when they're no longer reachable.</li>
<li>Weak references don't prevent the value they're pointing to from
being garbage collected. This means that if a value is <em>only</em>
referenced by a weak pointer in a cache then it will still be garbage
collected.</li>
</ol>
<p>As a result, there's really no downside to this form of caching
except a very small amount of compute and memory used to maintain the
cache itself. Your mileage may vary, but as the numbers show, in our
case this cost was <strong>very much worth it</strong> when compared to
the gains.</p>
<p>Here's an implementation of a simple <em>Interning Cache</em>:</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">module</span> <span class="dt">InternCache</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>  ( <span class="dt">InternCache</span>,</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>    newInternCache,</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>    lookupCached,</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>    insertCached,</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>    intern,</span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>    hoist,</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="kw">where</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="kw">import</span> <span class="dt">Control.Monad.IO.Class</span> (<span class="dt">MonadIO</span> (..))</span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.HashMap.Strict</span> (<span class="dt">HashMap</span>)</span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.HashMap.Strict</span> <span class="kw">qualified</span> <span class="kw">as</span> <span class="dt">HashMap</span></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Hashable</span> (<span class="dt">Hashable</span>)</span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">System.Mem.Weak</span></span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">UnliftIO.STM</span></span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a><span class="co">-- | Parameterized by the monad in which it operates, the key type, </span></span>
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a><span class="co">-- and the value type.</span></span>
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">InternCache</span> m k v <span class="ot">=</span> <span class="dt">InternCache</span></span>
<span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a>  {<span class="ot"> lookupCached ::</span> k <span class="ot">-&gt;</span> m (<span class="dt">Maybe</span> v),</span>
<span id="cb1-22"><a href="#cb1-22" aria-hidden="true" tabindex="-1"></a><span class="ot">    insertCached ::</span> k <span class="ot">-&gt;</span> v <span class="ot">-&gt;</span> m ()</span>
<span id="cb1-23"><a href="#cb1-23" aria-hidden="true" tabindex="-1"></a>  }</span>
<span id="cb1-24"><a href="#cb1-24" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-25"><a href="#cb1-25" aria-hidden="true" tabindex="-1"></a><span class="co">-- | Creates an &#39;InternCache&#39; which uses weak references to only </span></span>
<span id="cb1-26"><a href="#cb1-26" aria-hidden="true" tabindex="-1"></a><span class="co">-- keep values in the cache for as long as they&#39;re reachable by </span></span>
<span id="cb1-27"><a href="#cb1-27" aria-hidden="true" tabindex="-1"></a><span class="co">-- something else in the app.</span></span>
<span id="cb1-28"><a href="#cb1-28" aria-hidden="true" tabindex="-1"></a><span class="co">--</span></span>
<span id="cb1-29"><a href="#cb1-29" aria-hidden="true" tabindex="-1"></a><span class="co">-- This means you don&#39;t need to worry about a value not being </span></span>
<span id="cb1-30"><a href="#cb1-30" aria-hidden="true" tabindex="-1"></a><span class="co">-- GC&#39;d because it&#39;s in the cache.</span></span>
<span id="cb1-31"><a href="#cb1-31" aria-hidden="true" tabindex="-1"></a><span class="ot">newInternCache ::</span> </span>
<span id="cb1-32"><a href="#cb1-32" aria-hidden="true" tabindex="-1"></a>  <span class="kw">forall</span> m k v<span class="op">.</span> (<span class="dt">MonadIO</span> m, <span class="dt">Hashable</span> k) </span>
<span id="cb1-33"><a href="#cb1-33" aria-hidden="true" tabindex="-1"></a>  <span class="ot">=&gt;</span> m (<span class="dt">InternCache</span> m k v)</span>
<span id="cb1-34"><a href="#cb1-34" aria-hidden="true" tabindex="-1"></a>newInternCache <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb1-35"><a href="#cb1-35" aria-hidden="true" tabindex="-1"></a>  var <span class="ot">&lt;-</span> newTVarIO <span class="fu">mempty</span></span>
<span id="cb1-36"><a href="#cb1-36" aria-hidden="true" tabindex="-1"></a>  <span class="fu">pure</span> <span class="op">$</span></span>
<span id="cb1-37"><a href="#cb1-37" aria-hidden="true" tabindex="-1"></a>    <span class="dt">InternCache</span></span>
<span id="cb1-38"><a href="#cb1-38" aria-hidden="true" tabindex="-1"></a>      { lookupCached <span class="ot">=</span> lookupCachedImpl var,</span>
<span id="cb1-39"><a href="#cb1-39" aria-hidden="true" tabindex="-1"></a>        insertCached <span class="ot">=</span> insertCachedImpl var</span>
<span id="cb1-40"><a href="#cb1-40" aria-hidden="true" tabindex="-1"></a>      }</span>
<span id="cb1-41"><a href="#cb1-41" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb1-42"><a href="#cb1-42" aria-hidden="true" tabindex="-1"></a><span class="ot">    lookupCachedImpl ::</span> <span class="dt">TVar</span> (<span class="dt">HashMap</span> k (<span class="dt">Weak</span> v)) <span class="ot">-&gt;</span> k <span class="ot">-&gt;</span> m (<span class="dt">Maybe</span> v)</span>
<span id="cb1-43"><a href="#cb1-43" aria-hidden="true" tabindex="-1"></a>    lookupCachedImpl var ch <span class="ot">=</span> liftIO <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb1-44"><a href="#cb1-44" aria-hidden="true" tabindex="-1"></a>      cache <span class="ot">&lt;-</span> readTVarIO var</span>
<span id="cb1-45"><a href="#cb1-45" aria-hidden="true" tabindex="-1"></a>      <span class="kw">case</span> HashMap.lookup ch cache <span class="kw">of</span></span>
<span id="cb1-46"><a href="#cb1-46" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Nothing</span> <span class="ot">-&gt;</span> <span class="fu">pure</span> <span class="dt">Nothing</span></span>
<span id="cb1-47"><a href="#cb1-47" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Just</span> weakRef <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb1-48"><a href="#cb1-48" aria-hidden="true" tabindex="-1"></a>          deRefWeak weakRef</span>
<span id="cb1-49"><a href="#cb1-49" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-50"><a href="#cb1-50" aria-hidden="true" tabindex="-1"></a><span class="ot">    insertCachedImpl ::</span> <span class="dt">TVar</span> (<span class="dt">HashMap</span> k (<span class="dt">Weak</span> v)) <span class="ot">-&gt;</span> k <span class="ot">-&gt;</span> v <span class="ot">-&gt;</span> m ()</span>
<span id="cb1-51"><a href="#cb1-51" aria-hidden="true" tabindex="-1"></a>    insertCachedImpl var k v <span class="ot">=</span> liftIO <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb1-52"><a href="#cb1-52" aria-hidden="true" tabindex="-1"></a>      wk <span class="ot">&lt;-</span> mkWeakPtr v (<span class="dt">Just</span> <span class="op">$</span> removeDeadVal var k)</span>
<span id="cb1-53"><a href="#cb1-53" aria-hidden="true" tabindex="-1"></a>      atomically <span class="op">$</span> modifyTVar&#39; var (HashMap.insert k wk)</span>
<span id="cb1-54"><a href="#cb1-54" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-55"><a href="#cb1-55" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- Use this as a finalizer to remove the key from the map </span></span>
<span id="cb1-56"><a href="#cb1-56" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- when its value gets GC&#39;d</span></span>
<span id="cb1-57"><a href="#cb1-57" aria-hidden="true" tabindex="-1"></a><span class="ot">    removeDeadVal ::</span> <span class="dt">TVar</span> (<span class="dt">HashMap</span> k (<span class="dt">Weak</span> v)) <span class="ot">-&gt;</span> k <span class="ot">-&gt;</span> <span class="dt">IO</span> ()</span>
<span id="cb1-58"><a href="#cb1-58" aria-hidden="true" tabindex="-1"></a>    removeDeadVal var k <span class="ot">=</span> liftIO <span class="kw">do</span></span>
<span id="cb1-59"><a href="#cb1-59" aria-hidden="true" tabindex="-1"></a>      atomically <span class="op">$</span> modifyTVar&#39; var (HashMap.delete k)</span>
<span id="cb1-60"><a href="#cb1-60" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-61"><a href="#cb1-61" aria-hidden="true" tabindex="-1"></a><span class="co">-- | Changing the monad in which the cache operates with a natural transformation.</span></span>
<span id="cb1-62"><a href="#cb1-62" aria-hidden="true" tabindex="-1"></a><span class="ot">hoist ::</span> (<span class="kw">forall</span> x<span class="op">.</span> m x <span class="ot">-&gt;</span> n x) <span class="ot">-&gt;</span> <span class="dt">InternCache</span> m k v <span class="ot">-&gt;</span> <span class="dt">InternCache</span> n k v</span>
<span id="cb1-63"><a href="#cb1-63" aria-hidden="true" tabindex="-1"></a>hoist f (<span class="dt">InternCache</span> lookup&#39; insert&#39;) <span class="ot">=</span></span>
<span id="cb1-64"><a href="#cb1-64" aria-hidden="true" tabindex="-1"></a>  <span class="dt">InternCache</span></span>
<span id="cb1-65"><a href="#cb1-65" aria-hidden="true" tabindex="-1"></a>    { lookupCached <span class="ot">=</span> f <span class="op">.</span> lookup&#39;,</span>
<span id="cb1-66"><a href="#cb1-66" aria-hidden="true" tabindex="-1"></a>      insertCached <span class="ot">=</span> \k v <span class="ot">-&gt;</span> f <span class="op">$</span> insert&#39; k v</span>
<span id="cb1-67"><a href="#cb1-67" aria-hidden="true" tabindex="-1"></a>    }</span></code></pre></div>
<p>Now you can create a cache for any values you like! You can maintain
a cache within the scope of a given chunk of code, or you can make a
global cache for your entire app using <code>unsafePerformIO</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="co">-- An in memory cache for interning hashes.</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- This allows us to avoid creating multiple in-memory instances of the same hash bytes;</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="co">-- but also has the benefit that equality checks for equal hashes are O(1) instead of O(n), since</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="co">-- they&#39;ll be pointer-equal.</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="ot">hashCache ::</span> (<span class="dt">MonadIO</span> m) <span class="ot">=&gt;</span> <span class="dt">InternCache</span> m <span class="dt">Hash</span> <span class="dt">Hash</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>hashCache <span class="ot">=</span> unsafePerformIO <span class="op">$</span> hoist liftIO <span class="op">&lt;$&gt;</span> IC.newInternCache <span class="op">@</span><span class="dt">IO</span> <span class="op">@</span><span class="dt">Hash</span> <span class="op">@</span><span class="dt">Hash</span> </span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# NOINLINE hashCache #-}</span></span></code></pre></div>
<p>And here's an example of what it looks like to use the cache in
practice:</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">expectHash ::</span> <span class="dt">HashId</span> <span class="ot">-&gt;</span> <span class="dt">Transaction</span> <span class="dt">Hash</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>expectHash h <span class="ot">=</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- See if we&#39;ve got the value in the cache</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>  lookupCached hashCache h <span class="op">&gt;&gt;=</span> \<span class="kw">case</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Just</span> hash <span class="ot">-&gt;</span> <span class="fu">pure</span> hash</span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Nothing</span> <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>      hash <span class="ot">&lt;-</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>        queryOneCol</span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a>          [sql|</span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a>              SELECT base32</span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a>              FROM hash</span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a>              WHERE id = :h</span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a>            |]</span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a>      <span class="co">-- Since we didn&#39;t have it in the cache, add it now</span></span>
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true" tabindex="-1"></a>      insertCached hashCache h hash</span>
<span id="cb3-16"><a href="#cb3-16" aria-hidden="true" tabindex="-1"></a>      <span class="fu">pure</span> hash</span></code></pre></div>
<p>For things like Hashes, the memory savings are more modest, but in
the cases of entire subtrees of code the difference for us was
substantial. Not only did we save memory, but we saved a ton of time
re-hydrating subtrees of code from SQLite that we already had.</p>
<p>We can even get the benefits of a cache like this when we don't have
a separate key for the value, as long as the value itself has a
<code>Hashable</code> or <code>Ord</code> instance (if you swap the
InternCache to use a regular Map). We can use it as its own key, this
doesn't help us avoid the computational cost of <em>creating</em> the
value, but it still gives us the memory savings:</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="co">-- | When a value is its own key, this ensures that the given value </span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- is in the cache and always returns the single canonical in-memory </span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="co">-- instance of that value, garbage collecting any others.</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="ot">intern ::</span> (<span class="dt">Hashable</span> k, <span class="dt">Monad</span> m) <span class="ot">=&gt;</span> <span class="dt">InternCache</span> m k k <span class="ot">-&gt;</span> k <span class="ot">-&gt;</span> m k</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>intern cache k <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>  mVal <span class="ot">&lt;-</span> lookupCached cache k</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">case</span> mVal <span class="kw">of</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Just</span> v <span class="ot">-&gt;</span> <span class="fu">pure</span> v</span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Nothing</span> <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a>      insertCached cache k k</span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a>      <span class="fu">pure</span> k</span></code></pre></div>
<h2 id="conclusion">Conclusion</h2>
<p>An approach like this doesn't work for every app, it's much easier to
use when working with immutable values like this, but if there's a
situation in your app where it makes sense I recommend giving it a try!
I'll reiterate that for us, we dropped our codebase load times from 90s
down to 4s, and our resting memory usage from 2.73GB down to 148MB.</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Using traversals to batch database queries</title>
      <link href="https://chrispenner.ca/posts/traversals-for-batching"/>
      <id>https://chrispenner.ca/posts/traversals-for-batching</id>
      <updated>2025-08-11T00:00:00Z</updated>
      <summary>Techniques for lateralizing nested code</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/pipes.jpg" alt="Using traversals to batch database queries">
              <p>This article is about a code-transformation technique I used to get
100x-300x performance improvements on a particularly slow bit of code
which was loading Unison code from Postgres in Unison Share. I haven't
seen it documented anywhere else, so wanted to share the trick!</p>
<p>It's a perennial annoyance when I'm programming that often the most
readable way to write some code is also directly at odds with being
performant. A lot of data has a tree structure, and so working with this
data is usually most simply expressed as a series of nested function
calls. Nested function calls are a reasonable approach when executing
CPU-bound tasks, but in webapps we're often querying or fetching data
along the way. In a nested function structure we'll naturally end up
interleaving a lot of one-off data requests. In most cases these data
requests will block further execution until a round-trip to the database
fetches the data we need to proceed.</p>
<p>In Unison Share, I often need to hydrate an ID into an AST structure
which represents a chunk of code, and each reference in that code will
often contain some metadata or information of its own. We split off
large text blobs and external code references from the AST itself, so
sometimes these fetches will proceed in layers, e.g. fetch the AST, then
fetch the text literals referenced in the tree, then fetch the metadata
for code referenced by the tree, etc.</p>
<p>When hydrating a large batch of code definitions, if each definition
takes N database calls, loading M definitions is NxM database
round-trips, NxM query plans, and potentially NxM index or table scans!
If you make a call for each text ID or external reference individually,
then this scales even worse.</p>
<p>The technique in the post details a technique for using traversals to
iteratively evolve <strong>linear, nested</strong> codepaths into
similar functions which work on <strong>batches</strong> of data
instead. Critically, It allows keeping all the same codepaths which
allow you to keep the same nested code structure, avoiding the need to
restructure the whole codebase and allowing you to easily introduce
batching progressively without shipping a whole rewrite at once. It also
provides a trivial mechanism for <strong>deduplicating</strong> data
requests, and even allows using the exact same codepath for loading 0,
1, or many entities in a typesafe way. First a quick explanation of how
I ended up in this situation.</p>
<h2 id="case-study-unison-share-definition-loading">Case study: Unison
Share definition loading</h2>
<p>I'm in charge of the <a href="https://share.unison-lang.org/">Unison
Share</a> code-hosting and collaboration platform. The codebase for this
webapp started its life by collecting bits and pieces of code from the
UCM CLI application. UCM uses SQLite, so the first iteration was minimal
rewrite which simply replaced SQLite queries with the equivalent
Postgres queries, but the codepaths themselves were left largely the
same.</p>
<p>SQLite operates in-process and loads everything from memory or disk,
so for our intents and purposes in UCM it has essentially no latency. As
a result, most code for loading definitions from the user's codebase in
UCM was written simply and linearly, loading the data only as it is
needed. E.g. we may have a method
<code>loadText :: TextId -&gt; Sqlite.Transaction Text</code>, and when
we needed to load many text references it was perfectly reasonable to
just traverse <code>loadText</code> over a list of IDs.</p>
<p>However, not all databases have the same trade-offs! In the Unison
Share webapp we use Postgres, which means the database has a network
call and round-trip latency for each and every query. We now pay a fixed
round-trip latency cost on every query that simply wasn't a factor
before. Something simple like <code>traverse loadText textIds</code> is
now performing <strong>hundreds</strong> of <em>sequential</em> database
calls and individual text index lookups! Postgres doesn't know anything
about which query we'll run next, so it can't optimize this at all
(aside from warming up caches) That's clearly not good.</p>
<p>To optimize for Postgres we'd much prefer to make one large database
call which takes an array of a batch of <code>TextId</code>s and returns
all the <code>Text</code> results in a single query, this allows
Postgres to save a lot of work by finding all text values in a single
scan, and means we only incur a single round-trip delay rather than one
per text.</p>
<p>Here's a massively simplified sketch of what the original naive
linear code looked like:</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">loadTerm ::</span> <span class="dt">TermReference</span> <span class="ot">-&gt;</span> <span class="dt">Transaction</span> (<span class="dt">AST</span> <span class="dt">TermInfo</span> <span class="dt">Text</span>)</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>loadTerm ref <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>  ast <span class="ot">&lt;-</span> loadAST ref</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>  bitraverse loadTermInfo loadText ast</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">loadTermInfo ::</span> <span class="dt">TermReference</span> <span class="ot">-&gt;</span> <span class="dt">Transaction</span> <span class="dt">TermInfo</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>loadTermInfo ref <span class="ot">=</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>  queryOneRow [sql| SELECT name, type FROM terms WHERE ref = #{ref} |]</span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a><span class="ot">loadText ::</span> <span class="dt">TextId</span> <span class="ot">-&gt;</span> <span class="dt">Transaction</span> <span class="dt">Text</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>loadText textId <span class="ot">=</span></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a>  queryOneColumn [sql| SELECT text FROM texts WHERE id = #{textId} |]</span></code></pre></div>
<p>We really want to load all the Texts in a single query, but the
<code>TextIds</code> aren't just sitting in a nice list, they're nested
within the AST structure.</p>
<p>Here's some pseudocode for fetching a these as a batch:</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">batchLoadASTTexts ::</span> <span class="dt">AST</span> <span class="dt">TermReference</span> <span class="dt">TextId</span> <span class="ot">-&gt;</span> <span class="dt">Transaction</span> (<span class="dt">AST</span> <span class="dt">TermInfo</span> <span class="dt">Text</span>)</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>batchLoadASTTexts ast <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">let</span> textIds <span class="ot">=</span> <span class="dt">Foldable</span><span class="op">.</span>toList ast</span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>  texts <span class="ot">&lt;-</span> fetchTexts textIds</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>  for ast \textId <span class="ot">-&gt;</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">case</span> Map.lookup textId texts <span class="kw">of</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Nothing</span> <span class="ot">-&gt;</span> throwError <span class="op">$</span> <span class="dt">MissingText</span> textId</span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Just</span> text <span class="ot">-&gt;</span> <span class="fu">pure</span> text</span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a><span class="ot">    fetchTexts ::</span> [<span class="dt">TextId</span>] <span class="ot">-&gt;</span> <span class="dt">Transaction</span> (<span class="dt">Map</span> <span class="dt">TextId</span> <span class="dt">Text</span>)</span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a>    fetchTexts textIds <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a>      resolvedTexts <span class="ot">&lt;-</span> queryListColumns [sql|</span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a>        SELECT id, text FROM texts WHERE id = ANY(#{toArray textIds})</span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a>      |]</span>
<span id="cb2-15"><a href="#cb2-15" aria-hidden="true" tabindex="-1"></a>      <span class="fu">pure</span> <span class="op">$</span> Map.fromList resolvedTexts</span></code></pre></div>
<p>This solves the biggest problem, most importantly it reduces N
queries down to a single batch query which is already a huge
improvement! However, it is a bit of boilerplate, and we'd need to write
a custom version of this for each container we want to batch load texts
from.</p>
<p>Clever folks will realize that we actually don't care about the
<code>AST</code> structure at all, we only need a container which is
Traversable, so we can generalize over that:</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">batchLoadTexts ::</span> <span class="dt">Traversable</span> t <span class="ot">=&gt;</span> t <span class="dt">TextId</span> <span class="ot">-&gt;</span> <span class="dt">Transaction</span> (t <span class="dt">Text</span>)</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>batchLoadTexts textIds <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>  resolvedTexts <span class="ot">&lt;-</span> fetchTexts textIds</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>  <span class="fu">pure</span> <span class="op">$</span> <span class="fu">fmap</span> (\textId <span class="ot">-&gt;</span> <span class="kw">case</span> Map.lookup textId resolvedTexts <span class="kw">of</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Nothing</span> <span class="ot">-&gt;</span> throwError <span class="op">$</span> <span class="dt">MissingText</span> textId</span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Just</span> text <span class="ot">-&gt;</span> text) textIds</span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a><span class="ot">    fetchTexts ::</span> [<span class="dt">TextId</span>] <span class="ot">-&gt;</span> <span class="dt">Transaction</span> (<span class="dt">Map</span> <span class="dt">TextId</span> <span class="dt">Text</span>)</span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a>    fetchTexts textIds <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a>      resolvedTexts <span class="ot">&lt;-</span> queryListColumns [sql|</span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a>        SELECT id, text FROM texts WHERE id = ANY(#{toArray textIds})</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">pure</span> <span class="op">$</span> Map.fromList resolvedTexts</span></code></pre></div>
<p>This is much better, now we can use this on any form of Traversable,
meaning we can now batch load from ASTs, lists, vectors, Maps, and can
even just use <code>Identity</code> to re-use our query logic for a
single ID 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">loadText ::</span> <span class="dt">TextId</span> <span class="ot">-&gt;</span> <span class="dt">Transaction</span> <span class="dt">Text</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>loadText textId <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Identity</span> text <span class="ot">&lt;-</span> batchLoadTexts (<span class="dt">Identity</span> textId)</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>  <span class="fu">pure</span> text</span></code></pre></div>
<p>This approach does still require that the IDs you want to batch load
are the focus of some Traversable instance. What if instead your
structure contains a half-dozen different ID types, or is arranged such
that it's not in the Traversable slot of your type parameters?
Bitraversable can handle up to two parameters, but after that you're
back to writing bespoke functions for your container types.</p>
<p>For instance, how would we use this technique to batch load our
<code>TermInfo</code> from the AST's <code>TermReference</code>s?</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="co">-- Assume we&#39;ve written these batched term and termInfo loaders:</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="ot">batchLoadTexts ::</span> <span class="dt">Traversable</span> t <span class="ot">=&gt;</span> t <span class="dt">TextId</span> <span class="ot">-&gt;</span> <span class="dt">Transaction</span> (t <span class="dt">Text</span>)</span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="ot">batchLoadTermInfos ::</span> <span class="dt">Traversable</span> t <span class="ot">=&gt;</span> t <span class="dt">TermReference</span> <span class="ot">-&gt;</span> <span class="dt">Transaction</span> (t <span class="dt">TermInfo</span>)</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="ot">loadTerm ::</span> <span class="dt">TermReference</span> <span class="ot">-&gt;</span> <span class="dt">Transaction</span> (<span class="dt">AST</span> <span class="dt">TermInfo</span> <span class="dt">Text</span>)</span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a>loadTerm termRef <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>  ast <span class="ot">&lt;-</span> loadAST termRef</span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>  astWithText <span class="ot">&lt;-</span> batchLoadTexts ast</span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a>  <span class="op">???</span> astWithText <span class="co">-- How do we load the TermInfos in here?</span></span></code></pre></div>
<p>We're getting closer, but Traversable instances just aren't very
adaptable, the relevant ID must always be in the final parameter of the
type. In this case you could get by using <a
href="https://hackage.haskell.org/package/bifunctors-5.6.2/docs/Data-Bifunctor-Flip.html">Flip</a>
wrapper, but it's not going to be very readable and this technique
doesn't scale past two parameters.</p>
<p>We need some way to define and compose bespoke Traversable instances
for any given situation.</p>
<h2 id="custom-traversals">Custom Traversals</h2>
<p>In its essence, the Traversable type class is just a way to easily
provide a canonical implementation of <code>traverse</code> for a given
type:</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">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></code></pre></div>
<p>As it turns out, we don't need a type class in order to construct and
pass functions of this type around, we can define them ourselves.</p>
<p>With this signature it's still requiring that the elements being
traversed are the final type parameter of the container <code>t</code>;
we need a more general version. We can use this instead:</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="kw">type</span> <span class="dt">Traversal</span> s t a b <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> s <span class="ot">-&gt;</span> f t</span></code></pre></div>
<p>It looks very similar, but note that <code>s</code> and
<code>t</code> are now concrete types of kind <code>*</code>, they don't
take a parameter, which means we can pick any fully parameterized type
we like for <code>s</code> and <code>t</code> which focus some other
type <code>a</code> and convert or hydrate it into <code>b</code>.</p>
<p>E.g. If we want a traversal to focus the <code>TermReference</code>s
in an <code>AST</code> and convert them to <code>TermInfo</code>s, we
can write:</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="dt">Traversal</span> (<span class="dt">AST</span> <span class="dt">TermReference</span> text) (<span class="dt">AST</span> <span class="dt">TermInfo</span> text) <span class="dt">TermReference</span> <span class="dt">TermInfo</span></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="co">-- Which expands to the function type:</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Applicative</span> f <span class="ot">=&gt;</span> (<span class="dt">TermReference</span> <span class="ot">-&gt;</span> f <span class="dt">TermInfo</span>) <span class="ot">-&gt;</span> <span class="dt">AST</span> <span class="dt">TermReference</span> text <span class="ot">-&gt;</span> f (<span class="dt">AST</span> <span class="dt">TermInfo</span> text)</span></code></pre></div>
<p>If you've ever worked with optics or the <code>lens</code> library
before this should be looking mighty familiar, we've just derived
<code>lens</code>'s <a
href="https://hackage-content.haskell.org/package/lens-5.3.5/docs/Control-Lens-Combinators.html#t:Traversal"><code>Traversal</code></a>
type!</p>
<p>Most optics are essentially just traversals, we can write one-off
traversals for any situation we might need, and can trivially compose
small independent traversals together to create more complex
traversals.</p>
<p>Let's rewrite our batch loaders to take an explicit Traversal
argument.</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">import</span> <span class="dt">Control.Lens</span> <span class="kw">qualified</span> <span class="kw">as</span> <span class="dt">Lens</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Functor.Contravariant</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="co">-- Take a traversal, then a structure &#39;s&#39;, and replace all TextIds with Texts to</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a><span class="co">-- transform it into a &#39;t&#39;</span></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a><span class="ot">batchLoadTextsOf ::</span> <span class="dt">Lens.Traversal</span> s t <span class="dt">TextId</span> <span class="dt">Text</span> <span class="ot">-&gt;</span> s <span class="ot">-&gt;</span> <span class="dt">Transaction</span> t</span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a>batchLoadTextsOf traversal s <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a>  <span class="kw">let</span> textIds <span class="ot">=</span> toListOf (traversalToFold traversal) s</span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a>  resolvedTexts <span class="ot">&lt;-</span> fetchTexts textIds</span>
<span id="cb9-10"><a href="#cb9-10" aria-hidden="true" tabindex="-1"></a>  Lens.forOf traversal s <span class="op">$</span> \textId <span class="ot">-&gt;</span> <span class="kw">case</span> Map.lookup textId resolvedTexts <span class="kw">of</span></span>
<span id="cb9-11"><a href="#cb9-11" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Nothing</span> <span class="ot">-&gt;</span> throwError <span class="op">$</span> <span class="dt">MissingText</span> textId</span>
<span id="cb9-12"><a href="#cb9-12" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Just</span> text <span class="ot">-&gt;</span> <span class="fu">pure</span> text</span>
<span id="cb9-13"><a href="#cb9-13" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb9-14"><a href="#cb9-14" aria-hidden="true" tabindex="-1"></a><span class="ot">    fetchTexts ::</span> [<span class="dt">TextId</span>] <span class="ot">-&gt;</span> <span class="dt">Transaction</span> (<span class="dt">Map</span> <span class="dt">TextId</span> <span class="dt">Text</span>)</span>
<span id="cb9-15"><a href="#cb9-15" aria-hidden="true" tabindex="-1"></a>    fetchTexts textIds <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb9-16"><a href="#cb9-16" aria-hidden="true" tabindex="-1"></a>      resolvedTexts <span class="ot">&lt;-</span> queryListColumns [sql|</span>
<span id="cb9-17"><a href="#cb9-17" aria-hidden="true" tabindex="-1"></a>        SELECT id, text FROM texts WHERE id = ANY(#{toArray textIds})</span>
<span id="cb9-18"><a href="#cb9-18" aria-hidden="true" tabindex="-1"></a>      |]</span>
<span id="cb9-19"><a href="#cb9-19" aria-hidden="true" tabindex="-1"></a>      <span class="fu">pure</span> <span class="op">$</span> Map.fromList resolvedTexts</span>
<span id="cb9-20"><a href="#cb9-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-21"><a href="#cb9-21" aria-hidden="true" tabindex="-1"></a><span class="ot">traversalToFold ::</span></span>
<span id="cb9-22"><a href="#cb9-22" aria-hidden="true" tabindex="-1"></a>  (<span class="dt">Applicative</span> f, <span class="dt">Contravariant</span> f) <span class="ot">=&gt;</span></span>
<span id="cb9-23"><a href="#cb9-23" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Lens.Traversal</span> s t a b <span class="ot">-&gt;</span></span>
<span id="cb9-24"><a href="#cb9-24" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Lens.LensLike&#39;</span> f s a</span>
<span id="cb9-25"><a href="#cb9-25" aria-hidden="true" tabindex="-1"></a>traversalToFold traversal f s <span class="ot">=</span> phantom <span class="op">$</span> traversal (phantom <span class="op">.</span> f) s</span></code></pre></div>
<p>The <code>*Of</code> naming convention comes from the
<code>lens</code> library. A combinator ending in <code>Of</code> takes
an traversal as an argument.</p>
<p>It's a bit unfortunate that we need <code>traversalToFold</code>,
it's just a quirk of how Traversals and Folds are implemented in the
lens library, but don't worry we'll replace it with something better
soon.</p>
<p>Now we can pass any custom traversal we like into
<code>batchLoadTexts</code> and it will batch up the IDs and hydrate
them in-place.</p>
<p>Let's write the AST traversals we need:</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">astTexts ::</span> <span class="dt">Traversal</span> (<span class="dt">AST</span> <span class="dt">TermReference</span> <span class="dt">TextId</span>) (<span class="dt">AST</span> <span class="dt">TermReference</span> <span class="dt">Text</span>) <span class="dt">TextId</span> <span class="dt">Text</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>astTexts <span class="ot">=</span> <span class="fu">traverse</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="ot">astTermReferences ::</span> <span class="dt">Traversal</span> (<span class="dt">AST</span> <span class="dt">TermReference</span> <span class="dt">TextId</span>) (<span class="dt">AST</span> <span class="dt">TermInfo</span> <span class="dt">Text</span>) <span class="dt">TermReference</span> <span class="dt">TermInfo</span></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>astTermReferences f <span class="ot">=</span> bitraverse f <span class="fu">pure</span></span></code></pre></div>
<p>Here we can just piggy-back on existing <code>traverse</code> and
<code>bitraverse</code> implementations, but if you need to write your
own, I included a small guide on writing your own custom Traversals with
the <a
href="https://hackage-content.haskell.org/package/lens-5.3.5/docs/Control-Lens-Traversal.html#v:traversal">traversal</a>
method in the <code>lens</code> library, go check that out.</p>
<p>With this, we can now batch load both the texts and term infos from
an AST in one pass each.</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">loadTerm ::</span> <span class="dt">TermReference</span> <span class="ot">-&gt;</span> <span class="dt">Transaction</span> (<span class="dt">AST</span> <span class="dt">TermInfo</span> <span class="dt">Text</span>)</span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>loadTerm termRef <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>  ast <span class="ot">&lt;-</span> loadAST termRef</span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>  astWithText <span class="ot">&lt;-</span> batchLoadTextsOf astTexts ast</span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>  hydratedAST  <span class="ot">&lt;-</span> batchLoadTermInfosOf astTermReferences astWithText</span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>  <span class="fu">pure</span> hydratedAST</span></code></pre></div>
<h2 id="scaling-up">Scaling up</h2>
<p>Okay now we're cooking, we've reduced the number of queries per term
from <code>1 + numTexts + numTermRefs</code> down to a flat
<code>3</code> queries per term, which is a huge improvement, but
there's more to do.</p>
<p>What if we need to load a whole batch of asts at once? Here's a first
attempt:</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="co">-- Assume these batch loaders are in scope:</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a><span class="ot">batchLoadTermASTs ::</span> <span class="dt">Traversal</span> s t <span class="dt">TermReference</span> (<span class="dt">AST</span> <span class="dt">TermReference</span> <span class="dt">TextId</span>) <span class="ot">-&gt;</span> s <span class="ot">-&gt;</span> <span class="dt">Transaction</span> t</span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a><span class="ot">batchLoadTermInfos ::</span> <span class="dt">Traversal</span> s t <span class="dt">TermReference</span> <span class="dt">TermInfo</span> <span class="ot">-&gt;</span> s <span class="ot">-&gt;</span> <span class="dt">Transaction</span> t</span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a><span class="ot">batchLoadTexts ::</span> <span class="dt">Traversal</span> s t <span class="dt">TextId</span> <span class="dt">Text</span> <span class="ot">-&gt;</span> s <span class="ot">-&gt;</span> <span class="dt">Transaction</span> t</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="ot">batchLoadTerms ::</span> <span class="dt">Map</span> <span class="dt">TermReference</span> <span class="dt">TextId</span> <span class="ot">-&gt;</span> <span class="dt">Transaction</span> (<span class="dt">Map</span> <span class="dt">TermReference</span> (<span class="dt">AST</span> <span class="dt">TermInfo</span> <span class="dt">Text</span>))</span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a>batchLoadTerms termsMap <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a>  termASTsMap <span class="ot">&lt;-</span> batchLoadTermASTs <span class="fu">traverse</span> termsMap</span>
<span id="cb12-9"><a href="#cb12-9" aria-hidden="true" tabindex="-1"></a>  for termASTsMap \ast <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb12-10"><a href="#cb12-10" aria-hidden="true" tabindex="-1"></a>    astWithTexts <span class="ot">&lt;-</span> batchLoadTexts astTexts ast</span>
<span id="cb12-11"><a href="#cb12-11" aria-hidden="true" tabindex="-1"></a>    hydratedAST <span class="ot">&lt;-</span> batchLoadTermInfos astTermReferences astWithTexts</span>
<span id="cb12-12"><a href="#cb12-12" aria-hidden="true" tabindex="-1"></a>    <span class="fu">pure</span> hydratedAST</span></code></pre></div>
<p>This naive approach loads the asts in a batch, but then traverses
over the resulting ASTs batch loading the terms and texts: This is
better than no batching at all, but we're still running queries in a
loop. 2 queries for each term in the map is still <code>O(N)</code>
queries, we can do better.</p>
<p>Luckily, Traversals are easily composable! We can effectively
distribute the <code>for</code> loop into our batch calls by adding
composing an additional <code>traverse</code> so each traversal is
applied to every element of the outer map. In case you're not familiar
with optics, just note that traversals compose from outer to inner from
left to right, using <code>.</code>; it looks like this:</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">batchLoadTerms ::</span> <span class="dt">Map</span> <span class="dt">TermReference</span> <span class="dt">TextId</span> <span class="ot">-&gt;</span> <span class="dt">Transaction</span> (<span class="dt">Map</span> <span class="dt">TermReference</span> (<span class="dt">AST</span> <span class="dt">TermInfo</span> <span class="dt">Text</span>))</span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>batchLoadTerms termsMap <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a>  termASTsMap <span class="ot">&lt;-</span> batchLoadTermASTs <span class="fu">traverse</span> termsMap</span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>  astsMapWithTexts <span class="ot">&lt;-</span> batchLoadTexts (<span class="fu">traverse</span> <span class="op">.</span> astTexts) termASTsMap</span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a>  hydratedASTsMap <span class="ot">&lt;-</span> batchLoadTermInfos (<span class="fu">traverse</span> <span class="op">.</span> astTermReferences) astsMapWithTexts</span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a>  <span class="fu">pure</span> hydratedASTsMap</span></code></pre></div>
<p>If you want, you can even pipeline it like so:</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>  batchLoadTermASTs <span class="fu">traverse</span> termsMap</span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a>    <span class="op">&gt;&gt;=</span> batchLoadTexts (<span class="fu">traverse</span> <span class="op">.</span> astTexts)</span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a>    <span class="op">&gt;&gt;=</span> batchLoadTermInfos (traversed <span class="op">.</span> astTermReferences)</span></code></pre></div>
<p>It was a small change, but this performs <em>much</em> better at
scale, we went from <code>O(N)</code> queries to <code>O(1)</code>
queries, that is, we now run EXACTLY 3 queries, no matter how many terms
we're loading, pretty cool. In fact, the latter two queries have no
data-dependencies on each other, so you can also pipeline them if your
DB supports that, but I'll leave that as an exercise (or come ask me on
<a href="https://bsky.app/profile/chrispenner.ca">bluesky</a>).</p>
<p>That's basically the technique, the next section will show a few
tweaks which help me to use it at application scale.</p>
<h2 id="additional-tips">Additional tips</h2>
<p>Let's revisit the database layer where we actually make the batch
query:</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="kw">import</span> <span class="dt">Control.Lens</span> <span class="kw">qualified</span> <span class="kw">as</span> <span class="dt">Lens</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Functor.Contravariant</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="co">-- Take a traversal, then a structure &#39;s&#39;, and replace all TextIds with Texts to</span></span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a><span class="co">-- transform it into a &#39;t&#39;</span></span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a><span class="ot">batchLoadTextsOf ::</span> <span class="dt">Lens.Traversal</span> s t <span class="dt">TextId</span> <span class="dt">Text</span> <span class="ot">-&gt;</span> s <span class="ot">-&gt;</span> <span class="dt">Transaction</span> t</span>
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a>batchLoadTextsOf traversal s <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a>  <span class="kw">let</span> textIds <span class="ot">=</span> toListOf (traversalToFold traversal) s</span>
<span id="cb15-9"><a href="#cb15-9" aria-hidden="true" tabindex="-1"></a>  resolvedTexts <span class="ot">&lt;-</span> fetchTexts textIds</span>
<span id="cb15-10"><a href="#cb15-10" aria-hidden="true" tabindex="-1"></a>  Lens.forOf traversal s <span class="op">$</span> \textId <span class="ot">-&gt;</span> <span class="kw">case</span> Map.lookup textId resolvedTexts <span class="kw">of</span></span>
<span id="cb15-11"><a href="#cb15-11" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Nothing</span> <span class="ot">-&gt;</span> throwError <span class="op">$</span> <span class="dt">MissingText</span> textId</span>
<span id="cb15-12"><a href="#cb15-12" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Just</span> text <span class="ot">-&gt;</span> <span class="fu">pure</span> text</span>
<span id="cb15-13"><a href="#cb15-13" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb15-14"><a href="#cb15-14" aria-hidden="true" tabindex="-1"></a><span class="ot">    fetchTexts ::</span> [<span class="dt">TextId</span>] <span class="ot">-&gt;</span> <span class="dt">Transaction</span> (<span class="dt">Map</span> <span class="dt">TextId</span> <span class="dt">Text</span>)</span>
<span id="cb15-15"><a href="#cb15-15" aria-hidden="true" tabindex="-1"></a>    fetchTexts textIds <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb15-16"><a href="#cb15-16" aria-hidden="true" tabindex="-1"></a>      resolvedTexts <span class="ot">&lt;-</span> queryListColumns [sql|</span>
<span id="cb15-17"><a href="#cb15-17" aria-hidden="true" tabindex="-1"></a>        SELECT id, text FROM texts WHERE id = ANY(#{toArray textIds})</span>
<span id="cb15-18"><a href="#cb15-18" aria-hidden="true" tabindex="-1"></a>      |]</span>
<span id="cb15-19"><a href="#cb15-19" aria-hidden="true" tabindex="-1"></a>      <span class="fu">pure</span> <span class="op">$</span> Map.fromList resolvedTexts</span>
<span id="cb15-20"><a href="#cb15-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-21"><a href="#cb15-21" aria-hidden="true" tabindex="-1"></a><span class="ot">traversalToFold ::</span></span>
<span id="cb15-22"><a href="#cb15-22" aria-hidden="true" tabindex="-1"></a>  (<span class="dt">Applicative</span> f, <span class="dt">Contravariant</span> f) <span class="ot">=&gt;</span></span>
<span id="cb15-23"><a href="#cb15-23" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Lens.Traversal</span> s t a b <span class="ot">-&gt;</span></span>
<span id="cb15-24"><a href="#cb15-24" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Lens.LensLike&#39;</span> f s a</span>
<span id="cb15-25"><a href="#cb15-25" aria-hidden="true" tabindex="-1"></a>traversalToFold traversal f s <span class="ot">=</span> phantom <span class="op">$</span> traversal (phantom <span class="op">.</span> f) s</span></code></pre></div>
<p>This pattern is totally fine, but it does involve materializing and
sorting a Map of all the results, which also requires an Ord instance on
the database key we use. Here's an alternative approach:</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="kw">import</span> <span class="dt">Control.Lens</span> <span class="kw">qualified</span> <span class="kw">as</span> <span class="dt">Lens</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Functor.Contravariant</span></span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a><span class="co">-- Take a traversal, then a structure &#39;s&#39;, and replace all TextIds with Texts to</span></span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a><span class="co">-- transform it into a &#39;t&#39;</span></span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a><span class="ot">batchLoadTextsOf ::</span> <span class="dt">Lens.Traversal</span> s t <span class="dt">TextId</span> <span class="dt">Text</span> <span class="ot">-&gt;</span> s <span class="ot">-&gt;</span> <span class="dt">Transaction</span> t</span>
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a>batchLoadTextsOf traversal s <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb16-7"><a href="#cb16-7" aria-hidden="true" tabindex="-1"></a>  s <span class="op">&amp;</span> unsafePartsOf traversal <span class="op">%%~</span> \textIds <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb16-8"><a href="#cb16-8" aria-hidden="true" tabindex="-1"></a>      <span class="kw">let</span> orderedIds <span class="ot">=</span> <span class="fu">zip</span> [<span class="dv">0</span><span class="ot"> ::</span> <span class="dt">Int32</span> <span class="op">..</span>] textIds</span>
<span id="cb16-9"><a href="#cb16-9" aria-hidden="true" tabindex="-1"></a>      queryListColumns [sql|</span>
<span id="cb16-10"><a href="#cb16-10" aria-hidden="true" tabindex="-1"></a>        WITH text_ids(ord, id) AS (</span>
<span id="cb16-11"><a href="#cb16-11" aria-hidden="true" tabindex="-1"></a>          SELECT * unnest(#{toArray orderedIds}) AS ids(ord, id)</span>
<span id="cb16-12"><a href="#cb16-12" aria-hidden="true" tabindex="-1"></a>        )</span>
<span id="cb16-13"><a href="#cb16-13" aria-hidden="true" tabindex="-1"></a>        SELECT texts.text </span>
<span id="cb16-14"><a href="#cb16-14" aria-hidden="true" tabindex="-1"></a>          FROM texts JOIN text_ids ON texts.id = text_ids.id;</span>
<span id="cb16-15"><a href="#cb16-15" aria-hidden="true" tabindex="-1"></a>        ORDER BY text_ids.ord ASC</span>
<span id="cb16-16"><a href="#cb16-16" aria-hidden="true" tabindex="-1"></a>      |]</span></code></pre></div>
<p>Using <code>unsafePartsOf</code> allows us to act on the foci of a
traversal <em>as though</em> they were in a simple list. The
<code>unsafe</code> bit is that it will crash if we don't return a list
with the exact same number of elements, so be aware of that, but it's
the same crash we'd have gotten in our old version if an ID was missing
a value.</p>
<p>This also allows us to avoid the song-and-dance for converting the
incoming traversal into a fold.</p>
<p>We need the <code>ord</code> column simply because sql doesn't
guarantee any specific result order unless we specify one. This will
pair up result rows piecewise with the input IDs, and so it doesn't
require any Ord instance.</p>
<p>We can wrap <code>unsafePartsOf</code> with our own combinator to add
a few additional features.</p>
<p>Here's a version which will deduplicate IDs in the input list, will
skip the action if the input list is empty, and will provide a nice
error with a callstack if anything goes sideways.</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="ot">asListOf ::</span> (<span class="dt">HasCallStack</span>, <span class="dt">Ord</span> a) <span class="ot">=&gt;</span> <span class="dt">Traversal</span> s t a b <span class="ot">-&gt;</span> <span class="dt">Traversal</span> s t [a] [b]</span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a>asListOf trav f s <span class="ot">=</span></span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a>  s</span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">&amp;</span> unsafePartsOf trav <span class="op">%%~</span> \<span class="kw">case</span></span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a>      <span class="co">-- No point making a database call which will return no results</span></span>
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a>      [] <span class="ot">-&gt;</span> <span class="fu">pure</span> []</span>
<span id="cb17-7"><a href="#cb17-7" aria-hidden="true" tabindex="-1"></a>      inputs <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb17-8"><a href="#cb17-8" aria-hidden="true" tabindex="-1"></a>        <span class="co">-- First, deduplicate the inputs as a self indexed map.</span></span>
<span id="cb17-9"><a href="#cb17-9" aria-hidden="true" tabindex="-1"></a>        <span class="kw">let</span> asMap <span class="ot">=</span> Map.fromList (<span class="fu">zip</span> inputs inputs)</span>
<span id="cb17-10"><a href="#cb17-10" aria-hidden="true" tabindex="-1"></a>        asMap</span>
<span id="cb17-11"><a href="#cb17-11" aria-hidden="true" tabindex="-1"></a>          <span class="co">-- Call the action with the list of deduped inputs</span></span>
<span id="cb17-12"><a href="#cb17-12" aria-hidden="true" tabindex="-1"></a>          <span class="op">&amp;</span> unsafePartsOf traversed f</span>
<span id="cb17-13"><a href="#cb17-13" aria-hidden="true" tabindex="-1"></a>          <span class="op">&lt;&amp;&gt;</span> \resultMap <span class="ot">-&gt;</span></span>
<span id="cb17-14"><a href="#cb17-14" aria-hidden="true" tabindex="-1"></a>            <span class="co">-- Now map the result for each input in the original list to its result value</span></span>
<span id="cb17-15"><a href="#cb17-15" aria-hidden="true" tabindex="-1"></a>            <span class="kw">let</span> resultList <span class="ot">=</span> mapMaybe (\k <span class="ot">-&gt;</span> Map.lookup k resultMap) inputs</span>
<span id="cb17-16"><a href="#cb17-16" aria-hidden="true" tabindex="-1"></a>                aLength <span class="ot">=</span> <span class="fu">length</span> inputs</span>
<span id="cb17-17"><a href="#cb17-17" aria-hidden="true" tabindex="-1"></a>                bLength <span class="ot">=</span> <span class="fu">length</span> resultList</span>
<span id="cb17-18"><a href="#cb17-18" aria-hidden="true" tabindex="-1"></a>             <span class="kw">in</span> <span class="kw">if</span> aLength <span class="op">/=</span> bLength</span>
<span id="cb17-19"><a href="#cb17-19" aria-hidden="true" tabindex="-1"></a>                  <span class="co">-- Better error message if our query is bad and returns the wrong number of elements.</span></span>
<span id="cb17-20"><a href="#cb17-20" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">then</span> <span class="fu">error</span> <span class="op">$</span> <span class="st">&quot;asListOf: length mismatch, expected &quot;</span> <span class="op">++</span> <span class="fu">show</span> aLength <span class="op">++</span> <span class="st">&quot; elements, got &quot;</span> <span class="op">++</span> <span class="fu">show</span> bLength <span class="op">&lt;&gt;</span> <span class="st">&quot; elements&quot;</span></span>
<span id="cb17-21"><a href="#cb17-21" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">else</span> resultList</span></code></pre></div>
<p>Using a tool like this has caveats, it's very easy to cause runtime
crashes if your query isn't written to <em>always</em> return the same
number of results as it was given inputs, and skipping the action on
empty lists could result in some confusion.</p>
<h3 id="conclusion">Conclusion</h3>
<p>I've gotten a ton of use out of this technique in Unison Share, and
managed to speed things up by 2 orders of magnitude. I was also able to
perform a fully batched rewrite of heavily nested code without needing
to re-arrange the code-graph. This was particularly useful because it
allowed me to partially large portions of the codebase in smaller pieces
by using batched methods with a simple <code>id</code> Traversal, and
using simple traverse on methods you haven't rewritten yet.</p>
<p>You may not get such huge gains if your code isn't pessimistically
linear in the first place, but this is also a nice, composable way to
write batch code in the first place.</p>
<p>Anyways, give it a go and let me know what you think of it!</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Building Industrial Strength Software without Unit Tests</title>
      <link href="https://chrispenner.ca/posts/transcript-tests"/>
      <id>https://chrispenner.ca/posts/transcript-tests</id>
      <updated>2025-06-02T00:00:00Z</updated>
      <summary>Unit tests aren&#39;t the only way.</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/transcript-tests.jpg" alt="Building Industrial Strength Software without Unit Tests">
              <p>I don't know about you, but testing isn't my favourite part of
software development.</p>
<p>It's usually the last thing standing between me and shipping a shiny
new feature, and writing tests is often an annoying process with a lot
of boilerplate and fighting against your system to get your app into a
good start starting for the test or mocking out whichever services your
app depends on.</p>
<p>Much ink has been spilled about how to organize your code in order to
make this easier, but the fact that so many blog posts and frameworks
exist for this express purpose suggests to me that we as a community of
software developers haven't quite solved this issue yet.</p>
<p>Keep reading to see how I've solved this problem for myself by simply
avoiding unit testing altogether.</p>
<h2 id="an-alternative-testing-method">An alternative testing
method</h2>
<p>When I first started at Unison Computing I was submitting my first
feature when I learned there were precious few unit tests. I found it
rather surprising for a codebase for a compiler for a programming
language! How do you prevent regressions without unit tests?</p>
<p>The answer is what the Unison team has dubbed <strong>transcript
tests</strong>. These are a variation on the concept of <em>golden-file
tests</em>.</p>
<p>A <em>Unison transcript</em> is a markdown file which explains in
standard what behaviour it is going to test, then intersperses
code-blocks which outline the steps involved in testing that feature
using a mix of Unison code and UCM commands (UCM is Unison's CLI tool).
After that comes the magic trick; UCM itself can understand and run
these transcript files directly and record the results of each
block.</p>
<p>When running a transcript file with the <code>ucm transcript</code>
command UCM produces a deterministic output file containing the result
of processing each code block. Unless the behaviour of UCM has changed
since the last time it was run the resulting file will always be the
same.</p>
<p>Each block in the markdown file is either a command, which is sent to
the UCM shell tool, or it represents an update to a file on the
(virtual) file-system, in which case it will be typechecked against the
state of the codebase.</p>
<p>Here's a quick example of a transcript for testing UCM's view command
so you can get a feel for it.</p>
<pre><code># Testing the `view` command

First, let&#39;s write a simple definition to view:

``` unison
isZero = cases
  0 -&gt; true
  _ -&gt; false
```

Now we add the definition to the codebase, and view it.

``` ucm
scratch/main&gt; update
scratch/main&gt; view isZero
```</code></pre>
<p>We run this transcript file with
<code>ucm transcript my-transcript.md</code> which produces the
<code>my-transcript.output.md</code> file.</p>
<p>Notice how compiler output is added inline, ignore the hashed names,
It's because I'm skipping the step which adds names for Unison's
builtins.</p>
<pre><code># Testing the `view` command

First, let&#39;s write a simple definition to view:

``` unison
isZero = cases
  0 -&gt; true
  _ -&gt; false
```

``` ucm :added-by-ucm
  Loading changes detected in scratch.u.

  I found and typechecked these definitions in scratch.u. If you
  do an `add` or `update`, here&#39;s how your codebase would
  change:

    ⍟ These new definitions are ok to `add`:
    
      isZero : ##Nat -&gt; ##Boolean
```

Now we add the definition to the codebase, and view it.

``` ucm
scratch/main&gt; update

  Done.

scratch/main&gt; view isZero

  isZero : ##Nat -&gt; ##Boolean
  isZero = cases
    0 -&gt; true
    _ -&gt; false
```</code></pre>
<p>Feel free to browse through the <a
href="https://github.com/unisonweb/unison/tree/86bf4b2/unison-src/transcripts-using-base">collection
of transcripts</a> we test in CI to keep UCM working as expected.</p>
<h2 id="testing-in-ci">Testing in CI</h2>
<p>Running transcript tests in CI is pretty trivial; we discover all
markdown files within our transcript directory and run them all. After
the outputs have been written we can use
<code>git diff --exit-code</code> which will then fail with a non-zero
code if anything of the outputs have changed from what was committed.
Conveniently, git will also report <em>exactly</em> what changed, and
what the old output was.</p>
<p>This failure method allows the developer to know exactly which file
has unexpected behaviour so they can easily re-run that file or recreate
the state in their own codebase if they desire.</p>
<h2 id="transcript-tests-in-other-domains">Transcript tests in other
domains</h2>
<p>I liked the transcript tests in UCM so much that when I was tasked
with building out the Unison Share webapp I decided to use
transcript-style testing for that too. Fast forward a few years and
Unison Share is now a fully-featured package repository and code
collaboration platform running in production without a
<strong>single</strong> unit test.</p>
<p>If you're interested in how I've adapted transcript tests to work
well for a webapp, I'll leave a few notes at the end of the post.</p>
<h2 id="benefits-of-transcript-tests">Benefits of transcript tests</h2>
<p>Here's a shortlist of benefits I've found working with transcript
tests over alternatives like unit tests.</p>
<p><strong>You write a transcript using the same syntax as you'd
interact with UCM itself.</strong></p>
<p>This allows all your users to codify any buggy behaviour they've
encountered into a deterministic transcript. Knowing exactly how to
reproduce the behaviour your users are seeing is a huge boon, and having
a single standardized format for accepting bug reports helps reduce a
lot of the mental work that usually goes into reproducing bug reports
from a variety of sources. This also means that the bug report itself
can go directly into the test suite if we so desire.</p>
<p><strong>All tests are written against the tool's <em>external</em>
interface.</strong></p>
<p>The tests use the same interface that the users of your software will
employ, which means that <strong>internal refactors won't ever break
tests</strong> unless there's a change in behaviour that's externally
observable.</p>
<p>This has been a huge benefit for me personally. I'd often find myself
hesitant to re-work code because I knew that at the end I'd be rewriting
thousands of lines of tests. If you always have to rewrite your tests at
the same time you've rewritten your code, how do you have any confidence
that the tests still work as intended?</p>
<p><strong>Updating tests is trivial</strong></p>
<p>In the common case where transcripts are mismatched because some help
message was altered, or perhaps the behaviour has changed but the change
is intended, you don't need to rewrite any complex assertions, or mock
out any new dependencies. You can simply look at the new output, and if
it's reasonable you commit the changed transcript output files.</p>
<p>It can't be understated how convenient this is when making sweeping
changes; e.g. making changes to Unison's pretty printer. We don't need
to manually update test-cases, we just run the transcripts locally and
commit the output if it all looks good!</p>
<p><strong>Transcript changes appear in PR reviews</strong></p>
<p>Since all transcript outputs are committed, any change in behaviour
will show up in the PR diff in an easy-to-read form. This allows
reviewers to trivially see the old and new behaviour for each relevant
feature.</p>
<p><strong>Transcript tests are documentation</strong></p>
<p>Each transcript shows how a feature is intended to be used by
end-users.</p>
<p><strong>Transcripts as a collaboration tool</strong></p>
<p>When I'm implementing new features in Unison Share I need to
communicate the shape of a JSON API with our Frontend designer Simon.
Typically I'll just write a transcript test which exercises all possible
variants of the new feature, then I can just point at the transcript
output as the interface for those APIs.</p>
<p>It's beneficial for both of us since I don't need to keep an example
up-to-date for him, and he knows that the output is actually accurate
since it's generated from an execution of the service itself.</p>
<h2 id="transcript-testing-for-webapps">Transcript testing for
Webapps</h2>
<p>I've adapted transcript testing a bit for the Unison Share webapp. I
run the standard Share executable locally with its dependencies mocked
out via docker-compose. I've got a SQL file which resets the database
with a known set of test fixtures, then use a zsh script to reset my
application state in between running each transcript.</p>
<p>Each transcript file is just a zsh script that interacts with the
running server using a few bash functions which wrap curl commands, but
save the output to json files, which serve as the transcript output.</p>
<p>I've also got helpers for capturing specific fields from an API call
into local variables which I can then interpolate into future queries,
this is handy if you need to, for example, create a project then switch
it from private to public, then fetch that project via API.</p>
<p>Here's a small snippet from one of my transcripts for testing Unison
Share's project APIs:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode sh"><code class="sourceCode bash"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="co">#!/usr/bin/env zsh</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="co"># Fail the transcript if any command fails</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="bu">set</span> <span class="at">-e</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 class="co"># Load utility functions and variables for user credentials</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a><span class="bu">source</span> <span class="st">&quot;../../transcript_helpers.sh&quot;</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a><span class="co"># Run a UCM transcript to upload some code to load in projects.</span></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a><span class="ex">transcript_ucm</span> transcript prelude.md</span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a><span class="co"># I should be able to see the fixture project as an unauthenticated user.</span></span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a><span class="ex">fetch</span> <span class="st">&quot;</span><span class="va">$unauthenticated_user</span><span class="st">&quot;</span> GET project-get-simple <span class="st">&#39;/users/test/projects/publictestproject&#39;</span></span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true" tabindex="-1"></a><span class="co"># I should be able to create a new project as an authenticated user.</span></span>
<span id="cb3-16"><a href="#cb3-16" aria-hidden="true" tabindex="-1"></a><span class="ex">fetch</span> <span class="st">&quot;</span><span class="va">$transcripts_user</span><span class="st">&quot;</span> POST project-create <span class="st">&#39;/users/transcripts/projects/containers&#39;</span> <span class="st">&#39;{</span></span>
<span id="cb3-17"><a href="#cb3-17" aria-hidden="true" tabindex="-1"></a><span class="st">    &quot;summary&quot;: &quot;This is my project&quot;,</span></span>
<span id="cb3-18"><a href="#cb3-18" aria-hidden="true" tabindex="-1"></a><span class="st">    &quot;visibility&quot;: &quot;private&quot;,</span></span>
<span id="cb3-19"><a href="#cb3-19" aria-hidden="true" tabindex="-1"></a><span class="st">    &quot;tags&quot;: []</span></span>
<span id="cb3-20"><a href="#cb3-20" aria-hidden="true" tabindex="-1"></a><span class="st">}&#39;</span></span>
<span id="cb3-21"><a href="#cb3-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-22"><a href="#cb3-22" aria-hidden="true" tabindex="-1"></a><span class="ex">fetch</span> <span class="st">&quot;</span><span class="va">$transcripts_user</span><span class="st">&quot;</span> GET project-list <span class="st">&#39;/users/transcripts/projects&#39;</span></span></code></pre></div>
<p>You can see the output files generated by the full transcript <a
href="https://github.com/unisoncomputing/share-api/tree/f475f49/transcripts/share-apis/projects-flow">in
this directory</a>.</p>
<h2 id="requirements-of-a-good-transcript-testing-tool">Requirements of
a good transcript testing tool</h2>
<p>After working with two different transcript testing tools across two
different apps I've got a few criteria for what makes a good transcript
testing tool, if you're thinking of adding transcript tests to your app
consider the following:</p>
<p><strong>Transcripts should be deterministic</strong></p>
<p>This is critical. Transcripts are only useful if they produce the
same result on every run, on every operating system, at every time of
day.</p>
<p>You may need to make a few changes in your app to adapt or remove
randomness, at least when in the context of a transcript test.</p>
<p>In Share there were a lot of timestamps, random IDs, and JWTs (which
contain a timestamp). The actual values of these weren't important for
the tests themselves, so I solved the issue by piping the curl output
through a <code>sed</code> script before writing to disk. The script
matches timestamps, UUIDs, and JWTs and replaces them with placeholders
like <code>&lt;TIMESTAMP&gt;</code>, <code>&lt;UUID&gt;</code>, and
<code>&lt;JWT&gt;</code> accordingly.</p>
<p>A special mode in your app for transcript testing which avoids
randomness can be useful, but use custom modes sparingly lest your app's
behaviour differ too much during transcripts and you can't test the real
thing.</p>
<p>I also make sure that the data returned by APIs is always sorted by
something other than randomized IDs, it's a small price to pay, and
reduces randomness and heisenbugs in the app as a helpful byproduct.</p>
<p><strong>Transcripts should be isolated</strong></p>
<p>Each individual transcript should be run in its own pristine
environment. Databases should be reset to known state, if the
file-system is used, it should be cleared or even better, a virtual
file-system should be used.</p>
<p><strong>Transcripts should be self-contained</strong></p>
<p>Everything that pertains to a given test-case's state or
configuration should be evident from within the transcript file itself.
I've found that changes in behaviour from the file's location or name
can just end up being confusing.</p>
<h2 id="difficulties-working-with-transcripts">Difficulties working with
Transcripts</h2>
<p><strong>Transcripts often require custom tooling</strong></p>
<p>In UCM's case the transcript tooling has evolved slowly over many
years, it has it's own parser, and you can even test UCM's API server by
using special code blocks for that.</p>
<p>Share has a variety of <code>zsh</code> utility scripts which provide
helpers for fetching endpoints using curl, and filtering output to
capture data for future calls. It also has a few tools for making
database calls and assertions.</p>
<p>Don't shy away from investing a bit of time into making transcript
testing sustainable and pleasant, it will pay dividends down the
road.</p>
<p><strong>Intensive Setup</strong></p>
<p>As opposed to unit tests which are generally pretty lightweight;
transcript tests are full integration tests, and require setting up
data, and sometimes executing entire flows so that we can get the system
into a good state for testing each feature.</p>
<p>You can mitigate the setup time by testing multiple features with
each transcript.</p>
<p>I haven't personally found transcript tests to take too much time in
CI, largely because I think transcript testing tends to produce fewer
tests, but of higher value than unit testing. I've seen many unit test
suites bogged down by particular unit tests which generate hundreds of
test cases that aren't actually providing real value. Also, any
setup/teardown is going to be more costly on thousands of unit-tests as
compared to dozens or hundreds of transcript tests.</p>
<p><strong>Service Mocking</strong></p>
<p>Since transcript tests run against the system-under-test's external
interface, you won't have traditional mocking/stubbing frameworks
available to you. Instead, you'll mock out the system's dependencies by
specifying custom services using environment variables, or wiring things
up in docker-compose.</p>
<p>Most systems have a setup for local development anyways, so
integrating transcript tests against it has the added benefit that
they'll ensure your local development setup is tested in CI, is
consistent for all members of your team, and continues to work as
expected.</p>
<h2 id="in-summary">In Summary</h2>
<p>Hopefully this post has helped you to consider your relationship with
unit tests and perhaps think about whether other testing techniques may
work better for your app.</p>
<p>Transcript tests surely aren't ideal for <strong>all</strong>
possible apps or teams, but my last few years at Unison have proven to
me that tests can be more helpful, efficient, and readable than I'd
previously thought possible.</p>
<p>Let me know how it works out for you!</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>3 things other languages should steal from Unison</title>
      <link href="https://chrispenner.ca/posts/things-to-steal-from-unison"/>
      <id>https://chrispenner.ca/posts/things-to-steal-from-unison</id>
      <updated>2025-04-24T00:00:00Z</updated>
      <summary>Some things other languages should steal from Unison</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/steal.jpg" alt="3 things other languages should steal from Unison">
              <p>New languages are coming out all the time, some experimental, some
industrial, others are purpose built for a specific domain. No single
language has the people-power or scope to try every cool new feature, so
a critical step in designing a new language is to observe how
experimental features have borne themselves out in practice.</p>
<p>As the saying goes, good [language designers] copy, great [language
designers] steal.</p>
<p>If you've heard anything about the Unison Language it's not a
surprise to you that it innovates in many areas. Unison very much tries
to reinvent Human-Compiler interactions for the 21st century, and in
that pursuit has spawned fully integrated ecosystem between the
compiler, codebase-manager, language server, version control and package
manager.</p>
<p>While some of these features are still too new to have proven their
worth (but we have our fingers crossed); there are aspects that I think
new languages should certainly consider as part of their designs.</p>
<h2 id="a-fully-interactive-and-incremental-compiler">A Fully
Interactive and Incremental Compiler</h2>
<p>With the modern era of language servers and programming assistants,
developers greatly benefit from instant feedback on their work. With
traditional batch compilers it's all too tempting to go for a coffee, or
a walk, or a YouTube binge every time you kick off a big build. The
context-switching induced by switching tasks while compiling wastes
developer time by paging things in and out of their working memory, not
to mention: <em>it just feels bad</em>. After the build finishes, the
developer is left with a giant wall of text, sentenced to dig through a
large list of compiler errors trying to find some root-cause error in
the file they're working on.</p>
<p>Unison has a fully interactive compilation experience. The
language-server is typechecking your scratch-file on every keystroke
providing error feedback right in your editor, and offering helpful
information via hover-hints which use your codebase and typechecking
info to help you orient yourself. It can even partially typecheck the
file to suggest which types or operators you may want to fill into a
given slot.</p>
<p>Once you're happy with a chunk of code, you can check it in to the
codebase and it won't be compiled again unless you want to change it, or
an update is automatically propagated into it from a downstream
change.</p>
<p>While most languages won't adopt Unison's scratch-file and codebase
model; having an interactive compiler with good support for caching of
already-compiled-assets is a huge boon to productivity in any
language.</p>
<p>On the topic of the language server, Unison's language server is
built directly into the compiler. This ensures we avoid the awkward
disagreements between the LSP and compiler that sometimes happen in
other languages. It can also help to avoid duplicate work, many
languages are running the compiler independently and in their LSP at the
same time without sharing any of the work between them, causing
redundant work and a waste of precious resources.</p>
<h2 id="codebase-api">Codebase API</h2>
<p>It's the compiler's job to understand your code intimately. It knows
exactly how every definition is linked together, even if you don't! In
many languages it can be frustrating to know that this information
exists deep within the compiler, but not having any access to it
yourself!</p>
<p>Unison stores all your code as structured data within your codebase
and exposes the ability for you to ask it useful questions about your
code, exposing that precious understanding to you as a developer.</p>
<p>Unison allows searching by type, finding the dependencies of a
definition, or inverting that relationship to finding all definitions
which depend on a definition.</p>
<p>Via the UCM CLI you can use utilities like <code>text.find</code> to
search only string constants, or <code>find</code> to search only
definition names.</p>
<p>Some codebase data is provided via an API which is exposed from the
interactive UCM compiler, allowing developers to write tooling to
customize their workflow. For example, check out this <a
href="https://marketplace.visualstudio.com/items?itemName=TomSherman.unison-ui">VS
Code plugin</a> someone wrote to view codebase definitions in the
sidebar. In other languages you'd typically need to write a scrappy
Regex or re-compile the code in a subprocess in order to achieve
something similar.</p>
<p>It doesn't have to be an API, it could be a parquet file or a SQLite
database or any number of things, the important part is that a language
exposes its one-true-source of information about the codebase in some
structured format for third-party tools to build upon.</p>
<h2 id="smart-docs">Smart docs</h2>
<p>It doesn't matter how great your language's package ecosystem is if
nobody can figure out how to use it! Documentation is critical for
helping end users understand and use functionality in your language, but
it has a fatal flaw: documentation isn't compiled and falls out of date
with the code.</p>
<p>In Unison, docs are a data-type within the language itself. This
means that docs can be generated dynamically by <em>running Unison
code</em>! We've leveraged this ability to enable embedding typechecked
runnable code examples into your docs. These examples are compiled
alongside the rest of your program, so they're <strong>guaranteed to be
kept up to date</strong>, and the outputs from your example code is run
and updated whenever the source definitions change.</p>
<p>You can also write code which <em>generates</em> documentation based
on your real application code. For example, you could write code which
crawls your web-server's implementation and collects all the routes and
parameters the server defines and displays them nicely as
documentation.</p>
<p>Unison goes one step further here by providing special support for
the documentation format on Unison Share, ensuring any definitions
mentioned in docs and code examples are hyper-linked to make for a
seamless package-browsing experience.</p>
<p>As an example of how far this can go, check out <a
href="https://share.unison-lang.org/@alvaroc1/circuit2/code/main/latest/terms/README">this
awesome project</a> by community contributor Alvaro which generates
mermaid graphs in the docs representing the behaviour of simulations.
The graphs are generated from the same underlying library code so they
won't go out of date.</p>
<h2 id="get-stealing">Get stealing</h2>
<p>This subset of topics doesn't touch on Unison's ability system,
continuation capturing, or code serialization so I'll probably need at
least a part 2!</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Building Type Search for Unison</title>
      <link href="https://chrispenner.ca/posts/unison-type-search"/>
      <id>https://chrispenner.ca/posts/unison-type-search</id>
      <updated>2024-08-14T00:00:00Z</updated>
      <summary>Building an efficient and scalable type search for Unison</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/type-based-search/type-based-search.png" alt="Building Type Search for Unison">
              <p>Hello! Today we'll be looking into type-based search, what it is, how
it helps, and how to build one for the <a
href="https://www.unison-lang.org/">Unison programming language</a> at
production scale.</p>
<h2 id="motivating-type-directed-search">Motivating type-directed
search</h2>
<p>If you've never used a type-directed code search like <a
href="https://hoogle.haskell.org/">Hoogle</a> it's tough to fully
understand how useful it can be. Before starting on my journey to learn
Haskell I had never even thought to ask for a tool like it, now I reach
for it every day.</p>
<p>Many languages offer some form of code search, or at the very least a
package search. This allows users to find code which is relevant for the
task they're trying to accomplish. Typically you'd use these searches by
querying for a natural language phrase describing what you want, e.g.
<code>"Markdown Parser"</code>.</p>
<p>This works great for finding entire packages, but searching at the
package level is often far too rough-grained for the problem at hand. If
I just want to very quickly remember the name of the function which
lifts a <code>Char</code> into a <code>Text</code>, I already know it's
probably in the <code>Text</code> package, but I can save some time
digging through the package by asking a search precisely for definitions
of this type. Natural languages are quite imprecise, so a more
specialized query-by-type language allows us to get better results
faster.</p>
<p>If I search using google for "javascript function to group elements
of a list using a predicate" I find many different functions which do
<em>some</em> form of grouping, but none of them quite match the shape I
had in mind, and I need to read through blogs, stack-overflow answers,
and package documentation to determine whether the provided functions
actually do what I'd like them to.</p>
<p>In Haskell I can instead express that question using a type! If I
enter the type <code>[a] -&gt; (a -&gt; Bool) -&gt; ([a], [a])</code>
into Hoogle I get a list of functions which match that type exactly,
there are few other operations with a matching signature, but I can
quickly open those definitions on Hackage and determine that
<code>partition</code> is exactly what I was looking for.</p>
<p>Hopefully this helps to convince you on the utility of a
type-directed search, though it does raise a question: if type-directed
search is so <strong>useful</strong>, why isn't it more
<strong>ubiquitous</strong>?</p>
<p>Here are a few possible reasons this could be:</p>
<ul>
<li>Some languages lack a sufficiently sophisticated type-system with
which to express useful queries</li>
<li>Some languages don't have a centralized package repository</li>
<li>Indexing every function ever written in your language can be
computationally expensive</li>
<li>It's not immediately obvious how to implement such a system</li>
</ul>
<p>Read on and I'll do what my best to help with the latter
limitation.</p>
<h2 id="establishing-our-goals">Establishing our goals</h2>
<p>Before we start building anything, we should nail-down what our
search problem actually is.</p>
<p>Here are a few goals we had for the Unison type-directed search:</p>
<ul>
<li>It should be able to find functions based on a partial
type-signature</li>
<li>The names given to type variables shouldn't matter.</li>
<li>The ordering of arguments to a function shouldn't matter.</li>
<li>It should be fast</li>
<li>It should should scale</li>
<li>It should be <em>good</em>...</li>
</ul>
<p>The last criterion is a bit subjective of course, but you know it
when you see it.</p>
<h2 id="the-method">The method</h2>
<p>It's easy to imagine search methods which match <em>some</em> of the
required characteristics. E.g. we can imagine iterating through every
definition and running the typechecker to see if the query unifies with
the definition's signature, but this would be <strong>far</strong> too
slow, and wouldn't allow partial matches or mismatched argument
orders.</p>
<p>Alternatively we could perform a plain-text search over rendered type
signatures, but this would be very imprecise and would break our
requirement that type variable names are unimportant.</p>
<p>Investigating prior art, Neil Mitchell's excellent Hoogle uses a
linear scan over a set of pre-built function-fingerprints for whittling
down potential matches. The level of speed accomplished with this method
is quite impressive!</p>
<p>In our case, Unison Share, the code-hosting platform and package
manager for Unison is backed by a Postgres database where all the code
is stored. I investigated a few different Postgres index variants and
landed on a GIN (Generalized inverted index).</p>
<p>If you're unfamiliar with GIN indexes the gist of it is that it
allows us to quickly find rows which are associated with any given
combination of search tokens. They're typically useful when implementing
full-text searches, for instance we may choose to index a text document
like the following:</p>
<pre><code>postgres=# select to_tsvector(&#39;And what is the use of a book without pictures or conversations?&#39;);
                      to_tsvector
-------------------------------------------------------
 &#39;book&#39;:8 &#39;convers&#39;:12 &#39;pictur&#39;:10 &#39;use&#39;:5 &#39;without&#39;:9
(1 row)</code></pre>
<p>The generated lexemes represent a fingerprint of the text file which
can be used to quickly and efficiently determine a subset of stored
documents which can then be filtered using other more precise methods.
So for instance we could search for <code>book &amp; pictur</code> to
very efficiently find all documents which contain at least one word that
tokenizes as <code>book</code> AND any word that tokenizes as
<code>pictur</code>.</p>
<p>I won't go too in-depth here on how GIN indexes work as you can
consult the excellent <a
href="https://www.postgresql.org/docs/current/gin.html">Postgres
documentation</a> if you'd like a deeper dive into that area.</p>
<p>Although our problem isn't exactly full-text-search, we can leverage
GIN into something similar to search type signatures by a set of
attributes.</p>
<p>The attributes we want to search for can be distilled from our
requirements; we need to know which types are mentioned in the
signature, and we need some way to <em>normalize</em> type variables and
argument position.</p>
<p>Let's come up with a way to <em>tokenize</em> type signatures into
the attributes we care about.</p>
<h2 id="computing-tokens-for-type-signature-search">Computing Tokens for
type signature search</h2>
<h3 id="mentions-of-concrete-types">Mentions of concrete types</h3>
<p>If the user metnions a concrete type in their query, we'll need to
find all type signatures which mention it.</p>
<p>Consider the following signature:
<code>Text.take : Nat -&gt; Text -&gt; Text</code></p>
<p>We can boil down the info here into the following data:</p>
<ul>
<li>A type called <code>Nat</code> is mentioned <em>once</em>, and it
does <em>NOT</em> appear in the return type of the function.</li>
<li>A type called <code>Text</code> is mentioned <em>twice</em>, and it
<em>does</em> appear in the return type of the function.</li>
</ul>
<p>There really aren't any rules on how to represent lexemes in a GIN
index, it's really just a set of string tokens. Earlier we saw how
Postgres used an English language tokenizer to distill down the essence
of a block of text into a set of tokens; we can just as easily devise
our own token format for the information we care about.</p>
<p>Here's the format I went with for our search tokens:
<code>&lt;token-kind&gt;,&lt;number-of-occurrences&gt;,&lt;name|hash|variable-id&gt;</code></p>
<p>So for the mentions of <code>Nat</code> in <code>Text.take</code>'s
signature we can build the token: <code>mn,1,Nat.</code>. It starts with
the token's kind (<code>mn</code> for Mention by Name), which prevents
conflicts between tokens even though they'll all be stored in the same
<code>tsvector</code> column. Next I include the number of times it's
mentioned in the signature followed by it's fully qualified name with
the path <em>reversed</em>.</p>
<p>In this case <code>Nat</code> is a single segment, but if the type
were named <code>data.JSON.Array</code> it would be encoded as
<code>Array.JSON.data.</code>,</p>
<p>Why? Postgres allows us to do <em>prefix</em> matches over tokens in
GIN indexes. This allows us to search for matches for any valid suffix
of the query's path, e.g. <code>mn,1,Array.*</code>,
<code>mn,1,Array.JSON.*</code> or <code>mn,1,Array.JSON.data.*</code>
would all match a single mention of this type.</p>
<p>Users don't always know <strong>all</strong> of the arguments of a
function they're looking for, so we'd love for partial type matches to
still return results. This also helps us to start searching for and
displaying potentially relevant results while the user is still typing
out their query.</p>
<p>For instance <code>Nat -&gt; Text</code> should still find
<code>Text.take</code>, so to facilitate that, when we have more than a
single mention we make a separate token for each of the
<code>1..n</code> mentions. E.g. in
<code>Text.take : Nat -&gt; Text -&gt; Text</code> we'd store both
<code>mn,1,Text</code> AND <code>mn,2,Text</code> in our set of
tokens.</p>
<p>We can't perform arithmetic in our GIN lookup, so this method is a
workaround which allows us to find any type where the number of mentions
is greater than or equal to the number of mentions in the query.</p>
<h3 id="type-mentions-by-hash">Type mentions by hash</h3>
<p>This is Unison after all, so if there's a specific type you care
about but you don't care what the particular package has named that
type, or if there's even a specific <strong>version</strong> of a type
you care about, you can search for it by hash: E.g.
<code>#abcdef -&gt; #ghijk</code>. This will tokenize into
<code>mh,1,#abcdef</code> and <code>mh,1,#ghijk</code>. Similar to name
mentions this allows us to search using only a prefix of the actual
hash.</p>
<h3 id="handling-return-types">Handling return types</h3>
<p>Although we don't care about the order of <em>arguments</em> to a
given function, the return-type <em>is</em> a very high value piece of
information. We can add additional tokens to track every type which is
mentioned in the return type of a function by simply adding an
additional token with an <code>r</code> in the 'mentions' place, e.g.
<code>mn,r,Text</code></p>
<p>We'll use this later to improve the scoring of returned results, and
may in the future allow performing more advanced searches like "Show me
all functions which produce a value of this type", a.k.a. functions
which return that type but don't accept it as an argument, or perhaps
"Show me all handlers of this ability", which corresponds to all
functions which accept that ability as an argument but <em>don't</em>
return it, e.g. <code>'mn,1,Stream' &amp; (! 'mn,r,Stream')</code>.</p>
<p>A note on higher-kinded types and abilities like
<code>Map Text Nat</code> and <code>a -&gt; {Exception} b</code>, we
simply treat each of these as its own concrete type mention. The system
could be expanded to include more token types for each of these, but one
has to be wary of an explosion in the number of generated tokens and in
initial testing the search seems to work quite well despite no special
treatment.</p>
<h3 id="mentions-of-type-variables">Mentions of type variables</h3>
<p>Concrete types are covered, but what about type variables? Consider
the type signature: <code>const: b -&gt; a -&gt; b</code>.</p>
<p>This type contains <code>a</code> and <code>b</code> which are
<em>type variables</em>. The names of type variables are not important
on their own, you can rename any type variable to anything you like as
long as you consider its scope and rename all the mentions of the same
variable within its scope.</p>
<p>To normalize the names of type variables I assign each variable a
numerical ID instead. In this example we may choose to assign
<code>b</code> the number <code>1</code> and <code>a</code> the number
<code>2</code>. However, we have to be careful because we <em>also</em>
want to be indifferent with regard to argument order. A search for
<code>a -&gt; b -&gt; b</code> should still find <code>const</code>! if
we assigned <code>a</code> to <code>1</code> and <code>b</code> to
<code>2</code> according to the order of their appearance we wouldn't
have a match.</p>
<p>To fix this issue we can simply sort the type variables according to
their number of <em>occurrences</em>, so in this example <code>a</code>
has fewer occurrences than <code>b</code>, so it gets the lower variable
ID.</p>
<p>This means that both <code>a -&gt; b -&gt; b</code> and
<code>b -&gt; a -&gt; b</code> will tokenize to the same set of tokens:
<code>v,1,1</code> for <code>a</code>, and <code>v,1,2</code>,
<code>v,2,2</code>, and <code>v,r,2</code> for <code>b</code>.</p>
<h2 id="parsing-the-search-query">Parsing the search query</h2>
<p>We could require that all queries are properly formed
type-signatures, but that's quite restrictive and we'd much rather allow
the user to be a bit <em>sloppy</em> in their search.</p>
<p>To that end I wrote a custom version of our type-parser that is
extremely lax in what it accepts, it will attempt to determine the arity
and return type of the query, but will also happily accept just a list
of type names. Searching for <code>Nat Text Text</code> and
<code>Nat -&gt; Text -&gt; Text</code> are both valid queries, but the
latter will return better results since we have information about both
the arity of the desired function and the return type. Once we've parsed
the query we can convert it into the same set of tokens we generated
from the type signatures in the codebase.</p>
<h2 id="performing-the-search">Performing the search</h2>
<p>After we've indexed all the code in our system (in Unison this takes
only a few minutes) we can start searching!</p>
<p>For Unison's search I've opted to require that each occurrence in the
query MUST be present in each match, however for better partial
type-signature support I do include results which are missing specified
return types, but will rank them lower than results with matching return
types in the results.</p>
<p>Other criteria used to score matches include: * Types with an arity
closer to the user's query are ranked higher * How complex the type
signature is, types with more tokens are ranked lower. * We give a
slight boost to some core projects, e.g. Unison's standard library
<code>base</code> will show up higher in search results if they match. *
You can include a text search along with your type search to further
filter results, e.g. <code>map (a -&gt; b) -&gt; [a] -&gt; [b]</code>
will prefer finding definitions with <code>map</code> somewhere in the
name. * Queries can include a specific user or project to search within
to further filter results, e.g. <code>@unison/cloud Remote</code></p>
<h2 id="summary">Summary</h2>
<p>I hope that helps shed some light on how it all works, and perhaps
will help others in implementing their own type-directed-search down the
road!</p>
<p>Now all that's left is to go <a
href="https://share.unison-lang.org/">try out a search or two</a> :)</p>
<p>If you're interested in digging deeper, Unison Share, and by-proxy
the entire type-directed search implementation, is all Open-Source, so
go check it out! It's changing and improving all the time, but <a
href="https://github.com/unisoncomputing/share-api/blob/6ee875db4ac35156733a0f2c9349bc528736243f/src/Share/Postgres/Search/DefinitionSearch/Queries.hs">this
module</a> would be a good place to start digging.</p>
<p>Let us know in the <a href="https://unison-lang.org/discord">Unison
Discord</a> if you've got any suggested improvements or run into any
bugs. Cheers!</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Simpler and safer API design using GADTs</title>
      <link href="https://chrispenner.ca/posts/gadt-design"/>
      <id>https://chrispenner.ca/posts/gadt-design</id>
      <updated>2020-12-10T00:00:00Z</updated>
      <summary>Herein we look at how, for certain situations, GADTs can sometimes
provide a cleaner approach than typeclasses.</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/gadts.jpg" alt="Simpler and safer API design using GADTs">
              <p>Hey folks! Today we'll be talking about <strong>GADTs</strong>, that
is, "Generalized Abstract Data Types". As the name implies, they're just
like Haskell's normal data types, but the <em>generalized</em> bit adds
a few new features! They aren't actually too tough to use once you
understand a few principles.</p>
<p>A lot of the writing out there regarding GADTs is pretty high-level
research and academia, in contrast, today I'm going to show off a
relatively practical and simple use-case. In this post we'll take a look
at a very real example where we can leveraged GADTs in a real-world
Haskell library to build a simple and expressive end-user interface.</p>
<p>We'll be designing a library for CSV manipulation. I used all of the
following techniques to design the interface for my <a
href="https://hackage.haskell.org/package/lens-csv">lens-csv</a>
library. Let's get started!</p>
<hr />
<p>Here's a teensy CSV that we'll work with throughout the rest of the
post. Any time you see <code>input</code> used in examples, assume it's
this CSV.</p>
<pre class="csv"><code>Name,Age,Home
Luke,19,Tatooine
Leia,19,Alderaan
Han,32,Corellia</code></pre>
<p>In its essence, a CSV is really just a list of <strong>rows</strong>
and each <strong>row</strong> is just a list of
<strong>columns</strong>. That's pretty much it! Any other meaning, even
something as benign as "this column contains numbers" isn't tracked in
the CSV itself.</p>
<p>This means we can model the data in a CSV using a simple type like
<code>[[String]]</code>, so far, so simple! There's a bit of a catch
here though. Although it's clear to us humans that
<code>Name,Age,Home</code> is the <strong>header row</strong> for this
CSV, there's no marker in the CSV itself to indicate that! It's up to
the user of the library to specify whether to treat the first row of a
CSV as a header or not, and herein lies our challenge!</p>
<p>Depending on whether the CSV has a header row or not, the user of our
library will want to reference the CSV columns by either a
<strong>column name</strong> or <strong>column number</strong>. In a
<strong>dynamic language</strong> (like Python) this is easily handled.
We would provide separate methods for indexing columns by either header
name or column number, and it would be the programmer's job to keep
track of when to use which. In a strongly-typed language like Haskell
however, we prefer to prevent such mistakes at compile time.
Effectively, we want to give the programmer jigsaw pieces that only fit
together in a way that works!</p>
<p>For the sake of pedagogy our miniature CSV library will perform the
following tasks:</p>
<ul>
<li>Decode a CSV string into a structured type</li>
<li>Get all the values in a given row</li>
</ul>
<h2 id="an-initial-approach">An Initial Approach</h2>
<p>First things first we'll need a <code>decode</code> function to parse
the CSV into a more structured type. In a production environment you'd
likely use performant types like <code>ByteString</code> and
<code>Vector</code>, but for our toy parser we'll stick to the types
provided by the Prelude.</p>
<p>Since this is a post about GADTs and not CSVs encodings we won't
worry about comma-escaping or quoting here, We'll do the naive thing and
split our rows into cells on every comma. The Prelude, unfortunately,
provides <code>lines</code> and <code>words</code>, but doesn't provide
a more generic splitting function, so I'll whip one up to suit our
needs.</p>
<p>Here's a function which splits a string on commas in such a way that
each "cell" is separated in the resulting list.</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">splitOn ::</span> <span class="dt">Eq</span> a <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> [a] <span class="ot">-&gt;</span> [[a]]</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>splitOn splitter <span class="ot">=</span> <span class="fu">foldr</span> go [[]]</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>    go char xs</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>      <span class="co">-- If the current character is our &quot;split&quot; character create a new partition</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>      <span class="op">|</span> splitter <span class="op">==</span> char <span class="ot">=</span> []<span class="op">:</span>xs</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>      <span class="co">-- Otherwise we can add the next char to the current cell</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>      <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="kw">case</span> xs <span class="kw">of</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>          (cell<span class="op">:</span>rest) <span class="ot">-&gt;</span> (char<span class="op">:</span>cell)<span class="op">:</span>rest</span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>          [] <span class="ot">-&gt;</span> [[char]]</span></code></pre></div>
<p>We can try it out to ensure it works as expected:</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="op">&gt;&gt;&gt;</span> splitOn <span class="ch">&#39;,&#39;</span> <span class="st">&quot;a,b,c&quot;</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>[<span class="st">&quot;a&quot;</span>,<span class="st">&quot;b&quot;</span>,<span class="st">&quot;c&quot;</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="co">-- Remember that CSV cells might be empty and we need it to handle that properly:</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> splitOn <span class="ch">&#39;,&#39;</span> <span class="st">&quot;,,&quot;</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>[<span class="st">&quot;&quot;</span>,<span class="st">&quot;&quot;</span>,<span class="st">&quot;&quot;</span>]</span></code></pre></div>
<p>Now we'll write a type to represent our CSV structure. We'll define
two constructors: one for a CSV with headers, one for a CSV without
headers.</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">data</span> <span class="dt">CSV</span> <span class="ot">=</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>      <span class="co">-- A CSV with headers includes a list of headers</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>      <span class="dt">NamedCsv</span> [<span class="dt">String</span>] [[<span class="dt">String</span>]]</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>      <span class="co">-- A CSV without headers contains only the CSV rows</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">|</span> <span class="dt">NumberedCsv</span> [[<span class="dt">String</span>]]</span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>)</span></code></pre></div>
<p>Great, now we can write our first attempt of a decoding function. The
implementation isn't really important here, so just focus on the
type!</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">decode ::</span> <span class="dt">Bool</span> <span class="co">-- ^ Whether to parse a header row or not</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>       <span class="ot">-&gt;</span> <span class="dt">String</span> <span class="co">--  ^ The csv file</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>       <span class="ot">-&gt;</span> <span class="dt">Maybe</span> <span class="dt">CSV</span> <span class="co">--  ^ We&#39;ll return &quot;Nothing&quot; if anything fails</span></span></code></pre></div>
<p>And here's our implementation just in case you're following along at
home:</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="co">-- Parse a header row</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>decode <span class="dt">True</span> input <span class="ot">=</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">case</span> splitOn <span class="ch">&#39;,&#39;</span> <span class="op">&lt;$&gt;</span> <span class="fu">lines</span> input <span class="kw">of</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>        (headers<span class="op">:</span>rows) <span class="ot">-&gt;</span> <span class="dt">Just</span> (<span class="dt">NamedCsv</span> headers rows)</span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>        [] <span class="ot">-&gt;</span> <span class="dt">Nothing</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a><span class="co">-- No header row</span></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a>decode <span class="dt">False</span> input <span class="ot">=</span></span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a>  <span class="kw">let</span> rows <span class="ot">=</span> splitOn <span class="ch">&#39;,&#39;</span> <span class="op">&lt;$&gt;</span> <span class="fu">lines</span> input</span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a>   <span class="kw">in</span> <span class="dt">Just</span> (<span class="dt">NumberedCsv</span> rows)</span></code></pre></div>
<p>Simple enough; we create a CSV with the correct constructor based on
whether we expect headers or not.</p>
<p>So what if we want to get all of the names from our CSV? Let's write
a function to get all the values of a specific column. Here's where
things get a bit more interesting:</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">getColumnByNumber ::</span> <span class="dt">CSV</span> <span class="ot">-&gt;</span> <span class="dt">Int</span>    <span class="ot">-&gt;</span> <span class="dt">Maybe</span> [<span class="dt">String</span>]</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="ot">getColumnByName   ::</span> <span class="dt">CSV</span> <span class="ot">-&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> [<span class="dt">String</span>]</span></code></pre></div>
<p>Since each type of CSV takes a different index type we need a
different function for each of the index types. Let's implement
them!</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="co">-- A safe indexing function to get elements by index.</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- This is strangely missing from the Prelude... 🤔</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="ot">safeIndex ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> [a] <span class="ot">-&gt;</span> <span class="dt">Maybe</span> a</span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>safeIndex i <span class="ot">=</span> <span class="fu">lookup</span> i <span class="op">.</span> <span class="fu">zip</span> [<span class="dv">0</span><span class="op">..</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="co">-- Get all values of a column by the column index</span></span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a><span class="ot">getColumnByNumber ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">CSV</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> [<span class="dt">String</span>]</span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a>getColumnByNumber columnIndex (<span class="dt">NumberedCsv</span> rows) <span class="ot">=</span></span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- Fail if a column is missing from any row</span></span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a>    <span class="fu">traverse</span> (safeIndex columnIndex) rows</span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a>getColumnByNumber columnIndex (<span class="dt">NamedCsv</span> _ rows) <span class="ot">=</span></span>
<span id="cb8-12"><a href="#cb8-12" aria-hidden="true" tabindex="-1"></a>    <span class="fu">traverse</span> (safeIndex columnIndex) rows</span>
<span id="cb8-13"><a href="#cb8-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-14"><a href="#cb8-14" aria-hidden="true" tabindex="-1"></a><span class="co">-- Get all values of a column by the column name</span></span>
<span id="cb8-15"><a href="#cb8-15" aria-hidden="true" tabindex="-1"></a><span class="ot">getColumnByName ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">CSV</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> [<span class="dt">String</span>]</span>
<span id="cb8-16"><a href="#cb8-16" aria-hidden="true" tabindex="-1"></a>getColumnByName  _ (<span class="dt">NumberedCsv</span> _) <span class="ot">=</span> <span class="dt">Nothing</span></span>
<span id="cb8-17"><a href="#cb8-17" aria-hidden="true" tabindex="-1"></a>getColumnByName columnName (<span class="dt">NamedCsv</span> headers rows) <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb8-18"><a href="#cb8-18" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- Get the column index from the headers</span></span>
<span id="cb8-19"><a href="#cb8-19" aria-hidden="true" tabindex="-1"></a>    columnIndex <span class="ot">&lt;-</span> elemIndex columnName headers</span>
<span id="cb8-20"><a href="#cb8-20" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- Lookup the column from each row, failing if the column is missing from any row</span></span>
<span id="cb8-21"><a href="#cb8-21" aria-hidden="true" tabindex="-1"></a>    <span class="fu">traverse</span> (safeIndex columnIndex) rows</span></code></pre></div>
<p>This works of course, but it feels like we're programming in a
<strong>dynamic language</strong>! If you try to get a column <strong>by
name</strong> from a <strong>numbered CSV</strong> we know it will
ALWAYS fail, so why do we even allow the programmer to express that?
Certainly it should fail to typecheck instead.</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> decode <span class="dt">True</span> input <span class="op">&gt;&gt;=</span> getColumnByName <span class="st">&quot;Name&quot;</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> [<span class="st">&quot;Luke&quot;</span>,<span class="st">&quot;Leia&quot;</span>,<span class="st">&quot;Han&quot;</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="co">-- If we index a numbered CSV by name we&#39;ll get &#39;Nothing&#39; no matter what.</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> decode <span class="dt">False</span> input <span class="op">&gt;&gt;=</span> getColumnByName <span class="st">&quot;Name&quot;</span></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a><span class="dt">Nothing</span></span></code></pre></div>
<p>The problem here becomes even more pronounced when we write a
function like <code>getHeaders</code>. Which type signature should it
have?</p>
<p>This one:</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">getHeaders ::</span> <span class="dt">CSV</span> <span class="ot">-&gt;</span> [<span class="dt">String</span>]</span></code></pre></div>
<p>Or this one?</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">getHeaders ::</span> <span class="dt">CSV</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> [<span class="dt">String</span>]</span></code></pre></div>
<p>We could pick the first signature and always return the <em>empty
list</em> when someone mistakenly tries to get the headers of a numbered
CSV, but that seems a bit disingenuous; It's common to check the number
of columns in a CSV by counting the headers, and that approach would
imply that every numbered CSV has zero columns! If we go with the latter
signature it properly handles the failure case of calling
<code>getHeaders</code> on a numbered CSV, but we know that getting the
headers from a <code>NamedCSV</code> should <strong>never</strong> fail,
so in that case we're adding a bit of unnecessary overhead, all callers
will have to unwrap <code>Maybe</code> in that case no matter what
😬.</p>
<p>In order to fix this issue we'll need to go back to the drawing board
and see if we can keep track of whether our CSV has headers inside its
<strong>type</strong>.</p>
<h2 id="differentiating-csvs-using-types">Differentiating CSVs using
types</h2>
<p>I promise we'll get to using GADTs soon, but let's look at the
"simple" approach that I suspect most folks would try next and see where
it ends up so we can motivate the need for <strong>GADTs</strong>.</p>
<p>The goal is to prevent the user from calling "header" specific
methods on a CSV that doesn't have headers. The simplest thing to do is
provide two separate <code>decode</code> methods which return completely
different concrete result types:</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">decodeWithoutHeaders ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> [[<span class="dt">String</span>]]</span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a><span class="ot">decodeWithHeaders    ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> ([<span class="dt">String</span>], [[<span class="dt">String</span>]])</span></code></pre></div>
<p>Next we could implement:</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">getColumnByNumber ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> [[<span class="dt">String</span>]]             <span class="ot">-&gt;</span> <span class="dt">Maybe</span> [<span class="dt">String</span>]</span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="ot">getColumnByName   ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> ([<span class="dt">String</span>], [[<span class="dt">String</span>]]) <span class="ot">-&gt;</span> <span class="dt">Maybe</span> [<span class="dt">String</span>]</span></code></pre></div>
<p>This solves the problem at hand, if we decode a CSV without headers
we'll have a <code>[[String]]</code> value, and can't pass that into
<code>getColumnByName</code>. However there's an issue with this
approach: We can no longer use <code>getColumnByNumber</code> to get a
column by number on a CSV which has headers.</p>
<p>We could, of course we could could <code>snd</code> it into
<code>[[String]]</code> first, but converting between types everywhere
is annoying and also means we <strong>can't write code which is
polymorphic over both kinds of CSV</strong>. Ideally we would have a
single set of functions which was <em>smart</em> about which type of CSV
so it could do <strong>the right thing</strong> while also ensuring
type-safety.</p>
<p>Some readers are likely thinking "Hrmmm, a <strong>group of functions
polymorphic over a type</strong>? Sounds like a
<strong>typeclass</strong>!" and you'd be right! As it turns out, this
is roughly the approach that the popular <a
href="https://hackage.haskell.org/package/cassava"><code>cassava</code></a>
library takes to its library design.</p>
<p><code>cassava</code> is more <strong>record-centric</strong> than the
library we're designing, so it provides separate typeclasses for named
and unnamed record types; <code>ToNamedRecord</code>,
<code>FromNamedRecord</code>, and their numbered variants
<code>ToRecord</code> and <code>FromRecord</code>. In our case we'll be
defining different typeclass instances for the CSV itself.</p>
<p>Here's the rough idea:</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 TypeFamilies #-}</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE FlexibleInstances #-}</span></span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE InstanceSigs #-}</span></span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">IsCSV</span> c <span class="kw">where</span></span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- A type family to specify the &quot;indexing&quot; type of the CSV</span></span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">type</span> <span class="dt">Index</span><span class="ot"> c ::</span> <span class="dt">Type</span></span>
<span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- Try parsing a CSV of the appropriate type</span></span>
<span id="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a><span class="ot">  decode ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> c</span>
<span id="cb14-10"><a href="#cb14-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-11"><a href="#cb14-11" aria-hidden="true" tabindex="-1"></a><span class="ot">  getColumnByIndex  ::</span> <span class="dt">Index</span> c <span class="ot">-&gt;</span> c <span class="ot">-&gt;</span> <span class="dt">Maybe</span> [<span class="dt">String</span>]</span>
<span id="cb14-12"><a href="#cb14-12" aria-hidden="true" tabindex="-1"></a><span class="ot">  getColumnByNumber ::</span> <span class="dt">Int</span>     <span class="ot">-&gt;</span> c <span class="ot">-&gt;</span> <span class="dt">Maybe</span> [<span class="dt">String</span>]</span>
<span id="cb14-13"><a href="#cb14-13" aria-hidden="true" tabindex="-1"></a><span class="ot">  getRow ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Row</span> c</span></code></pre></div>
<p>Let's talk about the <code>Index</code> type family. Numbered CSVs
are indexed by an <code>Int</code>, while Named CSVs are indexed by a
String. We can use the <code>Index</code> <em>associated type
family</em> to specify a different type of Index for each typeclass
instance.</p>
<p>The headerless CSV is pretty easy to implement:</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="kw">instance</span> <span class="dt">IsCSV</span> [[<span class="dt">String</span>]] <span class="kw">where</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">type</span> <span class="dt">Index</span> [[<span class="dt">String</span>]] <span class="ot">=</span> <span class="dt">Int</span></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- You can re-purpose the earlier decoder here.</span></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a>  decode <span class="ot">=</span> <span class="op">...</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="co">-- The Index type is Int, so we index by Int here:</span></span>
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a><span class="ot">  getColumnByIndex ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> [[<span class="dt">String</span>]] <span class="ot">-&gt;</span> <span class="dt">Maybe</span> [<span class="dt">String</span>]</span>
<span id="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a>  getColumnByIndex n rows <span class="ot">=</span> <span class="fu">traverse</span> (safeIndex n) rows</span>
<span id="cb15-9"><a href="#cb15-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-10"><a href="#cb15-10" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- Since the index is an Int we can re-use the other implementation</span></span>
<span id="cb15-11"><a href="#cb15-11" aria-hidden="true" tabindex="-1"></a><span class="ot">  getColumnByNumber ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> [[<span class="dt">String</span>]] <span class="ot">-&gt;</span> <span class="dt">Maybe</span> [<span class="dt">String</span>]</span>
<span id="cb15-12"><a href="#cb15-12" aria-hidden="true" tabindex="-1"></a>  getColumnByNumber <span class="ot">=</span> getColumnByIndex</span></code></pre></div>
<p>Now an instance for a CSV with headers:</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="kw">instance</span> <span class="dt">IsCSV</span> ([<span class="dt">String</span>], [[<span class="dt">String</span>]]) <span class="kw">where</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- We can index a column by the header name</span></span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">type</span> <span class="dt">Index</span> ([<span class="dt">String</span>], [[<span class="dt">String</span>]]) <span class="ot">=</span> <span class="dt">String</span></span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a>  decode <span class="ot">=</span> <span class="op">...</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="co">-- The &#39;index&#39; for this type of CSV is a String</span></span>
<span id="cb16-7"><a href="#cb16-7" aria-hidden="true" tabindex="-1"></a><span class="ot">  getColumnByIndex ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> ([<span class="dt">String</span>], [[<span class="dt">String</span>]]) <span class="ot">-&gt;</span> <span class="dt">Maybe</span> [<span class="dt">String</span>]</span>
<span id="cb16-8"><a href="#cb16-8" aria-hidden="true" tabindex="-1"></a>  getColumnByIndex columnName (headers, rows) <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb16-9"><a href="#cb16-9" aria-hidden="true" tabindex="-1"></a>    columnIndex <span class="ot">&lt;-</span> elemIndex columnName headers</span>
<span id="cb16-10"><a href="#cb16-10" aria-hidden="true" tabindex="-1"></a>    <span class="fu">traverse</span> (safeIndex columnIndex) rows</span>
<span id="cb16-11"><a href="#cb16-11" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- We can still index a Headered CSV by column number</span></span>
<span id="cb16-12"><a href="#cb16-12" aria-hidden="true" tabindex="-1"></a><span class="ot">  getColumnByNumber ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> ([<span class="dt">String</span>], [[<span class="dt">String</span>]]) <span class="ot">-&gt;</span> <span class="dt">Maybe</span> [<span class="dt">String</span>]</span>
<span id="cb16-13"><a href="#cb16-13" aria-hidden="true" tabindex="-1"></a>  getColumnByNumber n <span class="ot">=</span> getColumnByNumber n <span class="op">.</span> <span class="fu">snd</span></span></code></pre></div>
<p>This works out pretty well, here's how it looks to use it:</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="op">&gt;&gt;&gt;</span> decode input <span class="op">&gt;&gt;=</span> getColumnByIndex (<span class="st">&quot;Name&quot;</span><span class="ot"> ::</span> <span class="dt">String</span>)</span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a><span class="op">&lt;</span>interactive<span class="op">&gt;:</span><span class="dv">99</span><span class="op">:</span><span class="dv">36</span><span class="op">:</span> <span class="fu">error</span><span class="op">:</span></span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a>    • <span class="dt">Couldn&#39;t</span> match <span class="kw">type</span> ‘<span class="dt">Index</span> c0’ with ‘<span class="dt">String</span>’</span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Expected</span> <span class="kw">type</span><span class="op">:</span> <span class="dt">Index</span> c0</span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Actual</span> <span class="kw">type</span><span class="op">:</span> <span class="dt">String</span></span>
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a>      <span class="dt">The</span> <span class="kw">type</span> variable ‘c0’ is ambiguous</span>
<span id="cb17-7"><a href="#cb17-7" aria-hidden="true" tabindex="-1"></a>    • <span class="dt">In</span> the first argument <span class="kw">of</span> ‘getColumnByIndex’, namely</span>
<span id="cb17-8"><a href="#cb17-8" aria-hidden="true" tabindex="-1"></a>        ‘<span class="st">&quot;Name&quot;</span>’</span>
<span id="cb17-9"><a href="#cb17-9" aria-hidden="true" tabindex="-1"></a>      <span class="dt">In</span> the second argument <span class="kw">of</span> ‘(<span class="op">&gt;&gt;=</span>)’, namely</span>
<span id="cb17-10"><a href="#cb17-10" aria-hidden="true" tabindex="-1"></a>        ‘getColumnByIndex <span class="st">&quot;Name&quot;</span>’</span>
<span id="cb17-11"><a href="#cb17-11" aria-hidden="true" tabindex="-1"></a>      <span class="dt">In</span> the expression<span class="op">:</span></span>
<span id="cb17-12"><a href="#cb17-12" aria-hidden="true" tabindex="-1"></a>        decode input <span class="op">&gt;&gt;=</span> getColumnByIndex <span class="st">&quot;Name&quot;</span></span></code></pre></div>
<p>Uh oh... one issue with type classes is that GHC might not know which
which instance to use in certain situations!</p>
<p>We can help out GHC with a type hint, but it's a bit annoying and the
error message isn't always so clear!</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="op">&gt;&gt;&gt;</span> decode <span class="op">@</span>([<span class="dt">String</span>], [[<span class="dt">String</span>]]) input <span class="op">&gt;&gt;=</span> getColumnByIndex <span class="st">&quot;Name&quot;</span></span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> [<span class="st">&quot;Luke&quot;</span>,<span class="st">&quot;Leia&quot;</span>,<span class="st">&quot;Han&quot;</span>]</span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a><span class="co">-- Or we can define a type alias to clean it up a smidge</span></span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="kw">type</span> <span class="dt">Named</span> <span class="ot">=</span> ([<span class="dt">String</span>], [[<span class="dt">String</span>]])</span>
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> decode <span class="op">@</span><span class="dt">Named</span> input <span class="op">&gt;&gt;=</span> getColumnByIndex <span class="st">&quot;Name&quot;</span></span>
<span id="cb18-7"><a href="#cb18-7" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> [<span class="st">&quot;Luke&quot;</span>,<span class="st">&quot;Leia&quot;</span>,<span class="st">&quot;Han&quot;</span>]</span></code></pre></div>
<p>This works out okay but it's unintuitive to users to <em>need</em> a
type annotation. Let's take a look at how GADTs can allow us to
encourage better error messages while also making it easier to read, and
reduce the amount of boilerplate required.</p>
<h2 id="the-gadt-approach">The GADT approach</h2>
<p>Before we use them for CSVs let's get a quick primer on GADTs, if
you're well-acquainted already feel free to skip to the next
section.</p>
<p>GADTs, a.k.a. <strong>Generalized Abstract Data Types</strong>, bring
a few upgrades over regular Haskell <code>data</code> types. Just in
case you haven't seen one before, let's compare the regular
<code>Maybe</code> definition to its GADT version.</p>
<p>Here's how <code>Maybe</code> is written using standard
<code>data</code> syntax:</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">data</span> <span class="dt">Maybe</span> a <span class="ot">=</span></span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Nothing</span></span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">Just</span> a</span></code></pre></div>
<p>When we turn on <code>GADTs</code> we can write the exact same type
like this instead:</p>
<div class="sourceCode" id="cb20"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Maybe</span> a <span class="kw">where</span></span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Nothing</span><span class="ot"> ::</span> <span class="dt">Maybe</span> a</span>
<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Just</span><span class="ot"> ::</span> a <span class="ot">-&gt;</span> <span class="dt">Maybe</span> a</span></code></pre></div>
<p>This slightly different syntax, which looks a bit foreign at first,
is really just spelling out the type of constructors as though they were
functions!</p>
<p>Compare the definition with the type of each constructor:</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="op">&gt;&gt;&gt;</span> <span class="op">:</span>t <span class="dt">Nothing</span></span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Nothing</span><span class="ot"> ::</span> <span class="dt">Maybe</span> a</span>
<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="op">:</span>t <span class="dt">Just</span></span>
<span id="cb21-4"><a href="#cb21-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span><span class="ot"> ::</span> a <span class="ot">-&gt;</span> <span class="dt">Maybe</span> a</span></code></pre></div>
<p>Each argument to the function represents a "slot" in the
constructor.</p>
<p>But of course there's more than just the definition syntax! Why use
GADTs? They bring a few upgrades over regular <code>data</code>
definitions. GADTs are most often used for their ability to
<strong>include constraints over polymorphic types</strong> in their
constructor definitions. This means you can write a type like this:</p>
<div class="sourceCode" id="cb22"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE GADTs #-}</span></span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">HasEq</span> a <span class="kw">where</span></span>
<span id="cb22-4"><a href="#cb22-4" aria-hidden="true" tabindex="-1"></a>  <span class="dt">HasEq</span><span class="ot"> ::</span> <span class="dt">Eq</span> a <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">HasEq</span> a</span></code></pre></div>
<p>Where the <code>Eq a</code> constraint gets "<em>baked in</em>" to
the constructor such that we can then write a function 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">checkEq ::</span> <span class="dt">HasEq</span> a <span class="ot">-&gt;</span> <span class="dt">HasEq</span> a <span class="ot">-&gt;</span> <span class="dt">Bool</span></span>
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a>checkEq (<span class="dt">HasEq</span> one) (<span class="dt">HasEq</span> two) <span class="ot">=</span> one <span class="op">==</span> two</span></code></pre></div>
<p>We don't need to include an <code>Eq a</code> constraint in the type
because GHC knows that it's impossible to construct <code>HasEq</code>
without one, and it carries that constraint <em>with the value</em> in
the constructor!</p>
<p>In this post we'll be using a technique which follows (perhaps
unintuitively) from this; take a look at this type:</p>
<div class="sourceCode" id="cb24"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">IntOrString</span> a <span class="kw">where</span></span>
<span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a>  <span class="dt">AnInt</span><span class="ot"> ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">IntOrString</span> <span class="dt">Int</span></span>
<span id="cb24-3"><a href="#cb24-3" aria-hidden="true" tabindex="-1"></a>  <span class="dt">AString</span><span class="ot"> ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">IntOrString</span> <span class="dt">String</span></span></code></pre></div>
<p>Notice how each constructor fills in a value for the polymorphic
<code>a</code> type? E.g. <code>IntOrString Int</code> where
<code>a</code> is now <code>Int</code>? GHC can use this information
when it's matching constructors to types. It lets us write a silly
function like this:</p>
<div class="sourceCode" id="cb25"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a><span class="fu">toInt</span><span class="ot"> ::</span> <span class="dt">IntOrString</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Int</span></span>
<span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a><span class="fu">toInt</span> (<span class="dt">AnInt</span> n) <span class="ot">=</span> n</span></code></pre></div>
<p>Again, this doesn't seem too interesting, but there's something
unique here. It <strong>looks</strong> like I've got an incomplete
implementation for <code>toInt</code>; it lacks a case for the
<code>AString</code> constructor! However, GHC is smart enough to
realize that any values produced using the <code>AString</code>
constructor MUST have the type <code>IntOrString String</code>, and so
it knows that I don't need to handle that pattern here, in fact if I
<strong>do</strong> provide a pattern match on it, GHC will display an
"inaccessible code" warning!</p>
<p>The really nifty thing is that we can choose whether to be
polymorphic over the argument or not in each function definition and GHC
will know which patterns can appear in each case. This means we can just
as easily write this function:</p>
<div class="sourceCode" id="cb26"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a><span class="ot">toString ::</span> <span class="dt">IntOrString</span> a <span class="ot">-&gt;</span> <span class="dt">String</span></span>
<span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a>toString (<span class="dt">AnInt</span> n) <span class="ot">=</span> <span class="fu">show</span> n</span>
<span id="cb26-3"><a href="#cb26-3" aria-hidden="true" tabindex="-1"></a>toString (<span class="dt">AString</span> s) <span class="ot">=</span> s</span></code></pre></div>
<p>Since <code>a</code> might be <code>Int</code> OR <code>String</code>
we need to provide an implementation for <strong>both</strong>
constructors here, but note that EVEN in the polymorphic case we still
know the type of the value stored in each constructor, we know that
<code>AnInt</code> holds an <code>Int</code> and <code>AString</code>
holds a <code>String</code>.</p>
<p>If you're a bit confused, or just generally unconvinced, try writing
<code>IntOrString</code>, <code>toInt</code> and <code>toString</code>
in a type-safe manner using a regular <code>data</code> constructor,
it's a good exercise (it won't work 😉). Make sure you have
<code>-Wall</code> turned on as well. .</p>
<h2 id="gadts-and-csvs">GADTs and CSVs</h2>
<p>After that diversion, let's dive into writing a new CSV type!</p>
<div class="sourceCode" id="cb27"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE GADTs #-}</span></span>
<span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE StandaloneDeriving #-}</span></span>
<span id="cb27-3"><a href="#cb27-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb27-4"><a href="#cb27-4" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">CSV</span> <span class="fu">index</span> <span class="kw">where</span></span>
<span id="cb27-5"><a href="#cb27-5" aria-hidden="true" tabindex="-1"></a>  <span class="dt">NamedCsv</span><span class="ot">    ::</span> [<span class="dt">String</span>] <span class="ot">-&gt;</span> [[<span class="dt">String</span>]] <span class="ot">-&gt;</span> <span class="dt">CSV</span> <span class="dt">String</span></span>
<span id="cb27-6"><a href="#cb27-6" aria-hidden="true" tabindex="-1"></a>  <span class="dt">NumberedCsv</span><span class="ot"> ::</span>             [[<span class="dt">String</span>]] <span class="ot">-&gt;</span> <span class="dt">CSV</span> <span class="dt">Int</span></span>
<span id="cb27-7"><a href="#cb27-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb27-8"><a href="#cb27-8" aria-hidden="true" tabindex="-1"></a><span class="co">-- A side-effect of using GADTs is that we need to use standalone deriving </span></span>
<span id="cb27-9"><a href="#cb27-9" aria-hidden="true" tabindex="-1"></a><span class="co">-- for our instances.</span></span>
<span id="cb27-10"><a href="#cb27-10" aria-hidden="true" tabindex="-1"></a><span class="kw">deriving</span> <span class="kw">instance</span> <span class="dt">Show</span> (<span class="dt">CSV</span> i)</span>
<span id="cb27-11"><a href="#cb27-11" aria-hidden="true" tabindex="-1"></a><span class="kw">deriving</span> <span class="kw">instance</span> <span class="dt">Eq</span>   (<span class="dt">CSV</span> i)</span></code></pre></div>
<p>This type has two constructors, one for a CSV with headers and one
without. We're specifying a polymorphic <code>index</code> type variable
and saying that CSVs with headers are specifically indexed by
<code>String</code> and CSVs without headers are indexed by
<code>Int</code>. Notice that it's okay for us to specify a specific
type for the <code>index</code> parameter even though it's a
phantom-type (i.e. we don't actually store the <code>index</code> type
inside our structure anywhere).</p>
<p>Let's implement our CSV functions again and see how they look.</p>
<p>We still need the end-user to specify whether to parse headers or
not, but we can use another <strong>GADT</strong> to reflect their
choice in the type, and propagate that to the resulting CSV. Here's what
a CSV selector type looks like where each constructor carries some type
information with it (i.e. whether the resulting CSV is either String or
Int indexed).</p>
<div class="sourceCode" id="cb28"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb28-1"><a href="#cb28-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">CSVType</span> i <span class="kw">where</span></span>
<span id="cb28-2"><a href="#cb28-2" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Named</span><span class="ot"> ::</span> <span class="dt">CSVType</span> <span class="dt">String</span></span>
<span id="cb28-3"><a href="#cb28-3" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Numbered</span><span class="ot"> ::</span> <span class="dt">CSVType</span> <span class="dt">Int</span></span>
<span id="cb28-4"><a href="#cb28-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb28-5"><a href="#cb28-5" aria-hidden="true" tabindex="-1"></a><span class="kw">deriving</span> <span class="kw">instance</span> <span class="dt">Show</span> (<span class="dt">CSVType</span> i)</span>
<span id="cb28-6"><a href="#cb28-6" aria-hidden="true" tabindex="-1"></a><span class="kw">deriving</span> <span class="kw">instance</span> <span class="dt">Eq</span> (<span class="dt">CSVType</span> i)</span></code></pre></div>
<p>Now we can write <code>decode</code> like this:</p>
<div class="sourceCode" id="cb29"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb29-1"><a href="#cb29-1" aria-hidden="true" tabindex="-1"></a><span class="ot">decode ::</span> <span class="dt">CSVType</span> i <span class="ot">-&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> (<span class="dt">CSV</span> i)</span>
<span id="cb29-2"><a href="#cb29-2" aria-hidden="true" tabindex="-1"></a>decode <span class="dt">Named</span> s <span class="ot">=</span> <span class="kw">case</span> splitOn <span class="ch">&#39;,&#39;</span> <span class="op">&lt;$&gt;</span> <span class="fu">lines</span> s <span class="kw">of</span></span>
<span id="cb29-3"><a href="#cb29-3" aria-hidden="true" tabindex="-1"></a>    (h<span class="op">:</span>xs) <span class="ot">-&gt;</span> <span class="dt">Just</span> <span class="op">$</span> <span class="dt">NamedCsv</span> h xs</span>
<span id="cb29-4"><a href="#cb29-4" aria-hidden="true" tabindex="-1"></a>    _ <span class="ot">-&gt;</span> <span class="dt">Nothing</span></span>
<span id="cb29-5"><a href="#cb29-5" aria-hidden="true" tabindex="-1"></a>decode <span class="dt">Numbered</span> s <span class="ot">=</span> <span class="dt">Just</span> <span class="op">.</span> <span class="dt">NumberedCsv</span> <span class="op">.</span> <span class="fu">fmap</span> (splitOn <span class="ch">&#39;,&#39;</span>) <span class="op">.</span> <span class="fu">lines</span> <span class="op">$</span> s</span></code></pre></div>
<p>By accepting <code>CSVType</code> as an argument it acts as a proxy
for the type information we need. We can provide then provide a separate
implementation for each csv-type easily, and the index type provided on
the <code>CSVType</code> option is propagated to the result, thus
determining the type of the output CSV too!</p>
<p>Now for <code>getColumnByIndex</code> and
<code>getColumnByNumber</code>; in the typeclass version we needed to
provide an implementation for each class instance, using GADTs we can
collapse everything down to a single implementation for function.</p>
<p>Here's <code>getColumnByIndex</code>:</p>
<div class="sourceCode" id="cb30"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb30-1"><a href="#cb30-1" aria-hidden="true" tabindex="-1"></a><span class="ot">getColumnByIndex ::</span> i <span class="ot">-&gt;</span> <span class="dt">CSV</span> i <span class="ot">-&gt;</span> <span class="dt">Maybe</span> [<span class="dt">String</span>]</span>
<span id="cb30-2"><a href="#cb30-2" aria-hidden="true" tabindex="-1"></a>getColumnByIndex  columnName (<span class="dt">NamedCsv</span> headers rows) <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb30-3"><a href="#cb30-3" aria-hidden="true" tabindex="-1"></a>    columnIndex <span class="ot">&lt;-</span> elemIndex columnName headers</span>
<span id="cb30-4"><a href="#cb30-4" aria-hidden="true" tabindex="-1"></a>    <span class="fu">traverse</span> (safeIndex columnIndex) rows</span>
<span id="cb30-5"><a href="#cb30-5" aria-hidden="true" tabindex="-1"></a>getColumnByIndex n (<span class="dt">NumberedCsv</span> rows) <span class="ot">=</span> <span class="fu">traverse</span> (safeIndex n) rows</span></code></pre></div>
<p>The type signature says, if you give me the index type which matches
the index to the CSV you provide, I can get you that column if it
exists. It's smarter than it looks!</p>
<p>Even though the GADT constructor comes after the first argument, by
pattern matching on it we can determine the type of <code>i</code>, and
we then know that the first argument must match that <code>i</code>
type. So when we match on <code>NamedCsv</code> the first argument is a
<code>String</code>, and when we match on <code>NumberedCsv</code> it's
guaranteed to be an <code>Int</code></p>
<p>In the original "simple" CSV implementation you could try indexing
into a numbered CSV with a <code>String</code> header and it would
always return a <code>Nothing</code>, now it's actually a type error;
we've prevented a whole failure mode!</p>
<div class="sourceCode" id="cb31"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb31-1"><a href="#cb31-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- Decode our input into a CSV with numbered columns</span></span>
<span id="cb31-2"><a href="#cb31-2" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="kw">let</span> <span class="dt">Just</span> result <span class="ot">=</span> decode <span class="dt">Numbered</span> input</span>
<span id="cb31-3"><a href="#cb31-3" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> result</span>
<span id="cb31-4"><a href="#cb31-4" aria-hidden="true" tabindex="-1"></a><span class="dt">NumberedCsv</span> [</span>
<span id="cb31-5"><a href="#cb31-5" aria-hidden="true" tabindex="-1"></a>  [<span class="st">&quot;Name&quot;</span>,<span class="st">&quot;Age&quot;</span>,<span class="st">&quot;Home&quot;</span>],</span>
<span id="cb31-6"><a href="#cb31-6" aria-hidden="true" tabindex="-1"></a>  [<span class="st">&quot;Luke&quot;</span>,<span class="st">&quot;19&quot;</span>,<span class="st">&quot;Tatooine&quot;</span>],</span>
<span id="cb31-7"><a href="#cb31-7" aria-hidden="true" tabindex="-1"></a>  [<span class="st">&quot;Leia&quot;</span>,<span class="st">&quot;19&quot;</span>,<span class="st">&quot;Alderaan&quot;</span>],</span>
<span id="cb31-8"><a href="#cb31-8" aria-hidden="true" tabindex="-1"></a>  [<span class="st">&quot;Han&quot;</span>,<span class="st">&quot;32&quot;</span>,<span class="st">&quot;Corellia&quot;</span>]]</span>
<span id="cb31-9"><a href="#cb31-9" aria-hidden="true" tabindex="-1"></a><span class="co">-- Here&#39;s what happens if we try to write the wrong index type!</span></span>
<span id="cb31-10"><a href="#cb31-10" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> getColumnByIndex <span class="st">&quot;Name&quot;</span> result</span>
<span id="cb31-11"><a href="#cb31-11" aria-hidden="true" tabindex="-1"></a>    • <span class="dt">Couldn&#39;t</span> match <span class="kw">type</span> ‘<span class="dt">Int</span>’ with ‘<span class="dt">String</span>’</span>
<span id="cb31-12"><a href="#cb31-12" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Expected</span> <span class="kw">type</span><span class="op">:</span> <span class="dt">CSV</span> <span class="dt">String</span></span>
<span id="cb31-13"><a href="#cb31-13" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Actual</span> <span class="kw">type</span><span class="op">:</span> <span class="dt">CSV</span> <span class="dt">Int</span></span></code></pre></div>
<p>It works fine if provide an index which matches the way we
decoded:</p>
<div class="sourceCode" id="cb32"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb32-1"><a href="#cb32-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- By number using `Numbered`</span></span>
<span id="cb32-2"><a href="#cb32-2" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> decode <span class="dt">Numbered</span> input <span class="op">&gt;&gt;=</span> getColumnByIndex <span class="dv">0</span></span>
<span id="cb32-3"><a href="#cb32-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> [<span class="st">&quot;Name&quot;</span>,<span class="st">&quot;Luke&quot;</span>,<span class="st">&quot;Leia&quot;</span>,<span class="st">&quot;Han&quot;</span>]</span>
<span id="cb32-4"><a href="#cb32-4" aria-hidden="true" tabindex="-1"></a><span class="co">-- ...Or by header name using `Named`</span></span>
<span id="cb32-5"><a href="#cb32-5" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> decode <span class="dt">Named</span> input <span class="op">&gt;&gt;=</span> getColumnByIndex <span class="st">&quot;Name&quot;</span></span>
<span id="cb32-6"><a href="#cb32-6" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> [<span class="st">&quot;Luke&quot;</span>,<span class="st">&quot;Leia&quot;</span>,<span class="st">&quot;Han&quot;</span>]</span></code></pre></div>
<p>When indexing by number we can ignore the index type of the CSV
entirely, since we know we can index either a Named or Numbered CSV by
column number regardless.</p>
<div class="sourceCode" id="cb33"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb33-1"><a href="#cb33-1" aria-hidden="true" tabindex="-1"></a><span class="ot">getColumnByNumber ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">CSV</span> i <span class="ot">-&gt;</span> <span class="dt">Maybe</span> [<span class="dt">String</span>]</span>
<span id="cb33-2"><a href="#cb33-2" aria-hidden="true" tabindex="-1"></a>getColumnByNumber n (<span class="dt">NamedCsv</span> _ rows) <span class="ot">=</span> <span class="fu">traverse</span> (safeIndex n) rows</span>
<span id="cb33-3"><a href="#cb33-3" aria-hidden="true" tabindex="-1"></a>getColumnByNumber n (<span class="dt">NumberedCsv</span> rows) <span class="ot">=</span> <span class="fu">traverse</span> (safeIndex n) rows</span></code></pre></div>
<p>In an earlier attempt we ran into problems writing
<code>getHeaders</code>, since we <strong>knew</strong> intuitively that
it should always be safe to return the headers from a "Named" csv, but
we needed to introduce a <code>Maybe</code> into the type since we
couldn't be sure of the type of the CSV argument!</p>
<p>Now that the CSV has the index as part of the type we can solve that
handily by restricting the possible inputs the correct CSV type:</p>
<div class="sourceCode" id="cb34"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb34-1"><a href="#cb34-1" aria-hidden="true" tabindex="-1"></a><span class="ot">getHeaders ::</span> <span class="dt">CSV</span> <span class="dt">String</span> <span class="ot">-&gt;</span> [<span class="dt">String</span>]</span>
<span id="cb34-2"><a href="#cb34-2" aria-hidden="true" tabindex="-1"></a>getHeaders (<span class="dt">NamedCsv</span> headers _) <span class="ot">=</span> headers</span></code></pre></div>
<p>We don't need to match on <code>NumberedCsv</code>, since it has type
<code>CSV Int</code>, and that omission allows us to remove the need for
a <code>Maybe</code> from the signature. Pretty slick!</p>
<p>This is the brilliance of <strong>GADTs</strong> in this approach, we
can be general when we want to be general, or specific when we want to
be specific.</p>
<p>The interfaces provided by each approach look relatively similar at
the end of the day. The typeclass signatures have a fully polymorphic
variable with a type constraint AND a type family, whereas the GADT
signatures are simpler, including only a polymorphic index type, and the
consumers of the library won't need to know anything about GADTs in
order to use it.</p>
<p>The typeclass approach:</p>
<div class="sourceCode" id="cb35"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb35-1"><a href="#cb35-1" aria-hidden="true" tabindex="-1"></a><span class="ot">decode ::</span> <span class="dt">IsCSV</span> c <span class="ot">=&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> c</span>
<span id="cb35-2"><a href="#cb35-2" aria-hidden="true" tabindex="-1"></a><span class="ot">getColumnByIndex ::</span> <span class="dt">IsCSV</span> c <span class="ot">=&gt;</span> <span class="dt">Index</span> c <span class="ot">-&gt;</span> c <span class="ot">-&gt;</span> <span class="dt">Maybe</span> [<span class="dt">String</span>]</span>
<span id="cb35-3"><a href="#cb35-3" aria-hidden="true" tabindex="-1"></a><span class="ot">getColumnByNumber ::</span> <span class="dt">IsCSV</span> c <span class="ot">=&gt;</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> c <span class="ot">-&gt;</span> <span class="dt">Maybe</span> [<span class="dt">String</span>]</span>
<span id="cb35-4"><a href="#cb35-4" aria-hidden="true" tabindex="-1"></a><span class="ot">getHeaders ::</span> <span class="dt">IsCSV</span> c <span class="ot">=&gt;</span> c <span class="ot">-&gt;</span> <span class="dt">Maybe</span> [<span class="dt">String</span>]</span></code></pre></div>
<p>The GADT approach:</p>
<div class="sourceCode" id="cb36"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb36-1"><a href="#cb36-1" aria-hidden="true" tabindex="-1"></a><span class="ot">decode ::</span> <span class="dt">CSVType</span> i <span class="ot">-&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> (<span class="dt">CSV</span> i)</span>
<span id="cb36-2"><a href="#cb36-2" aria-hidden="true" tabindex="-1"></a><span class="ot">getColumnByIndex ::</span> i <span class="ot">-&gt;</span> <span class="dt">CSV</span> i <span class="ot">-&gt;</span> <span class="dt">Maybe</span> [<span class="dt">String</span>]</span>
<span id="cb36-3"><a href="#cb36-3" aria-hidden="true" tabindex="-1"></a><span class="ot">getColumnByNumber ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">CSV</span> i <span class="ot">-&gt;</span> <span class="dt">Maybe</span> [<span class="dt">String</span>]</span>
<span id="cb36-4"><a href="#cb36-4" aria-hidden="true" tabindex="-1"></a><span class="ot">getHeaders ::</span> <span class="dt">CSV</span> <span class="dt">String</span> <span class="ot">-&gt;</span> [<span class="dt">String</span>]</span></code></pre></div>
<p>Though similar, I find the GADT version easier to understand as a
consumer, everything you need to know is available to you, and you can
look up the <code>CSV</code> type to learn more about how to build one,
or which types are available.</p>
<p>The GADT types also result in simpler type errors when something goes
wrong.</p>
<p>Here's one common problem with the <strong>typeclass
approach</strong>, decode has a <strong>polymorphic result</strong> and
<code>getColumnByIndex</code> has a polymorphic argument, GHC can't
figure out what the intermediate type should be if we string them
together:</p>
<div class="sourceCode" id="cb37"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb37-1"><a href="#cb37-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> decode input <span class="op">&gt;&gt;=</span> getColumnByIndex <span class="st">&quot;Name&quot;</span></span>
<span id="cb37-2"><a href="#cb37-2" aria-hidden="true" tabindex="-1"></a>    • <span class="dt">Couldn&#39;t</span> match <span class="kw">type</span> ‘<span class="dt">Index</span> c0’ with ‘<span class="dt">String</span>’</span>
<span id="cb37-3"><a href="#cb37-3" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Expected</span> <span class="kw">type</span><span class="op">:</span> <span class="dt">Index</span> c0</span>
<span id="cb37-4"><a href="#cb37-4" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Actual</span> <span class="kw">type</span><span class="op">:</span> <span class="dt">String</span></span>
<span id="cb37-5"><a href="#cb37-5" aria-hidden="true" tabindex="-1"></a>      <span class="dt">The</span> <span class="kw">type</span> variable ‘c0’ is ambiguous</span>
<span id="cb37-6"><a href="#cb37-6" aria-hidden="true" tabindex="-1"></a>    • <span class="dt">In</span> the first argument <span class="kw">of</span> ‘getColumnByIndex’, namely</span>
<span id="cb37-7"><a href="#cb37-7" aria-hidden="true" tabindex="-1"></a>        ‘(<span class="st">&quot;Hi&quot;</span><span class="ot"> ::</span> <span class="dt">String</span>)’</span>
<span id="cb37-8"><a href="#cb37-8" aria-hidden="true" tabindex="-1"></a>      <span class="dt">In</span> the second argument <span class="kw">of</span> ‘(<span class="op">&gt;&gt;=</span>)’, namely</span>
<span id="cb37-9"><a href="#cb37-9" aria-hidden="true" tabindex="-1"></a>        ‘getColumnByIndex (<span class="st">&quot;Hi&quot;</span><span class="ot"> ::</span> <span class="dt">String</span>)’</span>
<span id="cb37-10"><a href="#cb37-10" aria-hidden="true" tabindex="-1"></a>      <span class="dt">In</span> the expression<span class="op">:</span></span>
<span id="cb37-11"><a href="#cb37-11" aria-hidden="true" tabindex="-1"></a>        decode input <span class="op">&gt;&gt;=</span> getColumnByIndex (<span class="st">&quot;Hi&quot;</span><span class="ot"> ::</span> <span class="dt">String</span>)</span></code></pre></div>
<p>We can fix this with an explicit type application, but that requires
us to know the underlying type that implements the instance.</p>
<div class="sourceCode" id="cb38"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb38-1"><a href="#cb38-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="kw">type</span> <span class="dt">Named</span> <span class="ot">=</span> ([<span class="dt">String</span>], [[<span class="dt">String</span>]])</span>
<span id="cb38-2"><a href="#cb38-2" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> decode <span class="op">@</span><span class="dt">Named</span> input <span class="op">&gt;&gt;=</span> getColumnByIndex <span class="st">&quot;Name&quot;</span></span>
<span id="cb38-3"><a href="#cb38-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> [<span class="st">&quot;Luke&quot;</span>,<span class="st">&quot;Leia&quot;</span>,<span class="st">&quot;Han&quot;</span>]</span></code></pre></div>
<p>If we mismatch the index type here, even when providing an explicit
type annotation, we get a slightly confusing error since it still
mentions a type family:</p>
<div class="sourceCode" id="cb39"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb39-1"><a href="#cb39-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> decode <span class="op">@</span><span class="dt">Named</span> input <span class="op">&gt;&gt;=</span> getColumnByIndex (<span class="dv">1</span><span class="ot"> ::</span> <span class="dt">Int</span>)</span>
<span id="cb39-2"><a href="#cb39-2" aria-hidden="true" tabindex="-1"></a>    • <span class="dt">Couldn&#39;t</span> match <span class="kw">type</span> ‘<span class="dt">Int</span>’ with ‘<span class="dt">String</span>’</span>
<span id="cb39-3"><a href="#cb39-3" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Expected</span> <span class="kw">type</span><span class="op">:</span> <span class="dt">Index</span> <span class="dt">Named</span></span>
<span id="cb39-4"><a href="#cb39-4" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Actual</span> <span class="kw">type</span><span class="op">:</span> <span class="dt">Int</span></span>
<span id="cb39-5"><a href="#cb39-5" aria-hidden="true" tabindex="-1"></a>    • <span class="dt">In</span> the first argument <span class="kw">of</span> ‘getColumnByIndex’, namely ‘(<span class="dv">1</span><span class="ot"> ::</span> <span class="dt">Int</span>)’</span>
<span id="cb39-6"><a href="#cb39-6" aria-hidden="true" tabindex="-1"></a>      <span class="dt">In</span> the second argument <span class="kw">of</span> ‘(<span class="op">&gt;&gt;=</span>)’, namely</span>
<span id="cb39-7"><a href="#cb39-7" aria-hidden="true" tabindex="-1"></a>        ‘getColumnByIndex (<span class="dv">1</span><span class="ot"> ::</span> <span class="dt">Int</span>)’</span>
<span id="cb39-8"><a href="#cb39-8" aria-hidden="true" tabindex="-1"></a>      <span class="dt">In</span> the expression<span class="op">:</span></span>
<span id="cb39-9"><a href="#cb39-9" aria-hidden="true" tabindex="-1"></a>        decode <span class="op">@</span><span class="dt">Named</span> input <span class="op">&gt;&gt;=</span> getColumnByIndex (<span class="dv">1</span><span class="ot"> ::</span> <span class="dt">Int</span>)</span></code></pre></div>
<p>Compare these to the errors generated by the GADT approach; first
we'll chain <code>decode</code> with <code>getColumnByIndex</code>:</p>
<div class="sourceCode" id="cb40"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb40-1"><a href="#cb40-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> decode <span class="dt">Named</span> input <span class="op">&gt;&gt;=</span> getColumnByIndex <span class="st">&quot;Name&quot;</span></span>
<span id="cb40-2"><a href="#cb40-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> [<span class="st">&quot;Luke&quot;</span>,<span class="st">&quot;Leia&quot;</span>,<span class="st">&quot;Han&quot;</span>]</span></code></pre></div>
<p>There's no ambiguity here! We only have a single CSV type to choose,
and the "index" type variable is fully determined by the
<code>Named</code> argument. Very nice!</p>
<p>What if we try to index by number instead?</p>
<div class="sourceCode" id="cb41"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb41-1"><a href="#cb41-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> decode <span class="dt">Named</span> input <span class="op">&gt;&gt;=</span> getColumnByIndex (<span class="dv">1</span><span class="ot"> ::</span> <span class="dt">Int</span>)</span>
<span id="cb41-2"><a href="#cb41-2" aria-hidden="true" tabindex="-1"></a><span class="fu">error</span><span class="op">:</span></span>
<span id="cb41-3"><a href="#cb41-3" aria-hidden="true" tabindex="-1"></a>    • <span class="dt">Couldn&#39;t</span> match <span class="kw">type</span> ‘<span class="dt">String</span>’ with ‘<span class="dt">Int</span>’</span>
<span id="cb41-4"><a href="#cb41-4" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Expected</span> <span class="kw">type</span><span class="op">:</span> <span class="dt">CSV</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> [<span class="dt">String</span>]</span>
<span id="cb41-5"><a href="#cb41-5" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Actual</span> <span class="kw">type</span><span class="op">:</span> <span class="dt">CSV</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> [<span class="dt">String</span>]</span>
<span id="cb41-6"><a href="#cb41-6" aria-hidden="true" tabindex="-1"></a>    • <span class="dt">In</span> the second argument <span class="kw">of</span> ‘(<span class="op">&gt;&gt;=</span>)’, namely</span>
<span id="cb41-7"><a href="#cb41-7" aria-hidden="true" tabindex="-1"></a>        ‘getColumnByIndex (<span class="dv">1</span><span class="ot"> ::</span> <span class="dt">Int</span>)’</span>
<span id="cb41-8"><a href="#cb41-8" aria-hidden="true" tabindex="-1"></a>      <span class="dt">In</span> the expression<span class="op">:</span></span>
<span id="cb41-9"><a href="#cb41-9" aria-hidden="true" tabindex="-1"></a>        decode <span class="dt">Named</span> input <span class="op">&gt;&gt;=</span> getColumnByIndex (<span class="dv">1</span><span class="ot"> ::</span> <span class="dt">Int</span>)</span>
<span id="cb41-10"><a href="#cb41-10" aria-hidden="true" tabindex="-1"></a>      <span class="dt">In</span> an equation for ‘it’<span class="op">:</span></span>
<span id="cb41-11"><a href="#cb41-11" aria-hidden="true" tabindex="-1"></a>          it <span class="ot">=</span> decode <span class="dt">Named</span> input <span class="op">&gt;&gt;=</span> getColumnByIndex (<span class="dv">1</span><span class="ot"> ::</span> <span class="dt">Int</span>)</span></code></pre></div>
<p>It clearly outlines the expected and actual types:</p>
<div class="sourceCode" id="cb42"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb42-1"><a href="#cb42-1" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Expected</span> <span class="kw">type</span><span class="op">:</span> <span class="dt">CSV</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> [<span class="dt">String</span>]</span>
<span id="cb42-2"><a href="#cb42-2" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Actual</span> <span class="kw">type</span><span class="op">:</span> <span class="dt">CSV</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> [<span class="dt">String</span>]</span></code></pre></div>
<p>Which should be enough for the user to spot their mistake and patch
it up.</p>
<h2 id="next-steps">Next steps</h2>
<p>Still unconvinced? Try taking it a step further!</p>
<p>Try writing <code>getRow</code> and <code>getColumn</code> functions
for both the typeclass and GADT approaches. The row that's returned
should support type-safe index by <code>String</code> or
<code>Int</code> depending on the type of the source CSV.</p>
<p>E.g. the GADT version should look like this:</p>
<div class="sourceCode" id="cb43"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb43-1"><a href="#cb43-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> decode <span class="dt">Named</span> input <span class="op">&gt;&gt;=</span> getRow <span class="dv">1</span> <span class="op">&gt;&gt;=</span> getColumn <span class="st">&quot;Name&quot;</span></span>
<span id="cb43-2"><a href="#cb43-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> <span class="st">&quot;Leia&quot;</span></span>
<span id="cb43-3"><a href="#cb43-3" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> decode <span class="dt">Numbered</span> input <span class="op">&gt;&gt;=</span> getRow <span class="dv">1</span> <span class="op">&gt;&gt;=</span> getColumn <span class="dv">0</span></span>
<span id="cb43-4"><a href="#cb43-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> <span class="st">&quot;Leia&quot;</span></span></code></pre></div>
<p>You'll likely run into a rough patch or two when specifying different
Row result types in the typeclass approach (but it's certainly possible,
good luck!)</p>
<h2 id="conclusion">Conclusion</h2>
<p>This was just a peek at how typeclasses and GADTs can
<em>sometimes</em> overlap in the design space. When trying to decide
whether to use GADTs or a typeclass for a given problem, try asking the
following question:</p>
<p>Will users of my library need to define instances for their own
datatypes?</p>
<p>If the answer is <strong>no</strong>, a GADT is often clearer,
cleaner, and has better type inference properties than the equivalent
typeclass approach!</p>
<p>For a more in-depth "real world" example of this technique in action
check out my <code>lens-csv</code> library. It provides lensy
combinators for interacting with either of named or numbered CSVs in a
streaming fashion, and uses the <strong>GADT</strong> approach to (I
believe) great effect.</p>
<p>Enjoy playing around!</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Virtual Record Fields Using Lenses</title>
      <link href="https://chrispenner.ca/posts/virtual-fields"/>
      <id>https://chrispenner.ca/posts/virtual-fields</id>
      <updated>2020-11-26T00:00:00Z</updated>
      <summary>Lenses are commonly used for getting and setting fields on records, but
they&#39;re actually much more adaptable than that! This post dives into the
idea of &#39;virtual fields&#39; using optics.</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/virtual-fields.jpg" alt="Virtual Record Fields Using Lenses">
              <p>The following blog post is a short excerpt from by book on optics: <a
href="https://leanpub.com/optics-by-example/c/virtual-fields">"Optics By
Example"</a>. If you learn something from the post you'll likely enjoy
the rest of the book too!</p>
<p>Optics by Example provides a comprehensive example-driven guide to
manipulating data with optics, covering Lenses, Traversals, Prisms,
Isos, as well as many design patterns and extension libraries.</p>
<p>As thanks for checking out the blog you can grab a copy on sale with
<a href="https://leanpub.com/optics-by-example/c/virtual-fields">this
link</a> until the end of 2020.</p>
<hr />
<p>Lenses are commonly used for getting and setting fields on records,
but they're actually much more adaptable than that! This post dives into
the idea of "virtual fields" using optics.</p>
<p>Virtual fields can can provide many benefits:</p>
<ul>
<li>They help you adapt to change in your modules and types without
breaking backwards-compatibility</li>
<li>Provide a uniform interface for "smart" getters and setters which
maintain data invariants.</li>
<li>Make your code more resilient to refactoring.</li>
</ul>
<p>Let's dive in!</p>
<h2 id="what-is-a-virtual-field">What is a virtual field</h2>
<p>To establish terms, I'll define a <strong>virtual field</strong> as
any piece of data we might be interested in which doesn't exist as a
concrete field in a given record definition. In languages like Java or
Python these are sometimes called "computed properties" or "managed
attributes".</p>
<p>Oftentimes we'll use virtual fields to present data from concrete
fields in a more convenient way, or to maintain certain invariants on
the concrete fields. Sometimes virtual fields combine several concrete
fields together, other times they're used to avoid introducing breaking
changes when refactoring the structure of the record.</p>
<p>No matter what you use them for, at the end of the day they're really
just normal lenses! Let's look at a concrete example.</p>
<h2 id="writing-a-virtual-field">Writing a virtual field</h2>
<p>Let's look at the following type:</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">data</span> <span class="dt">Temperature</span> <span class="ot">=</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Temperature</span> {<span class="ot"> _location ::</span> <span class="dt">String</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>                ,<span class="ot"> _celsius  ::</span> <span class="dt">Float</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="kw">deriving</span> (<span class="dt">Show</span>)</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>makeLenses &#39;<span class="dt">&#39;Temperature</span></span></code></pre></div>
<p>This generates the field lenses:</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">location ::</span> <span class="dt">Lens&#39;</span> <span class="dt">Temperature</span> <span class="dt">String</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="ot">celsius  ::</span> <span class="dt">Lens&#39;</span> <span class="dt">Temperature</span> <span class="dt">Float</span></span></code></pre></div>
<p>Which we can use to <strong>get</strong>, <strong>set</strong>, or
<strong>modify</strong> the temperature in Celsius like so:</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="op">&gt;&gt;&gt;</span> <span class="kw">let</span> temp <span class="ot">=</span> <span class="dt">Temperature</span> <span class="st">&quot;Berlin&quot;</span> <span class="fl">7.0</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> view celsius temp</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="fl">7.0</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="op">&gt;&gt;&gt;</span> set celsius <span class="fl">13.5</span> temp</span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a><span class="dt">Temperature</span> {_location <span class="ot">=</span> <span class="st">&quot;Berlin&quot;</span>, _celsius <span class="ot">=</span> <span class="fl">13.5</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 class="co">-- Bump the temperature up by 10 degrees Celsius</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> over celsius (<span class="op">+</span><span class="dv">10</span>) temp</span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a><span class="dt">Temperature</span> {_location <span class="ot">=</span> <span class="st">&quot;Berlin&quot;</span>, _celsius <span class="ot">=</span> <span class="fl">17.0</span>}</span></code></pre></div>
<p>Now what about our American colleagues who'd prefer
<strong>Fahrenheit</strong>? It's easy enough to write a function which
converts <strong>Celsius</strong> to <strong>Fahrenheit</strong> and
call that on the result of <code>celsius</code>, but we'd still need to
<strong>set</strong> new temperatures in <strong>Celsius</strong>! How
can we avoid this dissonance between units?</p>
<p>First we'll define our conversion functions back and forth, nothing
too interesting there, if I'm honest I just stole the formulas from
wikipedia:</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">celsiusToFahrenheit ::</span> <span class="dt">Float</span> <span class="ot">-&gt;</span> <span class="dt">Float</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>celsiusToFahrenheit c <span class="ot">=</span> (c <span class="op">*</span> (<span class="dv">9</span><span class="op">/</span><span class="dv">5</span>)) <span class="op">+</span> <span class="dv">32</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 class="ot">fahrenheitToCelsius ::</span> <span class="dt">Float</span> <span class="ot">-&gt;</span> <span class="dt">Float</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>fahrenheitToCelsius f <span class="ot">=</span> (f <span class="op">-</span> <span class="dv">32</span>) <span class="op">*</span> (<span class="dv">5</span><span class="op">/</span><span class="dv">9</span>)</span></code></pre></div>
<p>Here's <em>one way</em> we could get and set using Fahrenheit:</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> temp <span class="ot">=</span> <span class="dt">Temperature</span> <span class="st">&quot;Berlin&quot;</span> <span class="fl">7.0</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- View temp in Berlin in Fahrenheit </span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> celsiusToFahrenheit <span class="op">.</span> view celsius temp</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="fl">44.6</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="co">-- Set temperature to 56.3 Fahrenheit</span></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> set celsius (fahrenheitToCelsius <span class="fl">56.3</span>) temp</span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a><span class="dt">Temperature</span> {_location <span class="ot">=</span> <span class="st">&quot;Berlin&quot;</span>, _celsius <span class="ot">=</span> <span class="fl">13.5</span>}</span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a><span class="co">-- Bump the temp up by 18 degrees Fahrenheit</span></span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> over celsius (fahrenheitToCelsius <span class="op">.</span> (<span class="op">+</span><span class="dv">18</span>) <span class="op">.</span> celsiusToFahrenheit) temp</span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a><span class="dt">Temperature</span> {_location <span class="ot">=</span> <span class="st">&quot;Berlin&quot;</span>, _celsius <span class="ot">=</span> <span class="fl">17.0</span>}</span></code></pre></div>
<p>The first two aren't <strong>too</strong> bad, but the
<code>over</code> example is getting a bit clunky and error prone! It's
hard to see what's going on, and since every type is <code>Float</code>
it'd be easy to forget or misplace one of our conversions.</p>
<p>If we instead encode the <strong>Fahrenheit</strong> version of the
temperature as a <strong>virtual field</strong> using optics we gain
improved usability, cleaner code, and avoid a lot of possible
mistakes.</p>
<p>Let's see what that looks like.</p>
<p>We can write a <code>fahrenheit</code> lens in terms of the existing
<code>celsius</code> lens! We embed the back-and-forth conversions into
the lens itself.</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">fahrenheit ::</span> <span class="dt">Lens&#39;</span> <span class="dt">Temperature</span> <span class="dt">Float</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>fahrenheit <span class="ot">=</span> lens getter setter</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>    getter <span class="ot">=</span> celsiusToFahrenheit <span class="op">.</span> view celsius</span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>    setter temp f <span class="ot">=</span> set celsius (fahrenheitToCelsius f) temp</span></code></pre></div>
<p>Look how much it cleans up the call sites:</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="kw">let</span> temp <span class="ot">=</span> <span class="dt">Temperature</span> <span class="st">&quot;Berlin&quot;</span> <span class="fl">7.0</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> view fahrenheit temp</span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="fl">44.6</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> set fahrenheit <span class="fl">56.3</span> temp</span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a><span class="dt">Temperature</span> {_location <span class="ot">=</span> <span class="st">&quot;Berlin&quot;</span>, _celsius <span class="ot">=</span> <span class="fl">13.5</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="op">&gt;&gt;&gt;</span> over fahrenheit (<span class="op">+</span><span class="dv">18</span>) temp</span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a><span class="dt">Temperature</span> {_location <span class="ot">=</span> <span class="st">&quot;Berlin&quot;</span>, _celsius <span class="ot">=</span> <span class="fl">17.0</span>}</span></code></pre></div>
<p>Much nicer, easier to read, and less error prone! Even though our
<code>Temperature</code> record doesn't actually have a concrete field
for the temperature in <strong>Fahrenheit</strong> we managed to fake it
by using lenses to create a <strong>virtual field</strong>! If we export
a smart constructor for our Temperature type and only export the lenses
from our Temperature module then the two field lenses are completely
indistinguishable.</p>
<h2 id="breakage-free-refactoring">Breakage-free refactoring</h2>
<p>In addition to providing more functionality in a really clean way,
another benefit of using lenses instead of field accessors for
interacting with our data is that we gain more freedom when
refactoring.</p>
<p>To continue with the Temperature example, let's say as we've
developed our wonderful weather app further we've discovered that Kelvin
is a much better canonical representation for temperature data. We'd
love to swap our <code>_celsius</code> field for a <code>_kelvin</code>
field instead and base all our measurements on that.</p>
<p>We'll consider two possible alternate universes, in the first, this
post was never written, so we didn't use lenses to access our fields
😱</p>
<p>In the second (the one you're living in) I published this post and of
course knew well enough to use lenses as the external interface
instead.</p>
<h2 id="a-world-without-lenses">A world without lenses</h2>
<p>In the sad universe without any lenses we had the following code
scattered throughout our app:</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">updateTempReading ::</span> <span class="dt">Temperature</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> <span class="dt">Temperature</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>updateTempReading temp <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>  newTempInCelsius <span class="ot">&lt;-</span> readOutdoorTemp</span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>  <span class="fu">return</span> temp{_celsius<span class="ot">=</span>newTempInCelsius}</span></code></pre></div>
<p>Then we refactored our <code>Temperature</code> object to the
following:</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">data</span> <span class="dt">Temperature</span> <span class="ot">=</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Temperature</span> {<span class="ot"> _location ::</span> <span class="dt">String</span></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>                ,<span class="ot"> _kelvin  ::</span> <span class="dt">Float</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>                }</span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">deriving</span> (<span class="dt">Show</span>)</span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a>makeLenses &#39;<span class="dt">&#39;Temperature</span></span></code></pre></div>
<p>Now, unfortunately, every file that used record update syntax now
fails to compile. This is because the <code>_celsius</code> field we are
depending on with our record-update-syntax no longer exists. If we had
instead used positional pattern matching the situation would be even
worse:</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">updateTempReading ::</span> <span class="dt">Temperature</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> <span class="dt">Temperature</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>updateTempReading (<span class="dt">Temperature</span> location _) <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>  newTempInCelsius <span class="ot">&lt;-</span> readOutdoorTemp</span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>  <span class="fu">return</span> (<span class="dt">Temperature</span> location newTempInCelsius)</span></code></pre></div>
<p>In this case the code <strong>will still happily compile</strong>,
but we've switched measurement units this code is now completely
incorrect!</p>
<h2 id="the-glorious-utopian-lenses-universe">The glorious utopian
lenses universe</h2>
<p>Come with me now to the happy universe. In this world we've decided
to use lenses as our interface for interacting with
<code>Temperature</code>s, meaning we didn't expose the field accessors
and thus disallowed fragile record-update syntax. We used the
<code>celsius</code> lens to perform the update instead:</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">updateTempReading ::</span> <span class="dt">Temperature</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> <span class="dt">Temperature</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>updateTempReading temp <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>  newTempInCelsius <span class="ot">&lt;-</span> readTemp</span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>  <span class="fu">return</span> <span class="op">$</span> set celsius newTempInCelsius temp</span></code></pre></div>
<p>Now when we refactor, we can export a replacement
<code>celsius</code> lens in place of the old generated one, and nobody
need be aware of our refactoring!</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">Temperature</span> <span class="ot">=</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Temperature</span> {<span class="ot"> _location ::</span> <span class="dt">String</span></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>                ,<span class="ot"> _kelvin  ::</span> <span class="dt">Float</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="kw">deriving</span> (<span class="dt">Show</span>)</span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a>makeLenses &#39;<span class="dt">&#39;Temperature</span></span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a><span class="ot">celsius ::</span> <span class="dt">Lens&#39;</span> <span class="dt">Temperature</span> <span class="dt">Float</span></span>
<span id="cb12-9"><a href="#cb12-9" aria-hidden="true" tabindex="-1"></a>celsius <span class="ot">=</span> lens getter setter</span>
<span id="cb12-10"><a href="#cb12-10" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb12-11"><a href="#cb12-11" aria-hidden="true" tabindex="-1"></a>    getter <span class="ot">=</span> (<span class="fu">subtract</span> <span class="fl">273.15</span>) <span class="op">.</span> view kelvin</span>
<span id="cb12-12"><a href="#cb12-12" aria-hidden="true" tabindex="-1"></a>    setter temp c <span class="ot">=</span> set kelvin (c <span class="op">+</span> <span class="fl">273.15</span>) temp</span></code></pre></div>
<p>By adding the replacement lens we <strong>avoid</strong> breaking any
external users of the type! Even our <code>fahrenheit</code> lens was
defined in terms of <code>celsius</code>, so it will continue to work
perfectly.</p>
<p>This is a simple example, but this principle holds for more complex
refactorings too. When adopting this style it's important to avoid
exporting the data type constructor or field accessors and instead
export a "smart constructor" function and the lenses for each field.</p>
<p>When you're writing more complex virtual fields it's relatively easy
to write lenses that don't abide by the <strong>lens laws</strong>. In
practice, this is usually perfectly fine. In many cases it's completely
fine to break these laws for the sake of pragmatism (especially in
application code). In fact the <code>lens</code> library itself exports
many law-breaking optics. The important thing is to think about whether
the lenses for your type behave in a way that's <em>intuitive</em> to
the caller or not, and whether it maintains any invariants your type may
have.</p>
<h2 id="exercises">Exercises</h2>
<p>In <a
href="https://leanpub.com/optics-by-example/c/virtual-fields"><strong>Optics
By Example</strong></a> I include exercises after each section to help
readers sharpen their skills. The book has answers too, but for this
blog post you're on your own. Give these a try!</p>
<p>Consider this data type for the following exercises:</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">data</span> <span class="dt">User</span> <span class="ot">=</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>  <span class="dt">User</span> {<span class="ot"> _firstName ::</span> <span class="dt">String</span></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a>       ,<span class="ot"> _lastName ::</span> <span class="dt">String</span></span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>       ,<span class="ot"> _username ::</span> <span class="dt">String</span></span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a>       ,<span class="ot"> _email ::</span> <span class="dt">String</span></span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a>       } <span class="kw">deriving</span> (<span class="dt">Show</span>)</span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a>makeLenses &#39;<span class="dt">&#39;User</span></span></code></pre></div>
<ol>
<li><p>We've decided we're no longer going to have separate usernames
and emails; now the email will be used in place of a username. Your task
is to delete the <code>_username</code> field and write a replacement
<code>username</code> lens which reads and writes from/to the
<code>_email</code> field instead. The change should be unnoticed by
those importing the module. Assume we haven't exported the constructor,
or any of our field accessors, only the generated lenses</p></li>
<li><p>Write a lens for the user's <code>fullName</code>. It should
append the first and last names when "getting". When "setting" treat
everything up to the first space as the first name, and everything
following it as the last name.</p></li>
</ol>
<p>It should behave something like this:</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="op">&gt;&gt;&gt;</span> <span class="kw">let</span> user <span class="ot">=</span> <span class="dt">User</span> <span class="st">&quot;John&quot;</span> <span class="st">&quot;Cena&quot;</span> <span class="st">&quot;invisible@example.com&quot;</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> view fullName user</span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;John Cena&quot;</span></span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> set fullName <span class="st">&quot;Doctor of Thuganomics&quot;</span> user</span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a><span class="dt">User</span></span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a>    { _firstName <span class="ot">=</span> <span class="st">&quot;Doctor&quot;</span></span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a>    , _lastName <span class="ot">=</span> <span class="st">&quot;of Thuganomics&quot;</span></span>
<span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a>    , _email <span class="ot">=</span> <span class="st">&quot;invisible@example.com&quot;</span></span>
<span id="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a>    }</span></code></pre></div>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Composable filters using Witherable optics</title>
      <link href="https://chrispenner.ca/posts/witherable-optics"/>
      <id>https://chrispenner.ca/posts/witherable-optics</id>
      <updated>2020-10-31T00:00:00Z</updated>
      <summary>Discovering applications of filterable optics</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/withered.jpg" alt="Composable filters using Witherable optics">
              <p>One of my favourite things about Haskell is that its structures and
abstractions are very principled, and they have laws dictating correct
behaviour.</p>
<p>In my experience, this means that when you find a new way to piece
together those abstractions it <em>almost always</em> ends up doing
something reasonable... or at the very least interesting!</p>
<p>As it turns out, optics have a lot of different "slots" where we can
experiment with different data types and constraints to get new
results.</p>
<p>In this post I'll be exploring one such new combination and the
results that follow. To get the most out of this post you'll want an
understanding of:</p>
<ul>
<li>optics</li>
<li>Traversable/Traversals</li>
<li>Alternative</li>
</ul>
<p>If optics are still new to you, I recommend you first check out my
introductory book <a href="https://leanpub.com/optics-by-example">Optics
By Example</a> 😎</p>
<p>Here's the agenda</p>
<ol>
<li>Introduce an adaptation of an existing typeclass to make it more
amenable for optics</li>
<li>Discover the semantics behind the new optic and how it works</li>
<li>Write some combinators</li>
<li><a href="https://www.youtube.com/watch?v=UM-wKQqBBnY">Throw science
at the wall to see what sticks</a> (a.k.a. lots of examples)</li>
</ol>
<h2 id="the-background">The Background</h2>
<p>First things first, let's go over the fundamentals we'll be working
with.</p>
<p>Let's take a look at the Traversable typeclass, it's where we find
Haskell's all-powerful secret weapon <strong>traverse</strong>! (<a
href="https://impurepics.com/fp-bot/index.html">BTW The answer is always
traverse.</a>)</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> 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="cb1-2"><a href="#cb1-2" 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></code></pre></div>
<p>This class eventually let to the concept of a <code>Traversal</code>
in Van Laarhoven encoded optics; which looks 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="kw">forall</span> f<span class="op">.</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> (s <span class="ot">-&gt;</span> f t)</span></code></pre></div>
<p>If we clear the constraints we get a <code>LensLike</code>, which is
just the shape of any combinator that will compose well with optics from
the <code>lens</code> library:</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">type</span> <span class="dt">LensLike</span> f s t a b <span class="ot">=</span> (a <span class="ot">-&gt;</span> f b) <span class="ot">-&gt;</span> (s <span class="ot">-&gt;</span> f t)</span></code></pre></div>
<p>Anyways, long story short, if you can make your function fit that
shape, it's probably useful as some sort of optic!</p>
<p>This leads us to <strong>Witherable</strong>!</p>
<h2 id="witherable">Witherable</h2>
<p>Ever heard of <a
href="https://hackage.haskell.org/package/witherable-0.3.5/docs/Data-Witherable.html">Witherable</a>?
It's a class which extends from Traversable, that is, Traversable is a
superclass, all Witherables are Traversable, but not the other way
around.</p>
<p>Here's what it looks like:</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">Traversable</span> t, <span class="dt">Filterable</span> t) <span class="ot">=&gt;</span> <span class="dt">Witherable</span> t <span class="kw">where</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="ot">  wither ::</span> <span class="dt">Applicative</span> f <span class="ot">=&gt;</span> (a <span class="ot">-&gt;</span> f (<span class="dt">Maybe</span> b)) <span class="ot">-&gt;</span> t a <span class="ot">-&gt;</span> f (t b)</span></code></pre></div>
<p>Types which implement Witherable expand on the functionality of
Traversable, they add the ability to <strong>filter</strong> items out
from a structure within an effectful context. Although this type isn't
yet in the <code>base</code> library, it turns out it can be pretty
handy!</p>
<p>Examples of witherable types include things like lists and maps, each
of their keys or values could potentially be "deleted" from the
structure in a sensible way.</p>
<p>My goal is that I'd like to be able to add "filtering" to the list of
things optics can do in a nicely composable way! To do that, we need it
to look like a <code>LensLike</code>.</p>
<p>As you can see, the type of <code>wither</code> is pretty similar to
the type of a <code>LensLike</code>, but unfortunately, it doesn't
<strong>quite</strong> match the shape we need, it's got a pesky extra
<code>Maybe</code> in the 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="co">-- We need a shape like this:</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>(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-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="co">-- But wither looks like this:</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>(a <span class="ot">-&gt;</span> f (<span class="dt">Maybe</span> b)) <span class="ot">-&gt;</span> t a <span class="ot">-&gt;</span> f (t b)</span></code></pre></div>
<p>We could get rid of that extra Maybe is by specializing the
<code>f</code> into something like <code>Compose f Maybe</code> using
<code>Data.Functor.Compose</code>. This would get us close, but
specializing the <code>f</code> type to include a concrete type loses a
LOT of the generality of optics and will make it much more difficult to
use this type with other optics. It's a non-starter.</p>
<p>We need to find some typeclass constraint which allows for the
behaviour of <code>wither</code>, but without the concrete requirement
of using <code>Maybe</code>. As it turns out, if we're looking to
express "failure" as an Applicative structure, that's exactly what
<code>Alternative</code> is for.</p>
<p><code>Alternative</code> provides a concrete representation of
"failure" which we can use as a substitute for the <code>Maybe</code>
value that was ruining our day. As it turns out,
<code>f (Maybe b)</code> is actually isomorphic to
<code>MaybeT f b</code>, and <code>MaybeT</code> provides an Alternative
instance, so we can always regain our previous behaviour if we're able
to generalize it this way.</p>
<p>Here's what <a
href="https://hackage.haskell.org/package/base-4.12.0.0/docs/Control-Applicative.html#t:Alternative">Alternative</a>
looks like:</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="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="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="ot">  empty ::</span> f a</span>
<span id="cb6-3"><a href="#cb6-3" 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></code></pre></div>
<p>In addition to the <code>MaybeT f</code> we already mentioned, some
examples of other <code>Alternative</code>s include <code>Maybe</code>,
<code>[]</code>, <code>IO</code>, <code>STM</code>, <code>Logic</code>
and most of the available <code>Parser</code> variants. You can of
course write your own effects which implement Alternative as well!</p>
<p>Okay, so here's the combinator I want to build, it's a valid
"LensLike" so it'll be composable with other optics:</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">withered ::</span> <span class="kw">forall</span> f t a b<span class="op">.</span> (<span class="dt">Alternative</span> f, <span class="dt">Witherable</span> t) <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>To save us time, I'll define an alias for our
<code>Alternative</code> <code>LensLike</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="co">-- </span><span class="al">NOTE</span><span class="co">: Wither and Wither&#39; are exported from Data.Witherable, </span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- BUT have they have the unfortunate, less-composable type we&#39;re trying to avoid.</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="co">-- This post uses the following variants instead (sorry about the naming confusion)</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">Wither</span> s t a b <span class="ot">=</span> <span class="kw">forall</span> f<span class="op">.</span> <span class="dt">Alternative</span> f <span class="ot">=&gt;</span> (a <span class="ot">-&gt;</span> f b) <span class="ot">-&gt;</span> s <span class="ot">-&gt;</span> f t</span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">Wither&#39;</span> s a <span class="ot">=</span> <span class="dt">Wither</span> s s a a</span></code></pre></div>
<p>Unfortunately, the <code>withered</code> function isn't provided by
the <code>Witherable</code> typeclass, but luckily we can write a
general implementation for all <code>Witherables</code>.</p>
<p>In order to do so, we need a way to "recognize" a failure within our
Alternative effect and represent it as a concrete "Maybe". Lucky us, a
combinator for this exact purpose exists, it's called
<code>optional</code>!</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">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></code></pre></div>
<p>When we use <code>optional</code> to <em>lift</em> the failure out of
the <em>structure</em> into a concrete <code>Maybe</code> it also
<em>removes</em> that particular failure from the <em>effect</em>,
yielding an action that will always <strong>succeed</strong> and return
either <code>Just</code> or <code>Nothing</code>.</p>
<p>Let's use it to build a "lensy" combinator in terms of our existing
<code>Witherable</code> class, this saves us the work of writing a new
class and re-implementing all the instances we'd need.</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">withered ::</span> (<span class="dt">Alternative</span> f, <span class="dt">Witherable</span> t) <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="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>withered f <span class="ot">=</span> wither (optional <span class="op">.</span> f)</span></code></pre></div>
<p>Great! In pretty short order we've constructed a new combinator that
fits a signature compatible with other optics, based on a typeclass that
has a pretty clear semantic meaning. Now for the fun part, let's see how
we can use it!</p>
<h2 id="withers-as-optics">Withers as Optics</h2>
<p>Any time a new optical structure is discovered we need to find some
concrete "actions" which we can run on it. This usually involves
discovering some interesting applications of different concrete types
which implement the constraints required by the optic.</p>
<p>To experiment a bit we'll use the most general action available,
which works on any optic. The <a
href="https://hackage.haskell.org/package/lens-4.19.2/docs/Control-Lens-Lens.html#v:-37--37--126-"><code>%%~</code></a>
combinator from <code>lens</code> allows us to run any optic if we
provide an effectful function which matches the optic's focus and
constraints.</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">(%%~) ::</span> <span class="dt">LensLike</span> f s t a b <span class="ot">-&gt;</span> (a <span class="ot">-&gt;</span> f b) <span class="ot">-&gt;</span> s <span class="ot">-&gt;</span> f t</span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- Which expands to:</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a><span class="ot">(%%~) ::</span> ((a <span class="ot">-&gt;</span> f b) <span class="ot">-&gt;</span> s <span class="ot">-&gt;</span> (f t)) <span class="ot">-&gt;</span> (a <span class="ot">-&gt;</span> f b) <span class="ot">-&gt;</span> s <span class="ot">-&gt;</span> f t</span></code></pre></div>
<p>E.g. for a <code>Traversal s t a b</code> we can provide a function
<code>Applicative f =&gt; a -&gt; f b</code> and it will return a
<code>s -&gt; f t</code> for us.</p>
<p>Fun fact, this combinator is actually implemented as just
<code>(%%~) = id</code>, which in practice just "applies" the optic to
the effectful function we provide. It really does help make things more
readable though, so we tend to use it despite the fact that it's really
just a glorified <code>id</code>.</p>
<p>So what can we do with <code>withered</code>? We start by considering
different functions of the type
<code>Alternative f =&gt; a -&gt; f b</code>, since that allows us to
leverage the new functionality we've added. By picking different
Alternatives we may get some different results.</p>
<p>Parsing is a great use-case, it's always possible that a string may
not match the format of the result we want. Spoilers,
<code>withered</code> works wonderfully with parser combinators, but
we'll start with something a little simpler:</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">&gt;&gt;&gt;</span> <span class="kw">import</span> <span class="dt">Text.Read</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="op">:</span>t readMaybe</span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a><span class="ot">readMaybe ::</span> <span class="dt">Read</span> a <span class="ot">=&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> a</span></code></pre></div>
<p>Okay, so <code>readMaybe</code> will try to parse a string into a
value of the provided type, and will fail as a <code>Nothing</code> if
it doesn't work out.</p>
<p>A regular ol' Traversal will sequence effects from deep inside a
structure all the way to the outside, what will <code>withered</code>
do?</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="kw">let</span> y <span class="ot">=</span> M.fromList [(<span class="ch">&#39;a&#39;</span>, [<span class="st">&quot;1&quot;</span>, <span class="st">&quot;2&quot;</span>, <span class="st">&quot;Tangerine&quot;</span>]), (<span class="ch">&#39;b&#39;</span>, [<span class="st">&quot;4&quot;</span>, <span class="st">&quot;Alpaca&quot;</span>, <span class="st">&quot;6&quot;</span>])] </span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> (y <span class="op">&amp;</span> withered <span class="op">.</span> withered <span class="op">%%~</span> readMaybe)<span class="ot"> ::</span> <span class="dt">Maybe</span> (<span class="dt">M.Map</span> <span class="dt">Char</span> [<span class="dt">Int</span>])</span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> (fromList [(<span class="ch">&#39;a&#39;</span>,[<span class="dv">1</span>,<span class="dv">2</span>]),(<span class="ch">&#39;b&#39;</span>,[<span class="dv">4</span>,<span class="dv">6</span>])])</span></code></pre></div>
<p>Okay, so like, you gotta admit, that's pretty cool! With the wave of
a hand we've gone two levels deep into a complex structure, applied a
parsing operation that could fail, and automatically filtered down the
containing list to remove failed parses, then rebuilt the outer
structure!</p>
<p>Compare this to what happens if try the same with a traversal
instead:</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="op">&gt;&gt;&gt;</span> <span class="kw">let</span> y <span class="ot">=</span> M.fromList [(<span class="ch">&#39;a&#39;</span>, [<span class="st">&quot;1&quot;</span>, <span class="st">&quot;2&quot;</span>, <span class="st">&quot;Tangerine&quot;</span>]), (<span class="ch">&#39;b&#39;</span>, [<span class="st">&quot;4&quot;</span>, <span class="st">&quot;Alpaca&quot;</span>, <span class="st">&quot;6&quot;</span>])] </span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> (y <span class="op">&amp;</span> <span class="fu">traverse</span> <span class="op">.</span> <span class="fu">traverse</span> <span class="op">%%~</span> readMaybe)<span class="ot"> ::</span> <span class="dt">Maybe</span> (<span class="dt">M.Map</span> <span class="dt">Char</span> [<span class="dt">Int</span>])</span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Nothing</span></span></code></pre></div>
<p>Oof, well that's disappointing! <code>withered</code> is clearly the
better match for this sort of thing, and is adding some secret sauce to
the whole equation.</p>
<p>Let's chat about how this actually works.</p>
<h2 id="filtering-branches">Filtering branches</h2>
<p>We can think of traversals as "branching" data explorations, they
help you dive down deeply into <strong>many</strong> sections of a data
structure at once, apply their transformations, then "re-build" the
structure as those branches unwind one by one! Each of those branches
carry an <strong>independent</strong> set of effects with them, but as
the structure is rebuilt, those branches are merged back together and
those effects are combined. In the case of <code>traverse</code>, those
effects are combined and sequenced using <code>Applicative</code>, and
the structure is rebuilt within that Applicative context. This is why,
when we tried using <code>traverse</code> for our parsing the whole
result was <code>Nothing</code> even though we had a few passing parses.
The Applicative instance of <code>Maybe</code> dictates that all
function applications inside a <code>Nothing</code> just keep returning
<code>Nothing</code> and it clobbered the whole structure!</p>
<p>Our <code>withered</code> combinator is
<strong>failure-aware</strong>; and the <code>Witherable</code> instance
knows how interpret that failure as a <em>filter</em> for a data
structure rather than completely <em>clobbering</em> it.</p>
<p>One important thing to notice here is that as <code>wither</code>
<strong>collects</strong> all the branches of its computation (one for
each element of the structure), it <strong>catches</strong> the failure
of the <code>Alternative</code> structure by using
<code>optional</code>. This means that failures to the right of a
<code>withered</code> <strong>will not propagate past it to the
left</strong>. The <code>withered</code> will catch it and filter out
that branch from the structure as it rebuilds it.</p>
<p>A second thing to notice is that a call to <code>wither</code> itself
will <strong>never "fail"</strong> (i.e. it won't return the
<code>empty</code> value of the Alternative). This is because the
<code>Witherable</code> class will simply return an empty structure
(rather than the empty effect) if all the elements are filtered out.
Take a look at what I mean:</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> withered (<span class="fu">const</span> <span class="dt">Nothing</span>) [<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>, <span class="dv">4</span>]</span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> []</span></code></pre></div>
<p>We can see the same behaviour in <code>wither</code> if we provide
the equivalent:</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="op">&gt;&gt;&gt;</span> wither (<span class="fu">const</span> (<span class="dt">Identity</span> <span class="dt">Nothing</span>)) [<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>, <span class="dv">4</span>]</span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Identity</span> []</span></code></pre></div>
<p>It doesn't matter if every element "fails", the result will still
"succeed" with an empty structure.</p>
<p>This is actually a huge benefit for us. We've seen that
<code>traverse</code> <strong>propagates</strong> any failures to the
left, and that <code>withered</code> <strong>catches</strong> any
failures and doesn't propagate them at all. By manipulating these facts
we can <strong>choose how and when to handle failure</strong>!</p>
<h2 id="catching-failures">Catching failures</h2>
<p>To demonstrate the point, let's stick to parsing with
<code>readMaybe</code>.</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="op">&gt;&gt;&gt;</span> <span class="kw">let</span> z <span class="ot">=</span> M.fromList [(<span class="ch">&#39;a&#39;</span>, [<span class="st">&quot;1&quot;</span>, <span class="st">&quot;2&quot;</span>, <span class="st">&quot;3&quot;</span>]), (<span class="ch">&#39;b&#39;</span>, [<span class="st">&quot;4&quot;</span>, <span class="st">&quot;Alpaca&quot;</span>, <span class="st">&quot;6&quot;</span>])] </span></code></pre></div>
<p>I've altered the structure, now it has an outer map with two keys,
the 'a' key contains all valid parses for integers. The 'b' key contains
2 good parses and one bad one.</p>
<p>Let's see what happens if we use <code>withered</code> to drill down
through both structures:</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="op">&gt;&gt;&gt;</span> (z <span class="op">&amp;</span> withered <span class="op">.</span> withered <span class="op">%%~</span> readMaybe)<span class="ot"> ::</span> <span class="dt">Maybe</span> (<span class="dt">M.Map</span> <span class="dt">Char</span> [<span class="dt">Int</span>])</span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> (fromList [(<span class="ch">&#39;a&#39;</span>,[<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]), (<span class="ch">&#39;b&#39;</span>,[<span class="dv">4</span>,<span class="dv">6</span>])])</span></code></pre></div>
<p>Just as expected, it has parsed the valid integers from 'a', in 'b'
it has filtered out the bad parse while still keeping the valid
parses.</p>
<p>Given our new understanding of how <code>traverse</code>
<strong>propagates</strong> errors rather than catching them, what do we
expect to happen if we replace the second <code>withered</code> with
<code>traverse</code>?</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="op">&gt;&gt;&gt;</span> (z <span class="op">&amp;</span> withered <span class="op">.</span> <span class="fu">traverse</span> <span class="op">%%~</span> readMaybe)<span class="ot"> ::</span> <span class="dt">Maybe</span> (<span class="dt">M.Map</span> <span class="dt">Char</span> [<span class="dt">Int</span>])</span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> (fromList [(<span class="ch">&#39;a&#39;</span>,[<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>])])</span></code></pre></div>
<p>Aha! <code>traverse</code> caused the single failure to propagate and
kill the branch at the next level up. Now the first
<code>withered</code> catches the error when rebuilding the Map and it
will filter out the entire <code>b</code> key from the map!</p>
<p>This can take a bit of getting used to of course, but ultimately it
allows <strong>composable</strong> filtering, and lets you to filter
complex data structures in tandem with using lenses or traversals to
base your judgements on their internals.</p>
<p>Until now I've been using <code>%%~</code> to pass explicit
<code>Alternative f =&gt; a -&gt; f b</code> functions, but we can build
some handy combinators around it to make it a bit easier to use.</p>
<h2 id="combinators">Combinators</h2>
<p>So, if filtering is our game, what if we want to filter one of the
traversed structures based on a predicate?</p>
<p>First I'll point out that the <code>Data.Witherable</code> package
exports combinators of the same name as what we define below,
<strong>however</strong>, they work under the assumption that the
<code>Maybe</code> is propagated explicitly, and thus they <strong>do
not compose with any of the optics from <code>lens</code></strong>. The
versions we define here avoid this problem by using
<code>Alternative f =&gt; f b</code> instead of
<code>f (Maybe b)</code>, and are more composable.</p>
<p>Assume that we use the combinators that we manually define rather
than those exported from <code>Data.Witherable</code> for the rest of
this post.</p>
<div class="sourceCode" id="cb20"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- Just a nifty helper to lift a predicate into an Alternative</span></span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a><span class="ot">guarding ::</span> <span class="dt">Alternative</span> f <span class="ot">=&gt;</span> (a <span class="ot">-&gt;</span> <span class="dt">Bool</span>) <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> f a</span>
<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a>guarding p a</span>
<span id="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">|</span> p a <span class="ot">=</span> <span class="fu">pure</span> a</span>
<span id="cb20-5"><a href="#cb20-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> empty</span>
<span id="cb20-6"><a href="#cb20-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-7"><a href="#cb20-7" aria-hidden="true" tabindex="-1"></a><span class="co">-- Filter based on a predicate using witherables</span></span>
<span id="cb20-8"><a href="#cb20-8" aria-hidden="true" tabindex="-1"></a><span class="ot">filterOf ::</span> <span class="dt">LensLike</span> <span class="dt">Maybe</span> s t a a <span class="ot">-&gt;</span> (a <span class="ot">-&gt;</span> <span class="dt">Bool</span>) <span class="ot">-&gt;</span> s <span class="ot">-&gt;</span> <span class="dt">Maybe</span> t</span>
<span id="cb20-9"><a href="#cb20-9" aria-hidden="true" tabindex="-1"></a>filterOf w p s <span class="ot">=</span> s <span class="op">&amp;</span> w <span class="op">%%~</span> guarding p</span></code></pre></div>
<p>Now we can express our filtering operations like this:</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="co">-- Filter all odd numbers out from the nested list</span></span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> [[<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>], [<span class="dv">4</span>, <span class="dv">5</span>, <span class="dv">6</span>]] <span class="op">&amp;</span> filterOf (withered <span class="op">.</span> withered) <span class="fu">even</span> </span>
<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> [[<span class="dv">2</span>],[<span class="dv">4</span>,<span class="dv">6</span>]]</span></code></pre></div>
<p>Now that we have a combinator for it, here's another example. We can
actually filter a list that's <strong>in the middle of our
structure</strong>, not just at the start or the end, based on deeply
nested values inside by composing our withers with lenses and
prisms!</p>
<p>Let's set up some data-types to work with:</p>
<div class="sourceCode" id="cb22"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- We&#39;ll keep track of whether an email has been validated at the type level</span></span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">UnvalidatedEmail</span> <span class="ot">=</span> <span class="dt">UnvalidatedEmail</span> {<span class="ot">_unvalidatedEmail ::</span> <span class="dt">String</span>}</span>
<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>, <span class="dt">IsString</span>)</span>
<span id="cb22-4"><a href="#cb22-4" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">ValidEmail</span> <span class="ot">=</span> <span class="dt">ValidEmail</span> {<span class="ot">_validEmail ::</span> <span class="dt">String</span>}</span>
<span id="cb22-5"><a href="#cb22-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>)</span>
<span id="cb22-6"><a href="#cb22-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb22-7"><a href="#cb22-7" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Address</span> <span class="ot">=</span> <span class="dt">Address</span></span>
<span id="cb22-8"><a href="#cb22-8" aria-hidden="true" tabindex="-1"></a>    {<span class="ot"> _country ::</span> <span class="dt">String</span></span>
<span id="cb22-9"><a href="#cb22-9" aria-hidden="true" tabindex="-1"></a>    <span class="co">--  ...</span></span>
<span id="cb22-10"><a href="#cb22-10" aria-hidden="true" tabindex="-1"></a>    } <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>)</span>
<span id="cb22-11"><a href="#cb22-11" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Employee</span> email <span class="ot">=</span> <span class="dt">Employee</span></span>
<span id="cb22-12"><a href="#cb22-12" aria-hidden="true" tabindex="-1"></a>    {<span class="ot"> _age ::</span> <span class="dt">Int</span></span>
<span id="cb22-13"><a href="#cb22-13" aria-hidden="true" tabindex="-1"></a>    ,<span class="ot"> _address ::</span> <span class="dt">Address</span></span>
<span id="cb22-14"><a href="#cb22-14" aria-hidden="true" tabindex="-1"></a>    ,<span class="ot"> _email ::</span> email</span>
<span id="cb22-15"><a href="#cb22-15" aria-hidden="true" tabindex="-1"></a>    <span class="co">--  ...</span></span>
<span id="cb22-16"><a href="#cb22-16" aria-hidden="true" tabindex="-1"></a>    } <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>)</span>
<span id="cb22-17"><a href="#cb22-17" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Company</span> email <span class="ot">=</span> <span class="dt">Company</span></span>
<span id="cb22-18"><a href="#cb22-18" aria-hidden="true" tabindex="-1"></a>    {<span class="ot"> _employees ::</span> [<span class="dt">Employee</span> email]</span>
<span id="cb22-19"><a href="#cb22-19" aria-hidden="true" tabindex="-1"></a>    <span class="co">--  ...</span></span>
<span id="cb22-20"><a href="#cb22-20" aria-hidden="true" tabindex="-1"></a>    } <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>)</span>
<span id="cb22-21"><a href="#cb22-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb22-22"><a href="#cb22-22" aria-hidden="true" tabindex="-1"></a>makeLenses &#39;<span class="dt">&#39;UnvalidatedEmail</span></span>
<span id="cb22-23"><a href="#cb22-23" aria-hidden="true" tabindex="-1"></a>makeLenses &#39;<span class="dt">&#39;ValidEmail</span></span>
<span id="cb22-24"><a href="#cb22-24" aria-hidden="true" tabindex="-1"></a>makeLenses &#39;<span class="dt">&#39;Address</span></span>
<span id="cb22-25"><a href="#cb22-25" aria-hidden="true" tabindex="-1"></a>makeLenses &#39;<span class="dt">&#39;Employee</span></span>
<span id="cb22-26"><a href="#cb22-26" aria-hidden="true" tabindex="-1"></a>makeLenses &#39;<span class="dt">&#39;Company</span></span></code></pre></div>
<p>And here's a company to work with:</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">company ::</span> <span class="dt">Company</span> <span class="dt">UnvalidatedEmail</span></span>
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a>company <span class="ot">=</span> <span class="dt">Company</span></span>
<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a>    [ <span class="dt">Employee</span> <span class="dv">22</span> (<span class="dt">Address</span> <span class="st">&quot;US&quot;</span>) <span class="st">&quot;stan@example.com&quot;</span></span>
<span id="cb23-4"><a href="#cb23-4" aria-hidden="true" tabindex="-1"></a>    , <span class="dt">Employee</span> <span class="dv">43</span> (<span class="dt">Address</span> <span class="st">&quot;CA&quot;</span>) <span class="st">&quot;what do I fill in here?&quot;</span></span>
<span id="cb23-5"><a href="#cb23-5" aria-hidden="true" tabindex="-1"></a>    , <span class="dt">Employee</span> <span class="dv">35</span> (<span class="dt">Address</span> <span class="st">&quot;NO&quot;</span>) <span class="st">&quot;bob@bobloblawslaw.com&quot;</span></span>
<span id="cb23-6"><a href="#cb23-6" aria-hidden="true" tabindex="-1"></a>    , <span class="dt">Employee</span> <span class="dv">37</span> (<span class="dt">Address</span> <span class="st">&quot;CA&quot;</span>) <span class="st">&quot;dude@wheresmycar.com&quot;</span></span>
<span id="cb23-7"><a href="#cb23-7" aria-hidden="true" tabindex="-1"></a>    ]</span></code></pre></div>
<p>Check this out:</p>
<div class="sourceCode" id="cb24"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- Filter our company for only Canadians:</span></span>
<span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> company <span class="op">&amp;</span> filterOf (employees <span class="op">.</span> withered <span class="op">.</span> address <span class="op">.</span> country) (<span class="op">==</span> <span class="st">&quot;CA&quot;</span>)</span>
<span id="cb24-3"><a href="#cb24-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> (<span class="dt">Company</span></span>
<span id="cb24-4"><a href="#cb24-4" aria-hidden="true" tabindex="-1"></a>       [ <span class="dt">Employee</span> <span class="dv">43</span> (<span class="dt">Address</span> <span class="st">&quot;CA&quot;</span>) (<span class="dt">UnvalidatedEmail</span> <span class="st">&quot;what do I fill in here?&quot;</span>)</span>
<span id="cb24-5"><a href="#cb24-5" aria-hidden="true" tabindex="-1"></a>       , <span class="dt">Employee</span> <span class="dv">37</span> (<span class="dt">Address</span> <span class="st">&quot;CA&quot;</span>) (<span class="dt">UnvalidatedEmail</span> <span class="st">&quot;dude@wheresmycar.com&quot;</span>)</span>
<span id="cb24-6"><a href="#cb24-6" aria-hidden="true" tabindex="-1"></a>       ]</span>
<span id="cb24-7"><a href="#cb24-7" aria-hidden="true" tabindex="-1"></a>     )</span></code></pre></div>
<p>This is deceptively simple at first glance, but it's pretty
impressive what this is accomplishing for us. Not only does it allow us
to filter our employees easily based on <strong>deeply nested
state</strong> within each employee, but it allows us to <strong>filter
them from a structure that's ALSO nested inside our larger
state</strong>! If we were to do this in any way OTHER than using
<code>withered</code> we'd have to first focus the employees, THEN run a
nested filter over the employees separately, and ALSO find a way to
filter them based on their nested "country" values.</p>
<p>We get even MORE mileage out of our combinators when we want to
perform a transformation that may fail over our structure.</p>
<p>Let's say we want to validate the email of all of our employees, and
track the results at the type level with our newtype wrapper.</p>
<div class="sourceCode" id="cb25"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- Validate an email</span></span>
<span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a><span class="ot">validateEmail ::</span> <span class="dt">UnvalidatedEmail</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> <span class="dt">ValidEmail</span></span>
<span id="cb25-3"><a href="#cb25-3" aria-hidden="true" tabindex="-1"></a>validateEmail (<span class="dt">UnvalidatedEmail</span> e)</span>
<span id="cb25-4"><a href="#cb25-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="fu">elem</span> <span class="ch">&#39;@&#39;</span> e <span class="ot">=</span> <span class="dt">Just</span> (<span class="dt">ValidEmail</span> e)</span>
<span id="cb25-5"><a href="#cb25-5" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="dt">Nothing</span></span>
<span id="cb25-6"><a href="#cb25-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb25-7"><a href="#cb25-7" aria-hidden="true" tabindex="-1"></a><span class="co">-- This will filter out our invalid &quot;what do I fill in here?&quot; email,</span></span>
<span id="cb25-8"><a href="#cb25-8" aria-hidden="true" tabindex="-1"></a><span class="co">-- And will wrap all the others in the &quot;ValidEmail&quot; type!</span></span>
<span id="cb25-9"><a href="#cb25-9" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> company <span class="op">&amp;</span> (employees <span class="op">.</span> withered <span class="op">.</span> email) <span class="op">%%~</span> validateEmail</span>
<span id="cb25-10"><a href="#cb25-10" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> (<span class="dt">Company</span></span>
<span id="cb25-11"><a href="#cb25-11" aria-hidden="true" tabindex="-1"></a>       [ <span class="dt">Employee</span> <span class="dv">22</span> (<span class="dt">Address</span> <span class="st">&quot;US&quot;</span>) (<span class="dt">ValidEmail</span> <span class="st">&quot;stan@example.com&quot;</span>)</span>
<span id="cb25-12"><a href="#cb25-12" aria-hidden="true" tabindex="-1"></a>       , <span class="dt">Employee</span> <span class="dv">35</span> (<span class="dt">Address</span> <span class="st">&quot;NO&quot;</span>) (<span class="dt">ValidEmail</span> <span class="st">&quot;bob@bobloblawslaw.com&quot;</span>)</span>
<span id="cb25-13"><a href="#cb25-13" aria-hidden="true" tabindex="-1"></a>       , <span class="dt">Employee</span> <span class="dv">37</span> (<span class="dt">Address</span> <span class="st">&quot;CA&quot;</span>) (<span class="dt">ValidEmail</span> <span class="st">&quot;dude@wheresmycar.com&quot;</span>)</span>
<span id="cb25-14"><a href="#cb25-14" aria-hidden="true" tabindex="-1"></a>       ])</span></code></pre></div>
<p>Because this is a <strong>type-changing-traversal</strong> it's much
clunkier to do this sort of filter &amp; transform operations without
using <code>Witherable</code>. Most obvious "two pass" implementations
will tend to be less performant and less composable as well.</p>
<p>Now you've seen the "gist" of what the tooling can do, let's just go
ham on some examples.</p>
<h2 id="bonus-fun-examples">Bonus: Fun examples</h2>
<p>If you've made it this far you're doing great! Here's a bunch of cool
stuff we can do, I'll be providing a bit less explanation of each of
these.</p>
<hr />
<p>Prisms already capture the idea of success and failure, but they
simply skip the traversal if the prism doesn't match, we can lift prisms
into withers such that they'll fail in a way that wither can catch!</p>
<div class="sourceCode" id="cb26"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a><span class="ot">witherPrism ::</span> (<span class="dt">Alternative</span> f, <span class="dt">Choice</span> p) <span class="ot">=&gt;</span> <span class="dt">Prism</span> s t a b <span class="ot">-&gt;</span> <span class="dt">Optic</span> p f s t a b</span>
<span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a>witherPrism prsm <span class="ot">=</span></span>
<span id="cb26-3"><a href="#cb26-3" aria-hidden="true" tabindex="-1"></a>    withPrism prsm <span class="op">$</span> \embed match <span class="ot">-&gt;</span></span>
<span id="cb26-4"><a href="#cb26-4" aria-hidden="true" tabindex="-1"></a>        dimap match (<span class="fu">either</span> (<span class="fu">const</span> empty) (<span class="fu">fmap</span> embed))  <span class="op">.</span> right&#39;</span></code></pre></div>
<p>Note that unfortunately the result of <code>witherPrism</code> will
no longer work with most of the prism combinators due to the added
Alternative constraint, but that's fine, if you need that behaviour,
then simply don't <code>wither</code> the prism in those
circumstances.</p>
<p>Now we can witherize a prism to turn it into a filter such that if
the value fails to match the prism the branch "fails", and if the prism
matches, it will run the predicate on the result!</p>
<div class="sourceCode" id="cb27"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> [(<span class="ch">&#39;a&#39;</span>, <span class="dt">Right</span> <span class="dv">1</span>), (<span class="ch">&#39;b&#39;</span>, <span class="dt">Left</span> <span class="dv">2</span>), (<span class="ch">&#39;c&#39;</span>, <span class="dt">Left</span> <span class="dv">3</span>)] <span class="op">&amp;</span> withered <span class="op">.</span> _2 <span class="op">.</span> witherPrism _Left <span class="op">%%~</span> guarding <span class="fu">odd</span></span>
<span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> [(<span class="ch">&#39;c&#39;</span>,<span class="dt">Left</span> <span class="dv">3</span>)]</span></code></pre></div>
<p>If we didn't lift our prism, it would simply "skip" unmatched values,
and thus they wouldn't fail or be filtered:</p>
<div class="sourceCode" id="cb28"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb28-1"><a href="#cb28-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> [(<span class="ch">&#39;a&#39;</span>, <span class="dt">Right</span> <span class="dv">1</span>), (<span class="ch">&#39;b&#39;</span>, <span class="dt">Left</span> <span class="dv">2</span>), (<span class="ch">&#39;c&#39;</span>, <span class="dt">Left</span> <span class="dv">3</span>)] <span class="op">&amp;</span> withered <span class="op">.</span> _2 <span class="op">.</span> _Left <span class="op">%%~</span> guarding <span class="fu">odd</span></span>
<span id="cb28-2"><a href="#cb28-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> [(<span class="ch">&#39;a&#39;</span>,<span class="dt">Right</span> <span class="dv">1</span>),(<span class="ch">&#39;c&#39;</span>,<span class="dt">Left</span> <span class="dv">3</span>)]</span></code></pre></div>
<hr />
<p>Have you ever used <code>filtered</code>? It's a traversal that skips
any elements that don't match a predicate. Here's the
<code>Wither</code> version which "fails" any elements that don't
match:</p>
<div class="sourceCode" id="cb29"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb29-1"><a href="#cb29-1" aria-hidden="true" tabindex="-1"></a><span class="ot">guarded ::</span> (a <span class="ot">-&gt;</span> <span class="dt">Bool</span>) <span class="ot">-&gt;</span> <span class="dt">Wither</span> a b a b</span>
<span id="cb29-2"><a href="#cb29-2" aria-hidden="true" tabindex="-1"></a>guarded p f a</span>
<span id="cb29-3"><a href="#cb29-3" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> p a <span class="ot">=</span> f a</span>
<span id="cb29-4"><a href="#cb29-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> empty</span></code></pre></div>
<p>This allows us to "do more" in a single pass. What if we want to
validate &amp; filter on emails AND filter by employee age in a single
pass?</p>
<div class="sourceCode" id="cb30"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb30-1"><a href="#cb30-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> company <span class="op">&amp;</span> (employees <span class="op">.</span> withered <span class="op">.</span> guarded ((<span class="op">&gt;</span> <span class="dv">35</span>) <span class="op">.</span> _age) <span class="op">.</span> email) <span class="op">%%~</span> validateEmail</span>
<span id="cb30-2"><a href="#cb30-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> (<span class="dt">Company</span> [ <span class="dt">Employee</span> <span class="dv">37</span> (<span class="dt">Address</span> <span class="st">&quot;CA&quot;</span>) (<span class="dt">ValidEmail</span> <span class="st">&quot;dude@wheresmycar.com&quot;</span>)])</span></code></pre></div>
<p>In this case the failures "stack", if either fails the branch will
fail! You could also use multiple guards interspersed between
<code>withered</code>s to filter at many different levels of your
structure.</p>
<hr />
<p>Since IO has an alternative instance which "fails" on IO Errors, we
can take a map containing filepaths and fetch the contents of files,
removing any key-value pairs from the map if the file doesn't exist.</p>
<div class="sourceCode" id="cb31"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb31-1"><a href="#cb31-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- Read in the content of files that exist, filter ones that fail to read!</span></span>
<span id="cb31-2"><a href="#cb31-2" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> M.fromList [(<span class="st">&quot;The Readme&quot;</span>, <span class="st">&quot;README.md&quot;</span>), (<span class="st">&quot;Missing File&quot;</span>, <span class="st">&quot;nonexistent.txt&quot;</span>)]</span>
<span id="cb31-3"><a href="#cb31-3" aria-hidden="true" tabindex="-1"></a>      <span class="op">&amp;</span> withered <span class="op">%%~</span> <span class="fu">readFile</span></span>
<span id="cb31-4"><a href="#cb31-4" aria-hidden="true" tabindex="-1"></a>fromList [(<span class="st">&quot;The Readme&quot;</span>,<span class="st">&quot;# wither\n&quot;</span>)]</span></code></pre></div>
<p>Note that since the alternative interface will <strong>only</strong>
catch IO errors I'd suggest against relying on this behaviour in any
sort of production scenario, but you could of course make the failure
mode explicit with <code>MaybeT</code> and do something similar!</p>
<hr />
<p>STM implements Alternative! A "transaction" is considered to have
<strong>failed</strong> if it ever needs to <strong>block</strong> on a
variable or channel, or someone calls <code>retry</code>.</p>
<p>Check out this nifty implementation of a structure-preserving
"multi-channel-select":</p>
<div class="sourceCode" id="cb32"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb32-1"><a href="#cb32-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Data.Map</span> <span class="kw">as</span> <span class="dt">M</span></span>
<span id="cb32-2"><a href="#cb32-2" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="kw">import</span> <span class="dt">Control.Concurrent.STM</span></span>
<span id="cb32-3"><a href="#cb32-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb32-4"><a href="#cb32-4" aria-hidden="true" tabindex="-1"></a><span class="co">-- Initialize some new channels</span></span>
<span id="cb32-5"><a href="#cb32-5" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> [a, b, c] <span class="ot">&lt;-</span> <span class="fu">sequenceA</span> <span class="op">$</span> [newTChanIO, newTChanIO, newTChanIO]</span>
<span id="cb32-6"><a href="#cb32-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb32-7"><a href="#cb32-7" aria-hidden="true" tabindex="-1"></a><span class="co">-- Build a map of the channels keyed by their name</span></span>
<span id="cb32-8"><a href="#cb32-8" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> chans <span class="ot">=</span> M.fromList [(<span class="ch">&#39;a&#39;</span>, a), (<span class="ch">&#39;b&#39;</span>, b), (<span class="ch">&#39;c&#39;</span>, c)]<span class="ot"> ::</span> <span class="dt">M.Map</span> <span class="dt">Char</span> (<span class="dt">TChan</span> <span class="dt">Int</span>)</span>
<span id="cb32-9"><a href="#cb32-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb32-10"><a href="#cb32-10" aria-hidden="true" tabindex="-1"></a><span class="co">-- Write some data into only channels &#39;a&#39; and &#39;b&#39;</span></span>
<span id="cb32-11"><a href="#cb32-11" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> atomically <span class="op">$</span> writeTChan a <span class="dv">1</span> <span class="op">&gt;&gt;</span> writeTChan b <span class="dv">2</span></span>
<span id="cb32-12"><a href="#cb32-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb32-13"><a href="#cb32-13" aria-hidden="true" tabindex="-1"></a><span class="co">-- Get a filtered map of only the channels that have data available!</span></span>
<span id="cb32-14"><a href="#cb32-14" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> atomically <span class="op">.</span> withered readTChan <span class="op">$</span> M.fromList [(<span class="ch">&#39;a&#39;</span>, a), (<span class="ch">&#39;b&#39;</span>, b), (<span class="ch">&#39;c&#39;</span>, c)]</span>
<span id="cb32-15"><a href="#cb32-15" aria-hidden="true" tabindex="-1"></a>fromList [(<span class="ch">&#39;a&#39;</span>,<span class="dv">1</span>),(<span class="ch">&#39;b&#39;</span>,<span class="dv">2</span>)]</span>
<span id="cb32-16"><a href="#cb32-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb32-17"><a href="#cb32-17" aria-hidden="true" tabindex="-1"></a><span class="co">-- Now that we&#39;ve consumed the values, the channels are all empty, so we get an empty map!</span></span>
<span id="cb32-18"><a href="#cb32-18" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> atomically <span class="op">.</span> withered readTChan <span class="op">$</span> M.fromList [(<span class="ch">&#39;a&#39;</span>, a), (<span class="ch">&#39;b&#39;</span>, b), (<span class="ch">&#39;c&#39;</span>, c)]</span>
<span id="cb32-19"><a href="#cb32-19" aria-hidden="true" tabindex="-1"></a>fromList []</span></code></pre></div>
<hr />
<p>If we require <code>Monad</code> in addition to
<code>Alternative</code> we get power equivalent to
<code>MonadPlus</code> and can actually filter on the
<strong>results</strong> of computations rather than the arguments to
them!</p>
<div class="sourceCode" id="cb33"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb33-1"><a href="#cb33-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- We need an additional Monad constraint, so we&#39;ll add some new type aliases</span></span>
<span id="cb33-2"><a href="#cb33-2" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">Selector&#39;</span> s a <span class="ot">=</span> <span class="dt">Selector</span> s s a a</span>
<span id="cb33-3"><a href="#cb33-3" aria-hidden="true" tabindex="-1"></a><span class="co">-- We could optionally just use MonadPlus here since it&#39;s equivalent to Alternative + Monad</span></span>
<span id="cb33-4"><a href="#cb33-4" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">Selector</span> s t a b <span class="ot">=</span> <span class="kw">forall</span> f<span class="op">.</span> (<span class="dt">Alternative</span> f, <span class="dt">Monad</span> f) <span class="ot">=&gt;</span> <span class="dt">LensLike</span> f s t a b</span>
<span id="cb33-5"><a href="#cb33-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb33-6"><a href="#cb33-6" aria-hidden="true" tabindex="-1"></a><span class="co">-- Conditionally fail a branch based on a predicate over the RESULT of a computation</span></span>
<span id="cb33-7"><a href="#cb33-7" aria-hidden="true" tabindex="-1"></a><span class="ot">selectResult ::</span> (b <span class="ot">-&gt;</span> <span class="dt">Bool</span>) <span class="ot">-&gt;</span> <span class="dt">Selector</span> a b a b</span>
<span id="cb33-8"><a href="#cb33-8" aria-hidden="true" tabindex="-1"></a>selectResult p f a <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb33-9"><a href="#cb33-9" aria-hidden="true" tabindex="-1"></a>    f a <span class="op">&gt;&gt;=</span> \<span class="kw">case</span></span>
<span id="cb33-10"><a href="#cb33-10" aria-hidden="true" tabindex="-1"></a>      b <span class="op">|</span> p b <span class="ot">-&gt;</span> <span class="fu">pure</span> b</span>
<span id="cb33-11"><a href="#cb33-11" aria-hidden="true" tabindex="-1"></a>        <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">-&gt;</span> empty</span></code></pre></div>
<p>We can use this to build a combinator that filters out any "empty"
lists from a map AFTER we've done the initial filtering using
wither:</p>
<div class="sourceCode" id="cb34"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb34-1"><a href="#cb34-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> xs <span class="ot">=</span> M.fromList [(<span class="ch">&#39;a&#39;</span>, [<span class="dv">1</span>, <span class="dv">3</span>, <span class="dv">5</span>]), (<span class="ch">&#39;b&#39;</span>, [<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>])]</span>
<span id="cb34-2"><a href="#cb34-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- Original version, even though we &quot;wither&quot; we still end up with empty lists!</span></span>
<span id="cb34-3"><a href="#cb34-3" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> xs <span class="op">&amp;</span> filterOf (withered <span class="op">.</span> withered) <span class="fu">even</span> </span>
<span id="cb34-4"><a href="#cb34-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> (fromList [(<span class="ch">&#39;a&#39;</span>,[]),(<span class="ch">&#39;b&#39;</span>,[<span class="dv">2</span>])])</span>
<span id="cb34-5"><a href="#cb34-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb34-6"><a href="#cb34-6" aria-hidden="true" tabindex="-1"></a><span class="co">-- How annoying, we can clean those up by adding an additional filter which</span></span>
<span id="cb34-7"><a href="#cb34-7" aria-hidden="true" tabindex="-1"></a><span class="co">-- withers the containing map and kills empty lists!</span></span>
<span id="cb34-8"><a href="#cb34-8" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> xs <span class="op">&amp;</span> filterOf (withered <span class="op">.</span> selectResult (<span class="fu">not</span> <span class="op">.</span> <span class="fu">null</span>) <span class="op">.</span> withered) <span class="fu">even</span> </span>
<span id="cb34-9"><a href="#cb34-9" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> (fromList [(<span class="ch">&#39;b&#39;</span>,[<span class="dv">2</span>])])</span></code></pre></div>
<p>We can of course mix &amp; match result filters with any of our other
guards.</p>
<hr />
<p>When building traversals we don't just always use
<code>traverse</code>, sometimes we write custom traversals; anything of
that matches the <code>LensLike</code> shape will compose well with
other optics!</p>
<p>With that in mind, we can write custom <code>Wither</code>s too!</p>
<p>Here's one that allows us to "delete" the email field of a user!</p>
<div class="sourceCode" id="cb35"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb35-1"><a href="#cb35-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">Name</span> <span class="ot">=</span> <span class="dt">String</span></span>
<span id="cb35-2"><a href="#cb35-2" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">Email</span> <span class="ot">=</span> <span class="dt">String</span></span>
<span id="cb35-3"><a href="#cb35-3" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">User</span> <span class="ot">=</span></span>
<span id="cb35-4"><a href="#cb35-4" aria-hidden="true" tabindex="-1"></a>     <span class="dt">User</span> <span class="dt">Name</span></span>
<span id="cb35-5"><a href="#cb35-5" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span>  <span class="dt">UserWithEmail</span> <span class="dt">Name</span> <span class="dt">Email</span></span>
<span id="cb35-6"><a href="#cb35-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>, <span class="dt">Ord</span>)</span>
<span id="cb35-7"><a href="#cb35-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb35-8"><a href="#cb35-8" aria-hidden="true" tabindex="-1"></a><span class="ot">witherEmail ::</span> <span class="dt">Wither&#39;</span> <span class="dt">User</span> <span class="dt">Email</span></span>
<span id="cb35-9"><a href="#cb35-9" aria-hidden="true" tabindex="-1"></a>witherEmail _ (<span class="dt">User</span> name) <span class="ot">=</span> <span class="fu">pure</span> <span class="op">$</span> <span class="dt">User</span> name</span>
<span id="cb35-10"><a href="#cb35-10" aria-hidden="true" tabindex="-1"></a>witherEmail f (<span class="dt">UserWithEmail</span> name emailStr) <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb35-11"><a href="#cb35-11" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- Check whether the operation over email succeeded or failed</span></span>
<span id="cb35-12"><a href="#cb35-12" aria-hidden="true" tabindex="-1"></a>    optional (f emailStr) <span class="op">&lt;&amp;&gt;</span> \<span class="kw">case</span></span>
<span id="cb35-13"><a href="#cb35-13" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Just</span> e <span class="ot">-&gt;</span> <span class="dt">UserWithEmail</span> name e</span>
<span id="cb35-14"><a href="#cb35-14" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Nothing</span> <span class="ot">-&gt;</span> <span class="dt">User</span> name</span></code></pre></div>
<p>Here're two users, one email is valid the other isn't</p>
<div class="sourceCode" id="cb36"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb36-1"><a href="#cb36-1" aria-hidden="true" tabindex="-1"></a><span class="ot">users ::</span> [<span class="dt">User</span>]</span>
<span id="cb36-2"><a href="#cb36-2" aria-hidden="true" tabindex="-1"></a>users <span class="ot">=</span></span>
<span id="cb36-3"><a href="#cb36-3" aria-hidden="true" tabindex="-1"></a>    [ <span class="dt">UserWithEmail</span> <span class="st">&quot;bob&quot;</span> <span class="st">&quot;invalid email&quot;</span></span>
<span id="cb36-4"><a href="#cb36-4" aria-hidden="true" tabindex="-1"></a>    , <span class="dt">UserWithEmail</span> <span class="st">&quot;alice&quot;</span> <span class="st">&quot;alice@example.com&quot;</span></span>
<span id="cb36-5"><a href="#cb36-5" aria-hidden="true" tabindex="-1"></a>    ]</span>
<span id="cb36-6"><a href="#cb36-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb36-7"><a href="#cb36-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb36-8"><a href="#cb36-8" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> users <span class="op">&amp;</span> <span class="fu">traverse</span> <span class="op">.</span> witherEmail <span class="op">%%~</span> guarding (<span class="fu">elem</span> <span class="ch">&#39;@&#39;</span>)</span>
<span id="cb36-9"><a href="#cb36-9" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> [<span class="dt">User</span> <span class="st">&quot;bob&quot;</span>,<span class="dt">UserWithEmail</span> <span class="st">&quot;alice&quot;</span> <span class="st">&quot;alice@example.com&quot;</span>]</span></code></pre></div>
<p>Notice how our custom wither has "caught" the failure when operating
over email, and instead of simply removing the user from the list it has
instead reconstructed it as a User without an email! Pretty cool!</p>
<h2 id="conclusion">Conclusion</h2>
<p>Anyways, I think that's enough from me for now. If there's interest I
can look into merging some tools from this post into the
<code>witherable</code> package itself, or perhaps spin off a new
<code>lens-witherable</code> package to contain it.</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Silly job interview questions in Haskell</title>
      <link href="https://chrispenner.ca/posts/interview"/>
      <id>https://chrispenner.ca/posts/interview</id>
      <updated>2020-10-14T00:00:00Z</updated>
      <summary>Implementations of various silly job interview questions in Haskell</summary>
      <content type="html"><![CDATA[
              <p>Today I thought it'd be fun to take a look at a few common &amp;
simple "interview questions" in Haskell. These sorts of questions are
often used to establish whether someone has programming and problem
solving skills, and I thought it might be useful for folks to see how
they play out in Haskell since our beloved language's solutions tend to
follow a different paradigm than most other languages do. I'll withhold
any judgement on whether these questions are in any way helpful in
determining programming skill whatsoever 😅; please don't @ me about
it.</p>
<h2 id="palindromes">Palindromes</h2>
<p>Let's start off nice and easy with the standard "is it a palindrome"
question! The task is to write a function which determines whether a
given string is a palindrome (i.e. whether it reads the same in both
reverse and forwards)</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">isPalindrome ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Bool</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>isPalindrome str <span class="ot">=</span> str <span class="op">==</span> <span class="fu">reverse</span> str</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> isPalindrome <span class="st">&quot;racecar&quot;</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> isPalindrome <span class="st">&quot;hello world!&quot;</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="dt">False</span></span></code></pre></div>
<p>That'll do it! Not much to say about this one, it's nice that our
definition roughly matches an English sentence describing the problem
"does a given string equal itself in reverse". I'll leave it as an
exercise for the reader to expand it to handle differences in
capitalization however you like.</p>
<h2 id="fizz-buzz">Fizz Buzz</h2>
<p>Next up is the infamous Fizz Buzz! For the 3 of you who are
unfamiliar, for each number from 1 to 100 we need to print out "Fizz" if
it's divisible by 3, "Buzz" if it's divisible by 5, and "Fizz Buzz" if
it's divisible by both 3 AND 5! Otherwise we print the number
itself.</p>
<p>Let's see it!</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">import</span> <span class="dt">Data.Foldable</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="ot">fizzle ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">String</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>fizzle n</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> n <span class="ot">`mod`</span> <span class="dv">3</span> <span class="op">==</span> <span class="dv">0</span> <span class="op">&amp;&amp;</span> n <span class="ot">`mod`</span> <span class="dv">5</span> <span class="op">==</span> <span class="dv">0</span> <span class="ot">=</span> <span class="st">&quot;Fizz Buzz!&quot;</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> n <span class="ot">`mod`</span> <span class="dv">3</span> <span class="op">==</span> <span class="dv">0</span> <span class="ot">=</span> <span class="st">&quot;Fizz!&quot;</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> n <span class="ot">`mod`</span> <span class="dv">5</span> <span class="op">==</span> <span class="dv">0</span> <span class="ot">=</span> <span class="st">&quot;Buzz!&quot;</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="fu">show</span> n</span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a><span class="ot">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a>    for_ [<span class="dv">1</span><span class="op">..</span><span class="dv">100</span>] (<span class="fu">putStrLn</span> <span class="op">.</span> fizzle)</span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-15"><a href="#cb2-15" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> main</span>
<span id="cb2-16"><a href="#cb2-16" aria-hidden="true" tabindex="-1"></a><span class="dv">1</span></span>
<span id="cb2-17"><a href="#cb2-17" aria-hidden="true" tabindex="-1"></a><span class="dv">2</span></span>
<span id="cb2-18"><a href="#cb2-18" aria-hidden="true" tabindex="-1"></a><span class="dt">Fizz</span><span class="op">!</span></span>
<span id="cb2-19"><a href="#cb2-19" aria-hidden="true" tabindex="-1"></a><span class="dv">4</span></span>
<span id="cb2-20"><a href="#cb2-20" aria-hidden="true" tabindex="-1"></a><span class="dt">Buzz</span><span class="op">!</span></span>
<span id="cb2-21"><a href="#cb2-21" aria-hidden="true" tabindex="-1"></a><span class="dt">Fizz</span><span class="op">!</span></span>
<span id="cb2-22"><a href="#cb2-22" aria-hidden="true" tabindex="-1"></a><span class="dv">7</span></span>
<span id="cb2-23"><a href="#cb2-23" aria-hidden="true" tabindex="-1"></a><span class="dv">8</span></span>
<span id="cb2-24"><a href="#cb2-24" aria-hidden="true" tabindex="-1"></a><span class="dt">Fizz</span><span class="op">!</span></span>
<span id="cb2-25"><a href="#cb2-25" aria-hidden="true" tabindex="-1"></a><span class="dt">Buzz</span><span class="op">!</span></span>
<span id="cb2-26"><a href="#cb2-26" aria-hidden="true" tabindex="-1"></a><span class="dv">11</span></span>
<span id="cb2-27"><a href="#cb2-27" aria-hidden="true" tabindex="-1"></a><span class="dt">Fizz</span><span class="op">!</span></span>
<span id="cb2-28"><a href="#cb2-28" aria-hidden="true" tabindex="-1"></a><span class="dv">13</span></span>
<span id="cb2-29"><a href="#cb2-29" aria-hidden="true" tabindex="-1"></a><span class="dv">14</span></span>
<span id="cb2-30"><a href="#cb2-30" aria-hidden="true" tabindex="-1"></a><span class="dt">Fizz</span> <span class="dt">Buzz</span><span class="op">!</span></span>
<span id="cb2-31"><a href="#cb2-31" aria-hidden="true" tabindex="-1"></a><span class="dv">16</span></span>
<span id="cb2-32"><a href="#cb2-32" aria-hidden="true" tabindex="-1"></a><span class="co">-- ...you get the idea</span></span></code></pre></div>
<p>I write a helper function "fizzle" here which converts a number into
its appropriate string so I can keep the "printing" logic separate,
which is good programming style in Haskell as it makes things easier to
both test and reason about.</p>
<p>We can see that "case analysis" is very helpful for these sorts of
problems, I'm using "pattern guards" to do a sort of multi-way if
statement. Since "divisible by both 3 &amp; 5" overlaps with the other
conditions and also is the most restrictive, we check for that one
first, then check the other two cases falling back on returning the
string version of the number itself. It all works beautifully!</p>
<p>I really enjoy looking at this problem as an example of how Haskell
is different from other languages. Most things in Haskell are
<em>functions</em>, even our loops are just higher-order functions! The
nice thing about that is that functions are <em>composable</em> and have
very clean boundaries, which means we don't need to intermingle the
<strong>syntax</strong> of a <strong>for-loop</strong> with our logic.
It's these same principles which allow us to easily separate our
<em>effectful</em> printing logic from our function which computes the
output string.</p>
<p>The next difference we can see is that we use pattern-matching,
specifically "pattern guards", which allow us to select which definition
of a function we want to use. It looks a bit like a glorified
if-statement, but I find it's less syntactic noise once you get used to
it, and there are many more things pattern guards can do!</p>
<p>All that's left is to loop over all the numbers and print them out
one by one, which is a snap thanks to the <code>for_</code>
function!</p>
<p>Next!</p>
<h3 id="sum-up-to-n-problem">Sum up to N problem</h3>
<p>Here's a less-common problem that nonetheless I've still heard a few
times! I think it was in one of my algorithms assignments back in the
day...</p>
<p>The task is to take a <strong>list of numbers</strong> and find any
<strong>combinations of <em>3</em> numbers</strong> which add up to a
specified total. For instance, if we want to determine all combinations
of <strong>3</strong> numbers which add up to <strong>15</strong>, we'd
expect our result to look something like 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="op">&gt;&gt;&gt;</span> sumToN <span class="dv">15</span> [<span class="dv">2</span>, <span class="dv">5</span>, <span class="dv">3</span>, <span class="dv">10</span>, <span class="dv">4</span>, <span class="dv">1</span>, <span class="dv">0</span>]</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>[[<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">10</span>],[<span class="dv">5</span>,<span class="dv">10</span>,<span class="dv">0</span>],[<span class="dv">10</span>,<span class="dv">4</span>,<span class="dv">1</span>]]</span></code></pre></div>
<p>Notice how each inner list sums to 15? We only care about
<em>combinations</em> here, not <em>permutations</em>, so we have
<code>[2, 3, 10]</code>, but don't bother with
<code>[3, 2, 10]</code>!</p>
<p>So how will we set about implementing an algorithm for this? Well,
the first thing to come to mind here is that we're finding
<em>combinations</em>, then we're filtering them down to match a
predicate!</p>
<p>In Haskell we like to split problems into smaller composable pieces,
the filter part should be pretty easy, so let's tackle the combinations
problem first.</p>
<p>After a quick look through hackage it looks like there <em>is</em> a
<a
href="https://hackage.haskell.org/package/base-4.14.0.0/docs/Data-List.html#v:permutations"><code>permutations</code></a>
function, but strangely there's no <code>combinations</code> function! I
suppose we could somehow try to de-duplicate the output of
<code>permutations</code>, but it'll be fun to write our own version!
<code>combinations</code> are quite nice to compute recursively, so
let's try it that way!</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">combinations ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> [a] <span class="ot">-&gt;</span> [[a]]</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- Only one way to get zero things</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>combinations <span class="dv">0</span> _ <span class="ot">=</span> [[]]</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>combinations n (x<span class="op">:</span>xs) <span class="ot">=</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- Get all combinations containing x by appending x to all (n-1)</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- combinations of the rest of the list</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>    <span class="fu">fmap</span> (x<span class="op">:</span>) (combinations (n<span class="op">-</span><span class="dv">1</span>) xs)</span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- Combine it with all combinations from the rest of the list</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>      <span class="op">&lt;&gt;</span> combinations n xs</span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a><span class="co">-- No elements means no combinations!</span></span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a>combinations _ [] <span class="ot">=</span> []</span></code></pre></div>
<p>Here we're using pattern matching and recursion to do our dirty work.
First we can confidently say that there's only ONE way to get 0 elements
from <strong>any</strong> list of elements, so we can fill that in. Next
we'll handle a single step, if we have at least one element left in the
list, we can compute all the combinations which contain that element by
prepending it to all the combinations of size <code>n-1</code> from the
remainder of the list; and we'll concatenate that with all the
combinations of the <strong>rest</strong> of the list.</p>
<p>Lastly we add one more pattern match which handles all invalid inputs
(either negative numbers or empty lists) and simply assert that they
have no valid combinations.</p>
<p>Let's try out our implementation before we move on to the next
part.</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> combinations <span class="dv">3</span> [<span class="dv">1</span><span class="op">..</span><span class="dv">5</span>]</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>[[<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>],[<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">4</span>],[<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">5</span>],[<span class="dv">1</span>,<span class="dv">3</span>,<span class="dv">4</span>],[<span class="dv">1</span>,<span class="dv">3</span>,<span class="dv">5</span>],[<span class="dv">1</span>,<span class="dv">4</span>,<span class="dv">5</span>],[<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>],[<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">5</span>],[<span class="dv">2</span>,<span class="dv">4</span>,<span class="dv">5</span>],[<span class="dv">3</span>,<span class="dv">4</span>,<span class="dv">5</span>]]</span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> combinations <span class="dv">2</span> [<span class="dv">1</span><span class="op">..</span><span class="dv">4</span>]</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">1</span>,<span class="dv">3</span>],[<span class="dv">1</span>,<span class="dv">4</span>],[<span class="dv">2</span>,<span class="dv">3</span>],[<span class="dv">2</span>,<span class="dv">4</span>],[<span class="dv">3</span>,<span class="dv">4</span>]]</span></code></pre></div>
<p>Feel free to take the time to convince yourself that these are
correct 😀</p>
<p>To finish it off we need to find any of these combinations which add
up to our target number.</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">sumNToTotal ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> [<span class="dt">Int</span>] <span class="ot">-&gt;</span> [[<span class="dt">Int</span>]]</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>sumNToTotal n totalNeeded xs <span class="ot">=</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>    <span class="fu">filter</span> matchesSum (combinations n xs)</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>    matchesSum ys <span class="ot">=</span> <span class="fu">sum</span> ys <span class="op">==</span> totalNeeded</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>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> sumNToTotal <span class="dv">3</span> <span class="dv">15</span> [<span class="dv">2</span>, <span class="dv">5</span>, <span class="dv">3</span>, <span class="dv">10</span>, <span class="dv">4</span>, <span class="dv">1</span>, <span class="dv">0</span>]</span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a>[[<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">10</span>],[<span class="dv">5</span>,<span class="dv">10</span>,<span class="dv">0</span>],[<span class="dv">10</span>,<span class="dv">4</span>,<span class="dv">1</span>]]</span></code></pre></div>
<p>Great! We can simply get all possible combinations and filter out the
results which don't properly sum to the expected number. One other nifty
thing here is that, because Haskell is <strong>lazy</strong>, if we only
need to find the <strong>first</strong> valid combination, we could just
grab the first result of the list and Haskell won't do any more work
than absolutely necessary.</p>
<p>But wait! There's a surprise <strong>part two</strong> of this
problem:</p>
<p>We now have to find all combinations of ANY length which sum to a
target number, lucky for us, that's pretty easy for us to adapt for!</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">sumAnyToTarget ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> [<span class="dt">Int</span>] <span class="ot">-&gt;</span> [[<span class="dt">Int</span>]]</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>sumAnyToTarget totalNeeded xs</span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>  <span class="ot">=</span> <span class="fu">foldMap</span> (\n <span class="ot">-&gt;</span> sumNToTotal n totalNeeded xs) [<span class="dv">0</span><span class="op">..</span><span class="fu">length</span> xs]</span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> sumAnyToTarget <span class="dv">15</span> [<span class="dv">2</span>, <span class="dv">5</span>, <span class="dv">3</span>, <span class="dv">10</span>, <span class="dv">4</span>, <span class="dv">1</span>, <span class="dv">0</span>]</span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>[ [<span class="dv">5</span>,<span class="dv">10</span>]</span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a>, [<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">10</span>]</span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a>, [<span class="dv">5</span>,<span class="dv">10</span>,<span class="dv">0</span>]</span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a>, [<span class="dv">10</span>,<span class="dv">4</span>,<span class="dv">1</span>]</span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a>, [<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">10</span>,<span class="dv">0</span>]</span>
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a>, [<span class="dv">10</span>,<span class="dv">4</span>,<span class="dv">1</span>,<span class="dv">0</span>]</span>
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true" tabindex="-1"></a>, [<span class="dv">2</span>,<span class="dv">5</span>,<span class="dv">3</span>,<span class="dv">4</span>,<span class="dv">1</span>]</span>
<span id="cb7-13"><a href="#cb7-13" aria-hidden="true" tabindex="-1"></a>, [<span class="dv">2</span>,<span class="dv">5</span>,<span class="dv">3</span>,<span class="dv">4</span>,<span class="dv">1</span>,<span class="dv">0</span>]</span>
<span id="cb7-14"><a href="#cb7-14" aria-hidden="true" tabindex="-1"></a>]</span></code></pre></div>
<p>This new version re-uses the <code>sumNToTotal</code> function we
wrote in the previous step! It iterates over each possible length of
combination and finds all the winning combinations using
<code>sumNToTotal</code>, then concatenates them using
<code>foldMap</code>! Works out pretty cleanly if I do say so
myself!</p>
<h2 id="check-if-two-strings-are-anagrams">Check if two strings are
anagrams</h2>
<p>For whatever reason, interviewers LOVE string manipulation questions;
so let's try another one!</p>
<p>Here our task is to determine whether two strings are anagrams of
each other. I'd say the difficulty for this one comes from thinking up
your <em>strategy</em> rather than the implementation itself. Here's how
I'd give this a go 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">import</span> <span class="dt">Data.Function</span> (on)</span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="ot">isAnagram ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Bool</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>isAnagram <span class="ot">=</span> (<span class="op">==</span>) <span class="ot">`on`</span> <span class="fu">sort</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> isAnagram <span class="st">&quot;elbow&quot;</span> <span class="st">&quot;below&quot;</span></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span></span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> isAnagram <span class="st">&quot;bored&quot;</span> <span class="st">&quot;road&quot;</span></span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a><span class="dt">False</span></span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> isAnagram <span class="st">&quot;stressed&quot;</span> <span class="st">&quot;desserts&quot;</span></span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span></span></code></pre></div>
<p>Here we're using a funky higher-order function called
<code>on</code>; <code>on</code> takes two functions, AND THEN takes two
arguments! In this case it calls "sort" on both arguments, then checks
if the sorted results are equal! It turns out this is sufficient to know
if two strings are anagrams!</p>
<p>But wait! What's that? What if they're in differing cases! Okay
fine!</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">import</span> <span class="dt">Data.Char</span> (toLower)</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="ot">isAnagram ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Bool</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>isAnagram a b <span class="ot">=</span> (<span class="op">==</span>) <span class="ot">`on`</span> (<span class="fu">sort</span> <span class="op">.</span> <span class="fu">map</span> <span class="fu">toLower</span>)</span></code></pre></div>
<p>Happy now? No? What's that? It seems non-performant? Well yes, but
actually no!</p>
<p>While it's true that sort has an <code>O(nlogn)</code> performance
profile, one interesting thing here is that sorting is
<strong>lazy</strong> in Haskell! This means that if our two strings are
unequal, they will only be sorted far enough to determine inequality! In
fact, if the first elements of each sorted string aren't equal to each
other, then we won't bother sorting any more.</p>
<p>Sure, our function isn't perfect, but it's not bad, especially since
this is the first approach that came to mind. Compare our 2 line
solution with the <a
href="https://javarevisited.blogspot.com/2013/03/Anagram-how-to-check-if-two-string-are-anagrams-example-tutorial.html">Java
Solution</a> provided in the post which gave me the idea for this
problem. It might be more performant (though to be honest I haven't
benchmarked them), but if I'm going to be reading this code often in the
future, I'd much prefer the clearest version which performs at an
adequate level.</p>
<h2 id="min-and-max">Min and Max</h2>
<p>Here's a problem! Given a list of elements, find the smallest and
largest element of that list!</p>
<p>I'll show and discuss three different strategies for this one.</p>
<p>Here's the first:</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">simpleMinMax ::</span> <span class="dt">Ord</span> a <span class="ot">=&gt;</span> [a] <span class="ot">-&gt;</span> (a, a)</span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>simpleMinMax xs <span class="ot">=</span> (<span class="fu">minimum</span> xs, <span class="fu">maximum</span> xs)</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="op">&gt;&gt;&gt;</span> simpleMinMax [<span class="dv">3</span>, <span class="dv">1</span>, <span class="dv">10</span>, <span class="dv">5</span>]</span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>(<span class="dv">1</span>,<span class="dv">10</span>)</span></code></pre></div>
<p>This is the simplest way we could imagine doing this sort of thing;
and indeed it does work! Unfortunately, there are few skeletons from
"legacy" haskell that are hidden in this closet. Look what happens if we
try it on an empty list!</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="op">&gt;&gt;&gt;</span> simpleMinMax []</span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>(<span class="op">***</span> <span class="dt">Exception</span><span class="op">:</span> Prelude.minimum<span class="op">:</span> empty list</span></code></pre></div>
<p>Oops... Haskell isn't supposed to throw exceptions! That's okay
though, there are some other good ways to accomplish this which won't
blow up in our faces!</p>
<p>Time for the next one!</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">boundedMinMax ::</span> (<span class="dt">Bounded</span> a, <span class="dt">Ord</span> a) <span class="ot">=&gt;</span> [a] <span class="ot">-&gt;</span> (a, a)</span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>boundedMinMax xs <span class="ot">=</span> coerce <span class="op">$</span> <span class="fu">foldMap</span> (\x <span class="ot">-&gt;</span> (<span class="dt">Min</span> x, <span class="dt">Max</span> x)) xs</span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> boundedMinMax [<span class="dv">4</span>, <span class="dv">1</span>, <span class="dv">23</span>, <span class="dv">7</span>]<span class="ot"> ::</span> (<span class="dt">Int</span>, <span class="dt">Int</span>)</span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a>(<span class="dv">1</span>,<span class="dv">23</span>)</span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> boundedMinMax []<span class="ot"> ::</span> (<span class="dt">Int</span>, <span class="dt">Int</span>)</span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a>(<span class="dv">9223372036854775807</span>,<span class="op">-</span><span class="dv">9223372036854775808</span>)</span></code></pre></div>
<p>This implementation might be a bit confusing if you haven't learned
enough about Semigroups and Monoids, but don't let that scare you! These
are both very common abstractions in Haskell and are used very often and
to great effect!</p>
<p>A Semigroup is a type of interface which provides an implementation
which lets us combine multiple elements together. Haskell has two
semigroup type-wrappers which provide specific behaviour to whichever
type we wrap: <code>Min</code> and <code>Max</code>!</p>
<p>These types define a combining operation which, any time we combine
two elements, will keep only the smallest or largest value respectively!
I'm using <code>foldMap</code> here to project each list element into a
tuple of these two types which, when the list is collapsed by
<code>foldMap</code>, will all combine together and will include the
lowest and highest elements, all in a single pass!</p>
<p>So what's up with the second example? Well, it's a bit unexpected,
but not necessarily <em>wrong</em>. When we're missing any elements to
compare foldMap will use the default value for each of our type
wrappers, which it can do if they're monoids. For <code>Min</code> and
<code>Max</code> the default value is the "smallest" and "largest" value
of the wrapped type, which is defined by the <code>Bounded</code>
interface that we require in the type signature. This works okay, and
behaves as expected under <em>most</em> circumstances, but maybe we can
try one more time:</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">Data.Semigroup</span></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">minMax ::</span> <span class="dt">Ord</span> a <span class="ot">=&gt;</span> [a] <span class="ot">-&gt;</span> <span class="dt">Maybe</span> (a, a)</span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>minMax xs <span class="ot">=</span> <span class="kw">case</span> <span class="fu">foldMap</span> (\a <span class="ot">-&gt;</span> <span class="dt">Just</span> (<span class="dt">Min</span> a, <span class="dt">Max</span> a)) xs <span class="kw">of</span></span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a>                <span class="dt">Just</span> (<span class="dt">Min</span> x, <span class="dt">Max</span> y) <span class="ot">-&gt;</span> <span class="dt">Just</span> (x, y)</span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a>                _ <span class="ot">-&gt;</span> <span class="dt">Nothing</span></span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> minMax [<span class="dv">4</span>, <span class="dv">1</span>, <span class="dv">9</span>, <span class="dv">5</span>]</span>
<span id="cb13-9"><a href="#cb13-9" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> (<span class="dv">1</span>,<span class="dv">9</span>)</span>
<span id="cb13-10"><a href="#cb13-10" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> minMax []</span>
<span id="cb13-11"><a href="#cb13-11" aria-hidden="true" tabindex="-1"></a><span class="dt">Nothing</span></span></code></pre></div>
<p>Okay! This is pretty much the same, but we needed an
<strong>explicit</strong> way to correctly handle an empty list of
values. In this case, by wrapping our tuple in <code>Just</code> we
invoke the <code>Maybe</code> monoid, and remember that
<code>foldMap</code> is smart enough to return the "empty" element of
that monoid if our list is empty! That means we get <code>Nothing</code>
back if there are no elements.</p>
<p>This may seem like "magic" at first, but all of these
<em>typeclasses</em> have <strong>laws</strong> which dictate their
behaviour and make them predictable. I suggest learning more about
monoids if you have time, they're fascinating and useful!</p>
<p>This is a very "safe" implementation, in fact much safer than most
languages would offer. We explicitly return <code>Nothing</code> in the
case that the list is empty, and the <code>Maybe</code> return type
requires the caller to handle that case. I mentioned earlier how
functions are composable, and it turns out that data-types are too! If
we pair two objects with a semigroup together in a tuple, that tuple has
a semigroup instance too, which combines respective element together
when we combine tuples!</p>
<h2 id="word-frequency">Word Frequency</h2>
<p>This is a pretty popular one too!</p>
<p>The challenge this time is, given a block of text, find the most
common word!</p>
<p>Ultimately, this comes down to an understanding of
data-structures.</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="kw">import</span> <span class="dt">Data.List</span> (maximumBy)</span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Function</span> (on)</span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Data.Map</span> <span class="kw">as</span> <span class="dt">M</span></span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a><span class="ot">mostCommonWord ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> <span class="dt">String</span></span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a>mostCommonWord str <span class="ot">=</span></span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">if</span> <span class="fu">null</span> wordCounts</span>
<span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a>       <span class="kw">then</span> <span class="dt">Nothing</span></span>
<span id="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a>       <span class="kw">else</span> <span class="dt">Just</span> <span class="op">.</span> <span class="fu">fst</span> <span class="op">.</span> maximumBy (<span class="fu">compare</span> <span class="ot">`on`</span> <span class="fu">snd</span>) <span class="op">.</span> M.toList <span class="op">$</span> wordCounts</span>
<span id="cb14-10"><a href="#cb14-10" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb14-11"><a href="#cb14-11" aria-hidden="true" tabindex="-1"></a>    wordCounts <span class="ot">=</span> M.unionsWith (<span class="op">+</span>) <span class="op">.</span> <span class="fu">fmap</span> (\w <span class="ot">-&gt;</span> M.singleton w <span class="dv">1</span>) <span class="op">.</span> <span class="fu">words</span> <span class="op">$</span> str</span></code></pre></div>
<p>There's a bit more going on this time, so let's break it down a
bit!</p>
<p>In Haskell, we use "math-style" function composition using
<code>.</code>, so we read most expressions from right-to-left.</p>
<p>Let's look at the <code>wordCounts</code> binding down in the
<code>where</code> clause first. Reading from right to left, first we
use the <code>words</code> function from the built-in Prelude to split
the incoming stream into a list of words, then we create a key-value map
out of each one, consisting of the word as the key with a value of
<code>1</code> to start.</p>
<p>Now we have a list of key-value maps, and can add them up all up
key-wise using <code>unionsWith</code> from the <code>Data.Map</code>
library, this will count up the number of elements of each key and will
result in a key-value mapping where the values represent
occurrences.</p>
<p>We've got a mapping now, so let's find the largest count!</p>
<p>First things first, to be safe we'll check whether the map has any
values at all, if it doesn't then we'll return <code>Nothing</code>.
Otherwise, we can convert the map into a list of key-value pairs by
calling <code>M.toList</code>, then we can use <code>maximumBy</code> to
return the biggest element according to a comparison function that we
specify! <code>on</code> comes in handy here and we can tell it to
compare on the second element, which is the count. That will return us
the key-value pair with the largest value, then we just need to grab the
key as a result using <code>fst</code>!</p>
<p>Ultimately this is a bit of a naive implementation which won't work
well on huge texts, but it should be enough to get you through the
whiteboard portion of the interview 😄.</p>
<h2 id="summary">Summary</h2>
<p>That's all I've got for you today, nothing too revolutionary I'm
sure, but hopefully you had a bit of fun, or maybe learned a thing or
two about what code looks like in Haskell compared to your favourite
language 😄</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Generalizing &#39;jq&#39; and Traversal Systems using optics and standard monads</title>
      <link href="https://chrispenner.ca/posts/traversal-systems"/>
      <id>https://chrispenner.ca/posts/traversal-systems</id>
      <updated>2020-09-27T00:00:00Z</updated>
      <summary>We rebuild the core behaviour of &#39;jq&#39; using standard Haskell combinators
and optics</summary>
      <content type="html"><![CDATA[
              <p>Hi folks! Today I'll be chatting about <strong>Traversal
Systems</strong> like <strong>jq</strong> and <strong>XPath</strong>;
we're going to discover which properties make them useful, then see how
we can replicate their most useful behaviours in Haskell using (almost
entirely) pre-ols!existing standard Haskell tools! Let's go!</p>
<h2 id="whats-a-traversal-system">What's a Traversal System?</h2>
<p>First off I'll admit that "Traversal System" is a name I just came up
with, you probably won't find anything if you search for it (unless this
post really catches on 😉).</p>
<p>A <strong>Traversal System</strong> allows you dive deeply into a
piece of data and may allow you to fetch, query, and edit the structure
as you go while maintaining references to other pieces of the structure
to influence your work. The goal of most Traversal Systems is to make
this as painless and concise as possible. It turns out that this sort of
thing is <strong>incredibly useful</strong> for manipulating JSON,
querying HTML and CSS, working with CSVs, or even just handling standard
Haskell Records and data-types.</p>
<p>Some good examples of existing <strong>Traversal Systems</strong>
which you may have heard of include the brilliant <a
href="https://stedolan.github.io/jq/">jq</a> utility for manipulating
and querying JSON, the <strong>XPath</strong> language for querying XML,
and the <a href="https://github.com/noprompt/meander">meander</a> data
manipulation system in Clojure. Although each of these systems may
appear drastically different at a glance, they both <em>accomplish many
of the same goals</em> of manipulating and querying data in a concise
way.</p>
<p>The similarities between these systems intrigued me! They seem so
similar, but yet still seem to share very little in the way of
structure, syntax, and prior art. They re-invent the wheel for each new
data type! Ideally we could recognize the useful behaviours in each
system and build a generalized system which works for any data type.</p>
<p>This post is an attempt to do exactly that; we'll take a look at a
few things that these systems do well, then we'll re-build them in
Haskell using standard tooling, all the while abstracting over the type
of data!</p>
<h2 id="optics-as-a-basis-for-a-traversal-system">Optics as a basis for
a traversal system</h2>
<p>For any of those who know me it should be no surprise that my first
thought was to look at optics (i.e. Lenses and Traversals). In general I
find that optics solve a lot of my problems, but in this case they are
particularly appropriate! Optics inherently deal with the idea of diving
deep into data and querying or updating data in a structured and
compositional fashion.</p>
<p>In addition, optics also allow abstracting over the data type they
work on. There are pre-existing libraries of optics for working with
JSON via <a
href="https://hackage.haskell.org/package/lens-aeson"><code>lens-aeson</code></a>
and for html via <a
href="https://hackage.haskell.org/package/taggy-lens"><code>taggy-lens</code></a>.
I've written optics libraries for working with <a
href="https://hackage.haskell.org/package/lens-csv">CSVs</a> and even <a
href="https://hackage.haskell.org/package/lens-regex-pcre">Regular
Expressions</a>, so I can say confidently that they're a brilliantly
adaptable tool for data manipulation.</p>
<p>It also happens that optics are well-principled and mathematically
sound, so they're a good tool for studying the properties that a system
like this may have.</p>
<p>However, optics themselves don't provide everything we need! Optics
are rather obtuse, in fact I wrote <a
href="https://leanpub.com/optics-by-example">a whole book</a> to help
teach them, and they lack clarity and easy of use when it comes to
building larger expressions. It's also pretty tough to work on one part
of a data structure while referencing data in another part of the same
structure. My hope is to address some of these short comings in this
post.</p>
<p>In this particular post I'm mostly interested in explaining a
framework for traversal systems in Haskell, we'll be using many standard
<a
href="https://hackage.haskell.org/package/mtl"><strong>mtl</strong></a>
Monad Transformers alongside a lot of combinators from the <a
href="https://hackage.haskell.org/package/lens"><strong>lens</strong></a>
library. You won't need to understand any of these intimately to get the
<em>gist</em> of what's going on, but I won't be explaining them in
depth here, so you may need to look elsewhere if you're lacking a bit of
context.</p>
<h2 id="establishing-the-problem">Establishing the Problem</h2>
<p>I'll be demoing a few examples as we go along so let's set up some
data. I'll be working in both <strong>jq</strong> and
<strong>Haskell</strong> to make comparisons between them, so we'll set
up the same data in both <strong>JSON</strong> and Haskell.</p>
<p>Here's a funny lil' company as a JSON object:</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode json"><code class="sourceCode json"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>    <span class="dt">&quot;staff&quot;</span><span class="fu">:</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>      <span class="ot">[</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>        <span class="fu">{</span> <span class="dt">&quot;id&quot;</span><span class="fu">:</span> <span class="st">&quot;1&quot;</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>        <span class="fu">,</span> <span class="dt">&quot;name&quot;</span><span class="fu">:</span> <span class="st">&quot;bob&quot;</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>        <span class="fu">,</span> <span class="dt">&quot;pets&quot;</span><span class="fu">:</span> <span class="ot">[</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>              <span class="fu">{</span> <span class="dt">&quot;name&quot;</span><span class="fu">:</span> <span class="st">&quot;Rocky&quot;</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>              <span class="fu">,</span> <span class="dt">&quot;type&quot;</span><span class="fu">:</span> <span class="st">&quot;cat&quot;</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>              <span class="fu">}</span><span class="ot">,</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>              <span class="fu">{</span> <span class="dt">&quot;name&quot;</span><span class="fu">:</span> <span class="st">&quot;Bullwinkle&quot;</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>              <span class="fu">,</span> <span class="dt">&quot;type&quot;</span><span class="fu">:</span> <span class="st">&quot;dog&quot;</span></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a>              <span class="fu">}</span></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a>            <span class="ot">]</span></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a>        <span class="fu">}</span><span class="ot">,</span></span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a>        <span class="fu">{</span> <span class="dt">&quot;id&quot;</span><span class="fu">:</span> <span class="st">&quot;2&quot;</span></span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a>        <span class="fu">,</span> <span class="dt">&quot;name&quot;</span><span class="fu">:</span> <span class="st">&quot;sally&quot;</span></span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a>        <span class="fu">,</span> <span class="dt">&quot;pets&quot;</span><span class="fu">:</span> <span class="ot">[</span></span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a>              <span class="fu">{</span> <span class="dt">&quot;name&quot;</span><span class="fu">:</span> <span class="st">&quot;Inigo&quot;</span></span>
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a>              <span class="fu">,</span> <span class="dt">&quot;type&quot;</span><span class="fu">:</span> <span class="st">&quot;cat&quot;</span></span>
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a>              <span class="fu">}</span></span>
<span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a>            <span class="ot">]</span></span>
<span id="cb1-22"><a href="#cb1-22" aria-hidden="true" tabindex="-1"></a>        <span class="fu">}</span></span>
<span id="cb1-23"><a href="#cb1-23" aria-hidden="true" tabindex="-1"></a>      <span class="ot">]</span><span class="fu">,</span></span>
<span id="cb1-24"><a href="#cb1-24" aria-hidden="true" tabindex="-1"></a>    <span class="dt">&quot;salaries&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb1-25"><a href="#cb1-25" aria-hidden="true" tabindex="-1"></a>        <span class="dt">&quot;1&quot;</span><span class="fu">:</span> <span class="dv">12</span><span class="fu">,</span></span>
<span id="cb1-26"><a href="#cb1-26" aria-hidden="true" tabindex="-1"></a>        <span class="dt">&quot;2&quot;</span><span class="fu">:</span> <span class="dv">15</span></span>
<span id="cb1-27"><a href="#cb1-27" aria-hidden="true" tabindex="-1"></a>    <span class="fu">}</span></span>
<span id="cb1-28"><a href="#cb1-28" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
<p>And here's the same data in its Haskell representation, complete with
generated optics for each record field.</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">data</span> <span class="dt">Company</span> <span class="ot">=</span> <span class="dt">Company</span> {<span class="ot"> _staff ::</span> [<span class="dt">Employee</span>]</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>                       ,<span class="ot"> _salaries ::</span> <span class="dt">M.Map</span> <span class="dt">Int</span> <span class="dt">Int</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>                       } <span class="kw">deriving</span> <span class="dt">Show</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Pet</span> <span class="ot">=</span> <span class="dt">Pet</span> {<span class="ot"> _petName ::</span> <span class="dt">String</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>               ,<span class="ot"> _petType ::</span> <span class="dt">String</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>               } <span class="kw">deriving</span> <span class="dt">Show</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Employee</span> <span class="ot">=</span> <span class="dt">Employee</span> {<span class="ot"> _employeeId ::</span> <span class="dt">Int</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>                         ,<span class="ot"> _employeeName ::</span> <span class="dt">String</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>                         ,<span class="ot"> _employeePets ::</span> [<span class="dt">Pet</span>]</span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>                         } <span class="kw">deriving</span> <span class="dt">Show</span></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a>makeLenses &#39;<span class="dt">&#39;Company</span></span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a>makeLenses &#39;<span class="dt">&#39;Pet</span></span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a>makeLenses &#39;<span class="dt">&#39;Employee</span></span>
<span id="cb2-15"><a href="#cb2-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-16"><a href="#cb2-16" aria-hidden="true" tabindex="-1"></a><span class="ot">company ::</span> <span class="dt">Company</span></span>
<span id="cb2-17"><a href="#cb2-17" aria-hidden="true" tabindex="-1"></a>company <span class="ot">=</span> <span class="dt">Company</span> [ <span class="dt">Employee</span> <span class="dv">1</span> <span class="st">&quot;bob&quot;</span> [<span class="dt">Pet</span> <span class="st">&quot;Rocky&quot;</span> <span class="st">&quot;cat&quot;</span>, <span class="dt">Pet</span> <span class="st">&quot;Bullwinkle&quot;</span> <span class="st">&quot;dog&quot;</span>] </span>
<span id="cb2-18"><a href="#cb2-18" aria-hidden="true" tabindex="-1"></a>                  , <span class="dt">Employee</span> <span class="dv">2</span> <span class="st">&quot;sally&quot;</span> [<span class="dt">Pet</span> <span class="st">&quot;Inigo&quot;</span> <span class="st">&quot;cat&quot;</span>]</span>
<span id="cb2-19"><a href="#cb2-19" aria-hidden="true" tabindex="-1"></a>                  ] (M.fromList [ (<span class="dv">1</span>, <span class="dv">12</span>)</span>
<span id="cb2-20"><a href="#cb2-20" aria-hidden="true" tabindex="-1"></a>                                , (<span class="dv">2</span>, <span class="dv">15</span>)</span>
<span id="cb2-21"><a href="#cb2-21" aria-hidden="true" tabindex="-1"></a>                                ])</span></code></pre></div>
<h2 id="querying">Querying</h2>
<p>Let's dive into a few example queries to test the waters! First an
easy one, let's write a query to find all the pets owned by any of our
employees.</p>
<p>Here's how it looks in <strong>jq</strong>:</p>
<pre class="jq"><code>$ cat company.json | jq &#39;.staff[].pets[] | select(.type == &quot;cat&quot;)&#39;
{
  &quot;name&quot;: &quot;Rocky&quot;,
  &quot;type&quot;: &quot;cat&quot;
}
{
  &quot;name&quot;: &quot;Inigo&quot;,
  &quot;type&quot;: &quot;cat&quot;
}</code></pre>
<p>We look in the <code>staff</code> key, then <em>enumerate</em> that
list, then for each staff member we enumerate their cats! Lastly we
filter out anything that's not a cat.</p>
<p>We can recognize a few hallmarks of a <strong>Traversal
System</strong> here. <strong>jq</strong> allows us to "dive" down
deeper into our structure by providing a path to where we want to be. It
also allows us to <strong>enumerate</strong> many possibilities using
the <code>[]</code> operator, which will forward <strong>each</strong>
value to the rest of the pipeline one after the other. Lastly it allows
us to <strong>filter</strong> our results using <code>select</code>.</p>
<p>And in Haskell using optics it looks 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="op">&gt;&gt;&gt;</span> toListOf (staff <span class="op">.</span> folded <span class="op">.</span> employeePets <span class="op">.</span> folded <span class="op">.</span> filteredBy (petType <span class="op">.</span> only <span class="st">&quot;cat&quot;</span>)) company</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>[ <span class="dt">Pet</span> {_petName <span class="ot">=</span> <span class="st">&quot;Rocky&quot;</span>, _petType <span class="ot">=</span> <span class="st">&quot;cat&quot;</span>}</span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>, <span class="dt">Pet</span> {_petName <span class="ot">=</span> <span class="st">&quot;Inigo&quot;</span>, _petType <span class="ot">=</span> <span class="st">&quot;cat&quot;</span>}</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>]</span></code></pre></div>
<p>Here we use "toListOf" along with an optic which "folds" over each
staff member, then folds over each of their pets, again filtering for
"only" cats.</p>
<p>At a glance the two are extremely similar!</p>
<p>They each allow the <em>enumeration</em> of multiple values, in
<strong>jq</strong> using <code>[]</code> and in optics using
<code>folded</code>.</p>
<p>Both implement some form of <strong>filtering</strong>,
<strong>jq</strong> using <code>select</code> and our optics with
<code>filteredBy</code>.</p>
<p>Great! So far we've had no trouble keeping up! We're already starting
to see a lot of similarities between the two, and our solutions using
optics are easily generalizable to any data type.</p>
<p>Let's move on to a more complex example.</p>
<h2 id="keeping-references">Keeping references</h2>
<p>This time we're going to print out each pet and their owner!</p>
<p>First, here's the <strong>jq</strong>:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode sh"><code class="sourceCode bash"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> cat join.json <span class="kw">|</span> <span class="ex">jq</span> <span class="st">&#39;</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="st">    .staff[] </span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="st">  | .name as $personName </span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="st">  | .pets[] </span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="st">  | &quot;\(.name) belongs to \($personName)&quot;</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a><span class="st">&#39;</span></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;Rocky belongs to bob&quot;</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;Bullwinkle belongs to bob&quot;</span></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;Inigo belongs to sally&quot;</span></span></code></pre></div>
<p>Here we see a new feature in <strong>jq</strong> which is the ability
to maintain <strong>references</strong> to a part of the structure for
later while we continue to dig deeper into the structure. We're grabbing
the name of each employee as we enumerate them and saving it into
<code>$personName</code> so we can refer to this later on. Then we
enumerate each of the pets and use string interpolation to describe who
owns each pet.</p>
<p>If we try to stick with optics on their own, well, it's possible, but
unfortunately this is where it all starts to break down, look at this
absolute mess:</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">owners ::</span> [<span class="dt">String</span>]</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>owners <span class="ot">=</span> </span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>  company <span class="op">^..</span> </span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>    (staff <span class="op">.</span> folded <span class="op">.</span> reindexed _employeeName selfIndex <span class="op">&lt;.</span> employeePets <span class="op">.</span> folded <span class="op">.</span> petName) </span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">.</span> withIndex </span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">.</span> to (\(eName, pName) <span class="ot">-&gt;</span> pName <span class="op">&lt;&gt;</span> <span class="st">&quot; belongs to &quot;</span> <span class="op">&lt;&gt;</span> eName)</span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> owners</span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a>[ <span class="st">&quot;Rocky belongs to bob&quot;</span></span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a>, <span class="st">&quot;Bullwinkle belongs to bob&quot;</span></span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a>, <span class="st">&quot;Inigo belongs to sally&quot;</span></span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a>]</span></code></pre></div>
<p>You can bet that nobody is calling that "easy to read". Heck, I wrote
a book on optics and it still took me a few tries to figure out where
the brackets needed to go!</p>
<p>Optics are great for handling a <em>single</em> stream of values, but
they're much worse at more complex expressions, especially those which
require a reference to values that occur <em>earlier</em> in the chain.
Let's see how we can address those shortcomings as we build our
<strong>Traversal System</strong> in Haskell.</p>
<p>Just for the <strong>jq</strong> aficionados in the audience I'll
show off this alternate version which uses a little bit of
<em>magic</em> that <strong>jq</strong> does for you.</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode sh"><code class="sourceCode bash"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a> <span class="ex">$</span> cat company.json <span class="kw">|</span> <span class="ex">jq</span> <span class="st">&#39;.staff[] | &quot;\(.pets[].name) belongs to \(.name)&quot;&#39;</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;Rocky belongs to bob&quot;</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;Bullwinkle belongs to bob&quot;</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;Inigo belongs to sally&quot;</span></span></code></pre></div>
<p>Depending on your experience may be less <strong>magical</strong> and
more <strong>confusing</strong> 😬. Since the final expression contains
an <strong>enumeration</strong> (i.e. <code>\(.pets[].name)</code>)
<strong>jq</strong> will expand the final term once for each value in
the enumeration. This is really cool, but unfortunately a bit "less
principled" and tough to understand in my opinion.</p>
<p>Regardless, the behaviour is the same, and we haven't replicated it
in Haskell satisfactorily yet, let's see what we can do about that!</p>
<h2 id="monads-to-the-rescue-again">Monads to the rescue (again...)</h2>
<p>In Haskell we love our <strong>embedded DSLs</strong>; if you give a
Haskeller a problem to solve, you can bet that 9 times out of 10 they'll
solve it with a custom monad and an DSL 😂. Well, I'm sorry to tell you
that I'm no different!</p>
<p>We'll be using a monad to address the readability problem of the last
optics solution, but the question is... <em>which</em> monad?</p>
<p>Since all we're doing at the moment is <strong>querying</strong>
data, we can make use of the esteemed <strong>Reader Monad</strong> to
provide a context for our query.</p>
<p>Here's what that last query looks like when we use the <a
href="https://hackage.haskell.org/package/mtl-2.2.2/docs/Control-Monad-Reader.html"><code>Reader</code></a>
monad with the relatively lesser known <a
href="https://hackage.haskell.org/package/lens-4.19.2/docs/Control-Lens-Combinators.html#v:magnify"><code>magnify</code></a>
combinator:</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">owners&#39; ::</span> <span class="dt">Reader</span> <span class="dt">Company</span> [<span class="dt">String</span>]</span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>owners&#39; <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>    magnify (staff <span class="op">.</span> folded) <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>        personName <span class="ot">&lt;-</span> view employeeName</span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a>        magnify (employeePets <span class="op">.</span> folded) <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a>            animalName <span class="ot">&lt;-</span> view petName</span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a>            <span class="fu">return</span> [animalName <span class="op">&lt;&gt;</span> <span class="st">&quot; belongs to &quot;</span> <span class="op">&lt;&gt;</span> personName]</span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> runReader owners&#39; company</span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a>[ <span class="st">&quot;Rocky belongs to bob&quot;</span></span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a>, <span class="st">&quot;Bullwinkle belongs to bob&quot;</span></span>
<span id="cb8-12"><a href="#cb8-12" aria-hidden="true" tabindex="-1"></a>, <span class="st">&quot;Inigo belongs to sally&quot;</span></span>
<span id="cb8-13"><a href="#cb8-13" aria-hidden="true" tabindex="-1"></a>]</span></code></pre></div>
<p>I won't explain how the <code>Reader</code> monad itself works here,
so if you're a bit shaky on that you'll probably want to familiarize
yourself with that first.</p>
<p>As for <code>magnify</code>, it's a combinator from the
<code>lens</code> library which takes an <strong>optic</strong> and an
<strong>action</strong> as arguments. It uses the optic to focus a
<strong>subset</strong> of the <code>Reader</code>'s environment, then
runs the action within a Reader with that data subset as its focus. It's
just that easy!</p>
<p>One more thing! <code>magnify</code> can accept a <code>Fold</code>
which focuses <strong>multiple</strong> elements, in this case it will
run the action once for <strong>each</strong> focus, then combine all
the results together using a <strong>semigroup</strong>. In this case,
we wrapped our result in a <strong>list</strong> before returning it, so
magnify will go ahead and automatically <strong>concatenate</strong> all
the results together for us. Pretty nifty that we can get so much
functionality out of <code>magnify</code> without writing any code
ourselves!</p>
<p>We can see that rewriting the problem in this style has made it
considerably easier to read. It allows us to "pause" as we use optics to
descend and poke around a bit at any given spot. Since it's a monad and
we're using do-notation, we can easily bind any intermediate results
into names to be referenced later on; the names will correctly reference
the value from the current iteration! It's also nice that we have a
clear indication of the scope of all our bindings by looking at the
indentation of each nested do-notation block.</p>
<p>Depending on your personal style, you could write this expression
using the <code>(-&gt;)</code> monad directly, or even omit the
indentation entirely; though I don't personally recommend that. In case
you're curious, here's the way that I DON'T RECOMMEND writing this:</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">owners&#39;&#39; ::</span> <span class="dt">Company</span> <span class="ot">-&gt;</span> [<span class="dt">String</span>]</span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>owners&#39;&#39; <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>  magnify (staff <span class="op">.</span> folded) <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>  eName <span class="ot">&lt;-</span> view employeeName</span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>  magnify (employeePets <span class="op">.</span> folded) <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a>  pName <span class="ot">&lt;-</span> view petName</span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a>  <span class="fu">return</span> [pName <span class="op">&lt;&gt;</span> <span class="st">&quot; belongs to &quot;</span> <span class="op">&lt;&gt;</span> eName]</span></code></pre></div>
<h2 id="updating-deeply-nested-values">Updating deeply nested
values</h2>
<p>Okay! On to the next step! Let's say that according to our company
policy we want to give a $5 raise to anyone who owns a dog! Hey, I don't
make the rules here 🤷‍♂️. Notice that this time we're running an
<strong>update</strong> not just a <strong>query</strong>!</p>
<p>Here's one of a few different ways we could express this in
<strong>jq</strong></p>
<pre class="jq"><code>cat company.json | jq &#39;
[.staff[] | select(.pets[].type == &quot;dog&quot;) | .id] as $peopleWithDogs
| .salaries[$peopleWithDogs[]] += 5
&#39;

{
  &quot;staff&quot;: [
    {
      &quot;id&quot;: &quot;1&quot;,
      &quot;name&quot;: &quot;bob&quot;,
      &quot;pets&quot;: [
        {
          &quot;name&quot;: &quot;Rocky&quot;,
          &quot;type&quot;: &quot;cat&quot;
        },
        {
          &quot;name&quot;: &quot;Bullwinkle&quot;,
          &quot;type&quot;: &quot;dog&quot;
        }
      ]
    },
    {
      &quot;id&quot;: &quot;2&quot;,
      &quot;name&quot;: &quot;sally&quot;,
      &quot;pets&quot;: [
        {
          &quot;name&quot;: &quot;Inigo&quot;,
          &quot;type&quot;: &quot;cat&quot;
        }
      ]
    }
  ],
  &quot;salaries&quot;: {
    &quot;1&quot;: 17,
    &quot;2&quot;: 15
  }
}</code></pre>
<p>We first scan the staff to see who's worthy of a promotion, then we
iterate over each of their ids and bump up their salary, and sure enough
it works!</p>
<p>I'll admit that it took me a few tries to get this right in
<strong>jq</strong>; if you're not careful you'll
<strong>enumerate</strong> in a way that means <code>jq</code> can't
keep track of your references and you'll be unable to edit the correct
piece of the original object. For example, here's my first attempt to do
this sort of thing:</p>
<div class="sourceCode" id="cb11"><pre
class="sourceCode sh"><code class="sourceCode bash"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> cat company.json <span class="kw">|</span> <span class="ex">jq</span> <span class="st">&#39;</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="st">. as $company </span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a><span class="st">| .staff[] </span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a><span class="st">| select(.pets[].type == &quot;dog&quot;).id </span></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a><span class="st">| $company.salaries[.] += 5</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a><span class="st">&#39;</span></span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a><span class="ex">jq:</span> error <span class="er">(</span><span class="ex">at</span> <span class="op">&lt;</span>stdin<span class="op">&gt;</span>:28<span class="kw">)</span><span class="bu">:</span> Invalid path expression near attempt to access element <span class="st">&quot;salaries&quot;</span> of {<span class="st">&quot;staff&quot;</span>:[{<span class="st">&quot;id&quot;</span>:<span class="st">&quot;1&quot;</span>,<span class="st">&quot;name&quot;</span>...</span></code></pre></div>
<p>In this case it looks like <strong>jq</strong> can't edit something
we've stored as a variable; a bit surprising, but fair enough I
suppose.</p>
<p>This sort of task is tricky because it involves enumeration over one
area, storing those results, then enumerating AND updating in another!
It's definitely possible in <code>jq</code>, but some of the magic that
<strong>jq</strong> performs makes it a bit tough to know what will work
and what won't at a glance.</p>
<p>Now for the Haskell version:</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">salaryBump ::</span> <span class="dt">State</span> <span class="dt">Company</span> ()</span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>salaryBump <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>    ids <span class="ot">&lt;-</span> gets <span class="op">$</span> toListOf </span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>            ( staff </span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a>            <span class="op">.</span> traversed </span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a>            <span class="op">.</span> filteredBy (employeePets <span class="op">.</span> traversed <span class="op">.</span> petType <span class="op">.</span> only <span class="st">&quot;dog&quot;</span>) </span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a>            <span class="op">.</span> employeeId</span>
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a>            )</span>
<span id="cb12-9"><a href="#cb12-9" aria-hidden="true" tabindex="-1"></a>    for_ ids <span class="op">$</span> \id&#39; <span class="ot">-&gt;</span></span>
<span id="cb12-10"><a href="#cb12-10" aria-hidden="true" tabindex="-1"></a>        salaries <span class="op">.</span> ix id&#39; <span class="op">+=</span> <span class="dv">5</span></span>
<span id="cb12-11"><a href="#cb12-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-12"><a href="#cb12-12" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> execState salaryBump company</span>
<span id="cb12-13"><a href="#cb12-13" aria-hidden="true" tabindex="-1"></a><span class="dt">Company</span> { _staff <span class="ot">=</span> [ <span class="dt">Employee</span> { _employeeId <span class="ot">=</span> <span class="dv">1</span></span>
<span id="cb12-14"><a href="#cb12-14" aria-hidden="true" tabindex="-1"></a>                              , _employeeName <span class="ot">=</span> <span class="st">&quot;bob&quot;</span></span>
<span id="cb12-15"><a href="#cb12-15" aria-hidden="true" tabindex="-1"></a>                              , _employeePets <span class="ot">=</span> [ <span class="dt">Pet</span> { _petName <span class="ot">=</span> <span class="st">&quot;Rocky&quot;</span></span>
<span id="cb12-16"><a href="#cb12-16" aria-hidden="true" tabindex="-1"></a>                                              , _petType <span class="ot">=</span> <span class="st">&quot;cat&quot;</span></span>
<span id="cb12-17"><a href="#cb12-17" aria-hidden="true" tabindex="-1"></a>                                              }</span>
<span id="cb12-18"><a href="#cb12-18" aria-hidden="true" tabindex="-1"></a>                                        , <span class="dt">Pet</span> { _petName <span class="ot">=</span> <span class="st">&quot;Bullwinkle&quot;</span></span>
<span id="cb12-19"><a href="#cb12-19" aria-hidden="true" tabindex="-1"></a>                                              , _petType <span class="ot">=</span> <span class="st">&quot;dog&quot;</span></span>
<span id="cb12-20"><a href="#cb12-20" aria-hidden="true" tabindex="-1"></a>                                              }</span>
<span id="cb12-21"><a href="#cb12-21" aria-hidden="true" tabindex="-1"></a>                                        ]</span>
<span id="cb12-22"><a href="#cb12-22" aria-hidden="true" tabindex="-1"></a>                              }</span>
<span id="cb12-23"><a href="#cb12-23" aria-hidden="true" tabindex="-1"></a>                   , <span class="dt">Employee</span> { _employeeId <span class="ot">=</span> <span class="dv">2</span></span>
<span id="cb12-24"><a href="#cb12-24" aria-hidden="true" tabindex="-1"></a>                              , _employeeName <span class="ot">=</span> <span class="st">&quot;sally&quot;</span></span>
<span id="cb12-25"><a href="#cb12-25" aria-hidden="true" tabindex="-1"></a>                              , _employeePets <span class="ot">=</span> [<span class="dt">Pet</span> { _petName <span class="ot">=</span> <span class="st">&quot;Inigo&quot;</span></span>
<span id="cb12-26"><a href="#cb12-26" aria-hidden="true" tabindex="-1"></a>                                             , _petType <span class="ot">=</span> <span class="st">&quot;cat&quot;</span></span>
<span id="cb12-27"><a href="#cb12-27" aria-hidden="true" tabindex="-1"></a>                                             }</span>
<span id="cb12-28"><a href="#cb12-28" aria-hidden="true" tabindex="-1"></a>                                        ]</span>
<span id="cb12-29"><a href="#cb12-29" aria-hidden="true" tabindex="-1"></a>                              }</span>
<span id="cb12-30"><a href="#cb12-30" aria-hidden="true" tabindex="-1"></a>                   ]</span>
<span id="cb12-31"><a href="#cb12-31" aria-hidden="true" tabindex="-1"></a>        , _salaries <span class="ot">=</span> fromList [ (<span class="dv">1</span>, <span class="dv">17</span>)</span>
<span id="cb12-32"><a href="#cb12-32" aria-hidden="true" tabindex="-1"></a>                               , (<span class="dv">2</span>, <span class="dv">15</span>)</span>
<span id="cb12-33"><a href="#cb12-33" aria-hidden="true" tabindex="-1"></a>                               ]</span>
<span id="cb12-34"><a href="#cb12-34" aria-hidden="true" tabindex="-1"></a>      }</span></code></pre></div>
<p>You'll notice that now that we need to <strong>update</strong> a
value rather than just <strong>query</strong> I've switched from the
<code>Reader</code> monad to the <code>State</code> monad, which allows
us to keep track of our Company in a way that imitates mutable
state.</p>
<p>First we lean on optics to collect all the ids of people who have
dogs. Then, once we've got those ids we can iterate over our ids and
perform an update action using each of them. The <code>lens</code>
library includes a lot of nifty combinators for working with optics
inside the <code>State</code> monad; here we're using <code>+=</code> to
"statefully" update the salary at a given id. <code>for_</code> from
<code>Data.Foldable</code> correctly sequences each of our operations
and applies the updates one after the other.</p>
<p>When we're working inside <code>State</code> instead of
<code>Reader</code> we need to use <code>zoom</code> instead of
<code>magnify</code>; here's a rewrite of the last example which uses
<code>zoom</code> in a trivial way; but <code>zoom</code> allows us to
also edit values after we've zoomed in!</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">salaryBump ::</span> <span class="dt">State</span> <span class="dt">Company</span> ()</span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>salaryBump <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a>    ids <span class="ot">&lt;-</span> zoom ( staff </span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>                <span class="op">.</span> traversed </span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a>                <span class="op">.</span> filteredBy (employeePets <span class="op">.</span> traversed <span class="op">.</span> petType <span class="op">.</span> only <span class="st">&quot;dog&quot;</span>)</span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a>                ) <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a>              uses employeeId (<span class="op">:</span>[])</span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a>    for_ ids <span class="op">$</span> \id&#39; <span class="ot">-&gt;</span></span>
<span id="cb13-9"><a href="#cb13-9" aria-hidden="true" tabindex="-1"></a>        salaries <span class="op">.</span> ix id&#39; <span class="op">+=</span> <span class="dv">5</span></span></code></pre></div>
<h2 id="next-steps">Next Steps</h2>
<p>So hopefully by now I've convinced you that we can faithfully
re-create the core behaviours of a language like <code>jq</code> in
Haskell in a data-agnostic way! By swapping out your optics you can use
this same technique on JSON, CSVs, HTML, or anything you can dream up.
It leverages standard Haskell tools, so it composes well with Haskell
libraries, and you maintain the full power of the Haskell language so
you can easily write your own combinators to expand your vocabulary.</p>
<p>The question that remains is, where can we go from here? The answer,
of course, is that we can add more monads!</p>
<p>Although we have <code>filtered</code> and <code>filteredBy</code>
from <code>lens</code> to do filtering of our enumerations and
traversals using optics; it would be nice to have the same power when
we're inside a do-notation block! Haskell already has a stock-standard
combinator for this called <a
href="https://hackage.haskell.org/package/base-4.14.0.0/docs/Control-Monad.html#v:guard"><code>guard</code></a>.
It will "fail" in whichever monad you're working with. To work it
depends on your type having an instance of the <code>Alternative</code>
type; which unfortunately for us <code>State</code> does NOT have; so
we'll need to look for an <em>alternative</em> way to get an Alternative
instance 😂</p>
<p>The <code>MaybeT</code> monad transformer exists specifically to add
failure to other monad types, so let's integrate that! The tricky bit
here is that we want to fail only a <strong>single</strong> branch of
our computation, not the whole thing! So we'll need to "catch" any
failed branches before they merge back into the main computation.</p>
<p>Let's write a small wrapper around zoom to get the behaviour we
want.</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="kw">infixr</span> <span class="dv">0</span> <span class="op">%&gt;</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="ot">(%&gt;) ::</span> <span class="dt">Traversal&#39;</span> s e <span class="ot">-&gt;</span> <span class="dt">MaybeT</span> (<span class="dt">State</span> e) a <span class="ot">-&gt;</span> <span class="dt">MaybeT</span> (<span class="dt">State</span> s) [a]</span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a>l <span class="op">%&gt;</span> m <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a>    zoom l <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a>        <span class="co">-- Catch and embed the current branch so we don&#39;t fail the whole program</span></span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a>        a <span class="ot">&lt;-</span> lift <span class="op">$</span> runMaybeT m</span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a>        <span class="fu">return</span> (<span class="fu">maybe</span> [] (<span class="op">:</span>[]) a)</span></code></pre></div>
<p>This defines a handy new combinator for our traversal DSL which
allows us to zoom just like we did before, but the addition of
<code>MaybeT</code> allows us to easily use <code>guard</code> to prune
branches!</p>
<p>We make sure to run and re-lift the results of our action rather than
embedding them directly otherwise a single failed "guard" would fail the
<strong>entire</strong> remaining computation, which we certainly don't
want! Since each individual branch may fail, and since we've usually
been collecting our results as lists anyways, I just went ahead and
embedded our results in a list as part of the combinator, it should make
everything a bit easier to use!</p>
<p>Let's try it out! I'll rewrite the previous example, but we'll use
<code>guard</code> instead of <code>filteredBy</code> this time.</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">salaryBump&#39;&#39; ::</span> <span class="dt">MaybeT</span> (<span class="dt">State</span> <span class="dt">Company</span>) ()</span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>salaryBump&#39;&#39; <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a>    ids <span class="ot">&lt;-</span> staff <span class="op">.</span> traversed <span class="op">%&gt;</span> <span class="kw">do</span></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a>            isDog <span class="ot">&lt;-</span> employeePets <span class="op">.</span> traversed <span class="op">%&gt;</span> <span class="kw">do</span></span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a>                       uses petType (<span class="op">==</span> <span class="st">&quot;dog&quot;</span>)</span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a>            guard (<span class="fu">or</span> isDog)</span>
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a>            use employeeId</span>
<span id="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a>    for_ ids <span class="op">$</span> \id&#39; <span class="ot">-&gt;</span></span>
<span id="cb15-9"><a href="#cb15-9" aria-hidden="true" tabindex="-1"></a>        salaries <span class="op">.</span> ix id&#39; <span class="op">+=</span> <span class="dv">5</span></span>
<span id="cb15-10"><a href="#cb15-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-11"><a href="#cb15-11" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="fu">flip</span> execState company <span class="op">.</span> runMaybeT <span class="op">$</span> salaryBump&#39;&#39;</span>
<span id="cb15-12"><a href="#cb15-12" aria-hidden="true" tabindex="-1"></a><span class="dt">Company</span></span>
<span id="cb15-13"><a href="#cb15-13" aria-hidden="true" tabindex="-1"></a>{ _staff    <span class="ot">=</span></span>
<span id="cb15-14"><a href="#cb15-14" aria-hidden="true" tabindex="-1"></a>      [ <span class="dt">Employee</span> { _employeeId   <span class="ot">=</span> <span class="dv">1</span></span>
<span id="cb15-15"><a href="#cb15-15" aria-hidden="true" tabindex="-1"></a>                 , _employeeName <span class="ot">=</span> <span class="st">&quot;bob&quot;</span></span>
<span id="cb15-16"><a href="#cb15-16" aria-hidden="true" tabindex="-1"></a>                 , _employeePets <span class="ot">=</span></span>
<span id="cb15-17"><a href="#cb15-17" aria-hidden="true" tabindex="-1"></a>                       [ <span class="dt">Pet</span> { _petName <span class="ot">=</span> <span class="st">&quot;Rocky&quot;</span></span>
<span id="cb15-18"><a href="#cb15-18" aria-hidden="true" tabindex="-1"></a>                             , _petType <span class="ot">=</span> <span class="st">&quot;cat&quot;</span></span>
<span id="cb15-19"><a href="#cb15-19" aria-hidden="true" tabindex="-1"></a>                             }</span>
<span id="cb15-20"><a href="#cb15-20" aria-hidden="true" tabindex="-1"></a>                       , <span class="dt">Pet</span> { _petName <span class="ot">=</span> <span class="st">&quot;Bullwinkle&quot;</span></span>
<span id="cb15-21"><a href="#cb15-21" aria-hidden="true" tabindex="-1"></a>                             , _petType <span class="ot">=</span> <span class="st">&quot;dog&quot;</span></span>
<span id="cb15-22"><a href="#cb15-22" aria-hidden="true" tabindex="-1"></a>                             }</span>
<span id="cb15-23"><a href="#cb15-23" aria-hidden="true" tabindex="-1"></a>                       ]</span>
<span id="cb15-24"><a href="#cb15-24" aria-hidden="true" tabindex="-1"></a>                 }</span>
<span id="cb15-25"><a href="#cb15-25" aria-hidden="true" tabindex="-1"></a>      , <span class="dt">Employee</span> { _employeeId   <span class="ot">=</span> <span class="dv">2</span></span>
<span id="cb15-26"><a href="#cb15-26" aria-hidden="true" tabindex="-1"></a>                 , _employeeName <span class="ot">=</span> <span class="st">&quot;sally&quot;</span></span>
<span id="cb15-27"><a href="#cb15-27" aria-hidden="true" tabindex="-1"></a>                 , _employeePets <span class="ot">=</span> [ <span class="dt">Pet</span> { _petName <span class="ot">=</span> <span class="st">&quot;Inigo&quot;</span></span>
<span id="cb15-28"><a href="#cb15-28" aria-hidden="true" tabindex="-1"></a>                                         , _petType <span class="ot">=</span> <span class="st">&quot;cat&quot;</span></span>
<span id="cb15-29"><a href="#cb15-29" aria-hidden="true" tabindex="-1"></a>                                         }</span>
<span id="cb15-30"><a href="#cb15-30" aria-hidden="true" tabindex="-1"></a>                                   ]</span>
<span id="cb15-31"><a href="#cb15-31" aria-hidden="true" tabindex="-1"></a>                 }</span>
<span id="cb15-32"><a href="#cb15-32" aria-hidden="true" tabindex="-1"></a>      ]</span>
<span id="cb15-33"><a href="#cb15-33" aria-hidden="true" tabindex="-1"></a>, _salaries <span class="ot">=</span> fromList [(<span class="dv">1</span>, <span class="dv">17</span>), (<span class="dv">2</span>, <span class="dv">15</span>)]</span>
<span id="cb15-34"><a href="#cb15-34" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p>I wrote it out in "long form"; the expressiveness of our system means
there are a few different ways to write the same thing; which probably
isn't a good thing, but you can find the way that you like to work and
standardize on that!</p>
<p>It turns out that if you want even <strong>more</strong> power you
can replace <code>MaybeT</code> with a "List transformer done right"
like <a
href="https://hackage.haskell.org/package/logict"><code>LogicT</code></a>
or <a
href="https://hackage.haskell.org/package/list-t"><code>list-t</code></a>.
This will allow you to actually <strong>expand</strong> the number of
branches within a zoom, not just filter them! It leads to a lot of
power! I'll leave it as an exercise for the reader to experiment with,
see if you can rewrite <code>%&gt;</code> to use one of these list
transformers instead!</p>
<p>Hopefully that helps to show how a few optics along with a few monads
can allow you to replicate the power of something like <code>jq</code>
and even add more capabilities, all by leveraging composable tools that
already exist and while maintaining the full power of Haskell!</p>
<p>There are truly endless types of additional combinators you could add
to make your code look how you want, but I'll leave that up to you. You
can even use <code>ReaderT</code> or <code>StateT</code> as a base monad
to make the whole stack into a transformer so you can add any other
Monadic behaviour you want to your DSL (e.g. <code>IO</code>).</p>
<h2 id="is-it-really-data-agnostic">Is it really data agnostic?</h2>
<p>Just to show that everything we've built so far works on any data
type you like (so long as you can write optics for it); we'll rewrite
our Haskell code to accept a JSON <code>Aeson.Value</code> object
instead!</p>
<p>You'll find it's a bit longer than the <code>jq</code> version, but
keep in mind that it's fully typesafe!</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">salaryBumpJSON ::</span> <span class="dt">MaybeT</span> (<span class="dt">State</span> <span class="dt">Value</span>) ()</span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a>salaryBumpJSON <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a>    ids <span class="ot">&lt;-</span> key <span class="st">&quot;staff&quot;</span> <span class="op">.</span> values <span class="op">%&gt;</span> <span class="kw">do</span></span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a>        isDog <span class="ot">&lt;-</span> key <span class="st">&quot;pets&quot;</span> <span class="op">.</span> values <span class="op">%&gt;</span> <span class="kw">do</span></span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a>                        pType <span class="ot">&lt;-</span> use (key <span class="st">&quot;type&quot;</span> <span class="op">.</span> _String)</span>
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a>                        <span class="fu">return</span> <span class="op">$</span> pType <span class="op">==</span> <span class="st">&quot;dog&quot;</span></span>
<span id="cb16-7"><a href="#cb16-7" aria-hidden="true" tabindex="-1"></a>        guard (<span class="fu">or</span> isDog)</span>
<span id="cb16-8"><a href="#cb16-8" aria-hidden="true" tabindex="-1"></a>        use (key <span class="st">&quot;id&quot;</span> <span class="op">.</span> _String)</span>
<span id="cb16-9"><a href="#cb16-9" aria-hidden="true" tabindex="-1"></a>    for_ ids <span class="op">$</span> \id&#39; <span class="ot">-&gt;</span></span>
<span id="cb16-10"><a href="#cb16-10" aria-hidden="true" tabindex="-1"></a>        key <span class="st">&quot;salaries&quot;</span> <span class="op">.</span> key id&#39; <span class="op">.</span> _Integer <span class="op">+=</span> <span class="dv">5</span></span></code></pre></div>
<p>As you can see it's pretty much the same! We just have to specify the
type of JSON we expect to find in each location (e.g.
<code>_String</code>, <code>_Integer</code>), but otherwise it's very
similar!</p>
<p>For the record I'm not suggesting that you go and replace all of your
CLI usages of <code>jq</code> with Haskell, but I hope that this
exploration can help future programmers avoid "re-inventing" the wheel
and give them a more mathematically structured approach when building
their traversal systems; or maybe they'll just build those systems in
Haskell instead 😉</p>
<p>I'm excited to see what sort of cool tricks, combinators, and
interactions with other monads you all find!</p>
<h2 id="bonus">Bonus</h2>
<p>Just to show that you can do "real" work with this abstraction here
are a few more examples using this technique with different data types.
These examples will still be a bit tongue in cheek, but hopefully show
that you really can accomplish actual tasks with this abstraction across
a wide range of data types.</p>
<hr />
<p>First up; here's a transformation over a kubernetes manifest
describing the pods available in a given namespace. You can see an
example roughly what the data looks like <a
href="https://gist.github.com/ChrisPenner/53e4b505ff0673b39c60e6c926b2715d">here</a>.</p>
<p>This transformation takes a map of docker image names to port numbers
and goes through the manifest and sets each container to use the correct
ports. It also tags each pod with all of the images from its containers,
and finally returns a map of container names to docker image types! It's
pretty cool how this abstraction lets us mutate data while also
returning information.</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="ot">{-# LANGUAGE OverloadedStrings #-}</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a><span class="kw">module</span> <span class="dt">K8s</span> <span class="kw">where</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="kw">import</span> <span class="dt">Data.Aeson</span> <span class="kw">hiding</span> ((.=))</span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Aeson.Lens</span></span>
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Lens</span></span>
<span id="cb17-7"><a href="#cb17-7" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Monad.State</span></span>
<span id="cb17-8"><a href="#cb17-8" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Data.Map</span> <span class="kw">as</span> <span class="dt">M</span></span>
<span id="cb17-9"><a href="#cb17-9" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Data.Text</span> <span class="kw">as</span> <span class="dt">T</span></span>
<span id="cb17-10"><a href="#cb17-10" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Foldable</span></span>
<span id="cb17-11"><a href="#cb17-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-12"><a href="#cb17-12" aria-hidden="true" tabindex="-1"></a><span class="co">-- Load in your k8s JSON here however you like</span></span>
<span id="cb17-13"><a href="#cb17-13" aria-hidden="true" tabindex="-1"></a><span class="ot">k8sJSON ::</span> <span class="dt">Value</span></span>
<span id="cb17-14"><a href="#cb17-14" aria-hidden="true" tabindex="-1"></a>k8sJSON <span class="ot">=</span> <span class="fu">undefined</span></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="ot">transformation ::</span> <span class="dt">M.Map</span> <span class="dt">T.Text</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">State</span> <span class="dt">Value</span> (<span class="dt">M.Map</span> <span class="dt">T.Text</span> <span class="dt">T.Text</span>)</span>
<span id="cb17-17"><a href="#cb17-17" aria-hidden="true" tabindex="-1"></a>transformation ports <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb17-18"><a href="#cb17-18" aria-hidden="true" tabindex="-1"></a>    zoom (key <span class="st">&quot;items&quot;</span> <span class="op">.</span> values) <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb17-19"><a href="#cb17-19" aria-hidden="true" tabindex="-1"></a>        containerImages <span class="ot">&lt;-</span> zoom (key <span class="st">&quot;spec&quot;</span> <span class="op">.</span> key <span class="st">&quot;containers&quot;</span> <span class="op">.</span> values) <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb17-20"><a href="#cb17-20" aria-hidden="true" tabindex="-1"></a>            containerName <span class="ot">&lt;-</span> use (key <span class="st">&quot;name&quot;</span> <span class="op">.</span> _String)</span>
<span id="cb17-21"><a href="#cb17-21" aria-hidden="true" tabindex="-1"></a>            imageName <span class="ot">&lt;-</span> use (key <span class="st">&quot;image&quot;</span> <span class="op">.</span> _String <span class="op">.</span> to (T.takeWhile (<span class="op">/=</span> <span class="ch">&#39;:&#39;</span>)))</span>
<span id="cb17-22"><a href="#cb17-22" aria-hidden="true" tabindex="-1"></a>            zoom (key <span class="st">&quot;ports&quot;</span> <span class="op">.</span> values) <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb17-23"><a href="#cb17-23" aria-hidden="true" tabindex="-1"></a>                <span class="kw">let</span> hostPort <span class="ot">=</span> M.findWithDefault <span class="dv">8080</span> imageName ports</span>
<span id="cb17-24"><a href="#cb17-24" aria-hidden="true" tabindex="-1"></a>                key <span class="st">&quot;hostPort&quot;</span> <span class="op">.</span> _Integral <span class="op">.=</span> hostPort</span>
<span id="cb17-25"><a href="#cb17-25" aria-hidden="true" tabindex="-1"></a>                key <span class="st">&quot;containerPort&quot;</span> <span class="op">.</span> _Integral <span class="op">.=</span> hostPort <span class="op">+</span> <span class="dv">1000</span></span>
<span id="cb17-26"><a href="#cb17-26" aria-hidden="true" tabindex="-1"></a>            <span class="fu">return</span> <span class="op">$</span> M.singleton containerName imageName</span>
<span id="cb17-27"><a href="#cb17-27" aria-hidden="true" tabindex="-1"></a>        zoom (key <span class="st">&quot;metadata&quot;</span> <span class="op">.</span> key <span class="st">&quot;labels&quot;</span>) <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb17-28"><a href="#cb17-28" aria-hidden="true" tabindex="-1"></a>          for_ containerImages <span class="op">$</span> \imageName <span class="ot">-&gt;</span></span>
<span id="cb17-29"><a href="#cb17-29" aria-hidden="true" tabindex="-1"></a>              _Object <span class="op">.</span> at imageName <span class="op">?=</span> <span class="st">&quot;true&quot;</span></span>
<span id="cb17-30"><a href="#cb17-30" aria-hidden="true" tabindex="-1"></a>        <span class="fu">return</span> containerImages</span>
<span id="cb17-31"><a href="#cb17-31" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-32"><a href="#cb17-32" aria-hidden="true" tabindex="-1"></a><span class="ot">imagePorts ::</span> <span class="dt">M.Map</span> <span class="dt">T.Text</span> <span class="dt">Int</span></span>
<span id="cb17-33"><a href="#cb17-33" aria-hidden="true" tabindex="-1"></a>imagePorts <span class="ot">=</span> M.fromList [ (<span class="st">&quot;redis&quot;</span>, <span class="dv">6379</span>)</span>
<span id="cb17-34"><a href="#cb17-34" aria-hidden="true" tabindex="-1"></a>                        , (<span class="st">&quot;my-app&quot;</span>, <span class="dv">80</span>)</span>
<span id="cb17-35"><a href="#cb17-35" aria-hidden="true" tabindex="-1"></a>                        , (<span class="st">&quot;postgres&quot;</span>, <span class="dv">5432</span>)</span>
<span id="cb17-36"><a href="#cb17-36" aria-hidden="true" tabindex="-1"></a>                        ]</span>
<span id="cb17-37"><a href="#cb17-37" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-38"><a href="#cb17-38" aria-hidden="true" tabindex="-1"></a><span class="ot">result ::</span> (<span class="dt">M.Map</span> <span class="dt">T.Text</span> <span class="dt">T.Text</span>, <span class="dt">Value</span>)</span>
<span id="cb17-39"><a href="#cb17-39" aria-hidden="true" tabindex="-1"></a>result <span class="ot">=</span> runState (transformation imagePorts) k8sJSON</span></code></pre></div>
<hr />
<p>Next up; let's work with some HTML! The following transformation uses
<code>taggy-lens</code> to interact with HTML (or any XML you happen to
have lying around.)</p>
<p>This transformation will find all direct parents of
<code>&lt;img&gt;</code> tags and will set the <code>alt</code> tags on
those images to be all the text inside the parent node.</p>
<p>After that, it will find all <code>&lt;a&gt;</code> tags and wrap
them in a <code>&lt;strong&gt;</code> tag while also returning a list of
all <code>href</code> attributes so we can see all the links we have in
the document!</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="ot">{-# LANGUAGE OverloadedStrings #-}</span></span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a><span class="kw">module</span> <span class="dt">HTML</span> <span class="kw">where</span></span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Data.Text.Lazy</span> <span class="kw">as</span> <span class="dt">TL</span></span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Data.Text</span> <span class="kw">as</span> <span class="dt">T</span></span>
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Data.Text.Lazy.IO</span> <span class="kw">as</span> <span class="dt">TL</span></span>
<span id="cb18-7"><a href="#cb18-7" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Monad.State</span></span>
<span id="cb18-8"><a href="#cb18-8" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Text.Taggy.Lens</span></span>
<span id="cb18-9"><a href="#cb18-9" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Lens</span> <span class="kw">hiding</span> (elements)</span>
<span id="cb18-10"><a href="#cb18-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-11"><a href="#cb18-11" aria-hidden="true" tabindex="-1"></a><span class="ot">transformation ::</span> <span class="dt">State</span> <span class="dt">TL.Text</span> [<span class="dt">T.Text</span>]</span>
<span id="cb18-12"><a href="#cb18-12" aria-hidden="true" tabindex="-1"></a>transformation <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb18-13"><a href="#cb18-13" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- Select all tags which have an &quot;img&quot; as a direct child</span></span>
<span id="cb18-14"><a href="#cb18-14" aria-hidden="true" tabindex="-1"></a>    zoom (html <span class="op">.</span> elements <span class="op">.</span> deep (filteredBy (elements <span class="op">.</span> named (only <span class="st">&quot;img&quot;</span>)))) <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb18-15"><a href="#cb18-15" aria-hidden="true" tabindex="-1"></a>        <span class="co">-- Get the current node&#39;s text contents</span></span>
<span id="cb18-16"><a href="#cb18-16" aria-hidden="true" tabindex="-1"></a>        altText <span class="ot">&lt;-</span> use contents</span>
<span id="cb18-17"><a href="#cb18-17" aria-hidden="true" tabindex="-1"></a>        <span class="co">-- Set the text contents as the &quot;alt&quot; tag for all img children</span></span>
<span id="cb18-18"><a href="#cb18-18" aria-hidden="true" tabindex="-1"></a>        elements <span class="op">.</span> named (only <span class="st">&quot;img&quot;</span>) <span class="op">.</span> attr <span class="st">&quot;alt&quot;</span> <span class="op">?=</span> altText</span>
<span id="cb18-19"><a href="#cb18-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-20"><a href="#cb18-20" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- Transform all &quot;a&quot; tags recursively</span></span>
<span id="cb18-21"><a href="#cb18-21" aria-hidden="true" tabindex="-1"></a>    (html <span class="op">.</span> elements <span class="op">.</span> transformM <span class="op">.</span> named (only <span class="st">&quot;a&quot;</span>)) </span>
<span id="cb18-22"><a href="#cb18-22" aria-hidden="true" tabindex="-1"></a>      <span class="co">-- Wrap them in a &lt;strong&gt; tag while also returning their href value</span></span>
<span id="cb18-23"><a href="#cb18-23" aria-hidden="true" tabindex="-1"></a>      <span class="op">%%=</span> \tag <span class="ot">-&gt;</span> (tag <span class="op">^..</span> attr <span class="st">&quot;href&quot;</span> <span class="op">.</span> _Just, <span class="dt">Element</span> <span class="st">&quot;strong&quot;</span> <span class="fu">mempty</span> [<span class="dt">NodeElement</span> tag])</span></code></pre></div>
<hr />
<p>Lastly let's see a CSV example! I'll be using my <a
href="https://hackage.haskell.org/package/lens-csv-0.1.1.0/docs/Data-Csv-Lens.html"><code>lens-csv</code></a>
library for the optics.</p>
<p>This simple example iterates through all the rows in a csv and uses
an overly simplistic formula to recompute their ages based on their
birth year.</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="ot">{-# LANGUAGE OverloadedStrings #-}</span></span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE TypeApplications #-}</span></span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE LambdaCase #-}</span></span>
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a><span class="kw">module</span> <span class="dt">CSV</span> <span class="kw">where</span></span>
<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-6"><a href="#cb19-6" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Lens</span></span>
<span id="cb19-7"><a href="#cb19-7" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Csv.Lens</span></span>
<span id="cb19-8"><a href="#cb19-8" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Data.ByteString.Lazy</span> <span class="kw">as</span> <span class="dt">BL</span></span>
<span id="cb19-9"><a href="#cb19-9" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Monad.State</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="ot">recomputeAges ::</span> <span class="dt">State</span> <span class="dt">BL.ByteString</span> ()</span>
<span id="cb19-12"><a href="#cb19-12" aria-hidden="true" tabindex="-1"></a>recomputeAges <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb19-13"><a href="#cb19-13" aria-hidden="true" tabindex="-1"></a>    zoom (namedCsv <span class="op">.</span> rows) <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb19-14"><a href="#cb19-14" aria-hidden="true" tabindex="-1"></a>        preuse (column <span class="op">@</span><span class="dt">Int</span> <span class="st">&quot;birthYear&quot;</span>) <span class="op">&gt;&gt;=</span> \<span class="kw">case</span></span>
<span id="cb19-15"><a href="#cb19-15" aria-hidden="true" tabindex="-1"></a>            <span class="dt">Nothing</span> <span class="ot">-&gt;</span> <span class="fu">return</span> ()</span>
<span id="cb19-16"><a href="#cb19-16" aria-hidden="true" tabindex="-1"></a>            <span class="dt">Just</span> birthYear <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb19-17"><a href="#cb19-17" aria-hidden="true" tabindex="-1"></a>                column <span class="op">@</span><span class="dt">Int</span> <span class="st">&quot;age&quot;</span> <span class="op">.=</span> <span class="dv">2020</span> <span class="op">-</span> birthYear</span></code></pre></div>
<p>Hopefully these last few examples help convince you that this really
is an adaptable solution even though they're still a bit silly.</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Intro to Kaleidoscopes: Optics for aggregating data through Applicatives</title>
      <link href="https://chrispenner.ca/posts/kaleidoscopes"/>
      <id>https://chrispenner.ca/posts/kaleidoscopes</id>
      <updated>2020-02-02T00:00:00Z</updated>
      <summary>An introduction to kaleidoscopes</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/kaleidoscope.jpg" alt="Intro to Kaleidoscopes: Optics for aggregating data through Applicatives">
              <p>This is a blog post about optics, if you're at all interested in
optics I suggest you go check out my book: <a
href="https://leanpub.com/optics-by-example">Optics By Example</a>.
Although this post covers a more advanced topic the book covers
everything you need to go from a beginner to master in all things
optics! Check it out and tell your friends, now onwards to the post
you're here for.</p>
<p>In this article we're going to dig into a brand new type of optic,
the Kaleidoscope! The theory of which is described in <a
href="https://cs.ttu.ee/events/nwpt2019/abstracts/paper14.pdf">this
abstract</a> by Mario Román, Bryce Clarke, Derek Elkins, Jeremy Gibbons,
Bartosz Milewski, Fosco Loregian, and Emily Pillmore.</p>
<p>If you haven't read the <a
href="https://chrispenner.ca/posts/algebraic">previous blog post</a> in
this series it's not required, but might help to build a stronger
understanding.</p>
<h2 id="what-is-a-kaleidoscope">What is a Kaleidoscope?</h2>
<p>Like most optics, the behaviour of a kaleidoscope is mostly dictated
by the type of profunctor you're passing through it; but from a bird's
eye view I'd say that kaleidoscopes allow you to perform aggregations,
comparisons, and manipulations over different <strong>groupings</strong>
of focuses. They can allow you to calculate summaries of each column of
a table, or calculate aggregations over each respective key in a list of
JSON objects! They perform this grouping using Applicative instances and
can end up with interesting behaviour depending on the type of
Applicative you're working with.</p>
<p>I have hopes that as kaleidoscopes are added to more optics libraries
and the kinks get worked out that we'll end up with an expressive optics
language which let us express complex table queries and mutations like
SQL queries do!</p>
<h2 id="a-new-profunctor-class">A new profunctor class</h2>
<p>For this post we'll look at kaleidoscopes from a profunctor optics
perspective, meaning we'll need a profunctor class which encompasses the
behaviour of the optic.</p>
<p>Since the last article was released I had a chance to chat with
Mario, the author of the abstract, on twitter which has been very
helpful! He explained that the Kaleidoscope characterization in the
abstract:</p>
<ul>
<li>Kaleidoscope: <code>π n∈N (A^n → B) → (S^n → T)</code></li>
</ul>
<p>Is represented by the following Profunctor class:</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">MStrong</span> p <span class="ot">=&gt;</span> <span class="dt">Reflector</span> p <span class="kw">where</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="ot">  reflected ::</span> <span class="dt">Applicative</span> f <span class="ot">=&gt;</span> p a b <span class="ot">-&gt;</span> p (f a) (f b)</span></code></pre></div>
<p>Reflector has a superclass of the <code>MStrong</code> profunctor
noted in the corrections at the bottom of the previous post. That every
Reflector is MStrong is trivially witnessed by
<code>msecond' = reflected</code> since
<code>Monoid m =&gt; (m, a)</code> is an Applicative (namely the
<strong>Writer</strong> Applicative).</p>
<p>With this class defined we can say that a Kaleidoscope is any optic
which depends on <code>Reflector</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="kw">type</span> <span class="dt">Kaleidoscope</span> s t a b <span class="ot">=</span> <span class="kw">forall</span> p<span class="op">.</span> <span class="dt">Reflector</span> p <span class="ot">=&gt;</span> p a b <span class="ot">-&gt;</span> p s t</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">Kaleidoscope&#39;</span> s a <span class="ot">=</span> <span class="dt">Kaleidoscope</span> s s a a</span></code></pre></div>
<p>This provides an optic which focuses the contents of any Applicative
structure!</p>
<p>Here's what we get when we write <code>reflected</code> with its new
signature:</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">reflected ::</span> <span class="dt">Applicative</span> f <span class="ot">=&gt;</span> <span class="dt">Kaleidoscope</span> (f a) (f b) a b</span></code></pre></div>
<p>At first <code>reflected</code> seems almost identical to the
<code>traverse'</code> combinator from the <a
href="https://hackage.haskell.org/package/profunctors-5.5.1/docs/Data-Profunctor-Traversing.html#v:traverse-39-"><code>Traversing</code></a>
profunctor class:</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">traverse&#39; ::</span> (<span class="dt">Traversing</span> p, <span class="dt">Traversable</span> f) <span class="ot">=&gt;</span> <span class="dt">Optic</span> p (f a) (f b) a b</span></code></pre></div>
<p>But of course <code>traverse'</code> works only on Traversables
whereas our new optic works only on Applicatives. Although these have
significant overlap, the <strong>behaviour</strong> induced by the use
of applicative structure is distinct from the behaviour of
traversables.</p>
<p>Let's implement our new <code>Reflector</code> class for a few common
profunctors so we can actually try it out!</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="co">-- (-&gt;) Allows us to set or update values through a reflector</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Reflector</span> (<span class="ot">-&gt;</span>) <span class="kw">where</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>  reflected <span class="ot">=</span> <span class="fu">fmap</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="co">-- Costar allows us to run aggregations over collections like we did in the previous post</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Traversable</span> f <span class="ot">=&gt;</span> <span class="dt">Reflector</span> (<span class="dt">Costar</span> f) <span class="kw">where</span></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>  reflected (<span class="dt">Costar</span> f) <span class="ot">=</span> <span class="dt">Costar</span> (<span class="fu">fmap</span> f <span class="op">.</span> <span class="fu">sequenceA</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="co">-- Tagged allows us to &quot;review&quot; through a Reflector</span></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Reflector</span> <span class="dt">Tagged</span> <span class="kw">where</span></span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a>  reflected (<span class="dt">Tagged</span> b) <span class="ot">=</span> <span class="dt">Tagged</span> (<span class="fu">pure</span> b)</span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a><span class="co">-- Star allows us to calculate several &#39;projections&#39; of focuses </span></span>
<span id="cb5-14"><a href="#cb5-14" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Distributive</span> f <span class="ot">=&gt;</span> <span class="dt">Reflector</span> (<span class="dt">Star</span> f) <span class="kw">where</span></span>
<span id="cb5-15"><a href="#cb5-15" aria-hidden="true" tabindex="-1"></a>  reflected (<span class="dt">Star</span> f) <span class="ot">=</span> <span class="dt">Star</span> (collect f)</span></code></pre></div>
<p>These are the usual suspects, in optics they correspond to the
ability to run the following actions:</p>
<ul>
<li><code>(-&gt;)</code>: <code>set</code>/<code>modify</code></li>
<li><code>Costar</code>: <code>(?.)</code>/<code>(&gt;-)</code> (from
the last post)</li>
<li><code>Tagged</code>: review</li>
<li><code>Star</code>: traverseOf</li>
</ul>
<p>Unfortunately we can't implement an instance of
<code>Reflector</code> for <code>Forget</code>, so we won't be able to
<code>view</code> or <code>fold</code> over Kaleidoscopes. C'est la
vie!</p>
<p>The class and optic are all set up! Let's see what they can do.</p>
<h2 id="grouping-with-kaleidoscopes">Grouping with kaleidoscopes</h2>
<p>In the previous post we managed to fill out most of the examples from
the case study using Algebraic Lenses, but we got stuck when it came to
<strong>aggregating</strong> over the individual measurements of the
flowers in our data-set. We wanted to somehow aggregate over constituent
pieces of our data-set all at once, for instance if we had the following
measurements as a silly example:</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="dt">Measurements</span> [<span class="dv">1</span>  , <span class="dv">2</span>  , <span class="dv">3</span>  , <span class="dv">4</span>  ]</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Measurements</span> [<span class="dv">10</span> , <span class="dv">20</span> , <span class="dv">30</span> , <span class="dv">40</span> ]</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Measurements</span> [<span class="dv">100</span>, <span class="dv">200</span>, <span class="dv">300</span>, <span class="dv">400</span>]</span></code></pre></div>
<p>We want to average them across each <strong>column</strong>, so we
want to end up with:</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="dt">Measurements</span> </span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>  [ mean [<span class="dv">1</span>, <span class="dv">10</span>, <span class="dv">100</span>]</span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>  , mean [<span class="dv">2</span>, <span class="dv">20</span>, <span class="dv">200</span>]</span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>  , mean [<span class="dv">3</span>, <span class="dv">30</span>, <span class="dv">300</span>]</span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>  , mean [<span class="dv">4</span>, <span class="dv">40</span>, <span class="dv">400</span>]</span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>  ]</span></code></pre></div>
<p>However our Algebraic lenses didn't give us any way to talk about
<strong>grouping</strong> or <strong>convolution</strong> of the
elements in the container, but kaleidoscopes are going to help us get
there!</p>
<p>Let's try just running our optic in a few different ways that
type-check and see what happens.</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="co">-- When updating/setting it simply focuses each &#39;element&#39; of the applicative.</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- It&#39;s indistinguishable from `traversed` in this case</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> [<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>] <span class="op">&amp;</span> reflected <span class="op">%~</span> (<span class="op">*</span><span class="dv">10</span>)</span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>[<span class="dv">10</span>,<span class="dv">20</span>,<span class="dv">30</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="co">-- We can compose it to nest deeper into multiple stacked applicatives of course!</span></span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> [[<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>], [<span class="dv">4</span>, <span class="dv">5</span>, <span class="dv">6</span>]] <span class="op">&amp;</span> reflected <span class="op">.</span> reflected <span class="op">%~</span> (<span class="op">*</span><span class="dv">10</span>)</span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a>[[<span class="dv">10</span>,<span class="dv">20</span>,<span class="dv">30</span>],[<span class="dv">40</span>,<span class="dv">50</span>,<span class="dv">60</span>]]</span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> [[<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>], [<span class="dv">4</span>, <span class="dv">5</span>, <span class="dv">6</span>]] <span class="op">&amp;</span> reflected <span class="op">.</span> reflected <span class="op">%~</span> (<span class="op">*</span><span class="dv">10</span>)</span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a>[[<span class="dv">10</span>,<span class="dv">20</span>,<span class="dv">30</span>],[<span class="dv">40</span>,<span class="dv">50</span>,<span class="dv">60</span>]]</span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-12"><a href="#cb8-12" aria-hidden="true" tabindex="-1"></a><span class="co">-- Since `Tagged` is a `Reflector` we can &#39;review&#39; through &#39;reflected&#39; </span></span>
<span id="cb8-13"><a href="#cb8-13" aria-hidden="true" tabindex="-1"></a><span class="co">-- This will embed a value into any Applicative as though we&#39;d used &#39;pure&#39;</span></span>
<span id="cb8-14"><a href="#cb8-14" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> review reflected <span class="dv">1</span><span class="ot"> ::</span> <span class="dt">Either</span> () <span class="dt">Int</span></span>
<span id="cb8-15"><a href="#cb8-15" aria-hidden="true" tabindex="-1"></a><span class="dt">Right</span> <span class="dv">1</span></span>
<span id="cb8-16"><a href="#cb8-16" aria-hidden="true" tabindex="-1"></a><span class="co">-- We can compose with prisms</span></span>
<span id="cb8-17"><a href="#cb8-17" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> review (_Just <span class="op">.</span> reflected) <span class="dv">1</span><span class="ot"> ::</span> <span class="dt">Maybe</span> [<span class="dt">Int</span>]</span>
<span id="cb8-18"><a href="#cb8-18" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> [<span class="dv">1</span>]</span>
<span id="cb8-19"><a href="#cb8-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-20"><a href="#cb8-20" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> review (reflected <span class="op">.</span> reflected) <span class="dv">1</span><span class="ot"> ::</span> <span class="dt">Maybe</span> [<span class="dt">Int</span>]</span>
<span id="cb8-21"><a href="#cb8-21" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> [<span class="dv">1</span>]</span>
<span id="cb8-22"><a href="#cb8-22" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-23"><a href="#cb8-23" aria-hidden="true" tabindex="-1"></a><span class="co">-- Unfortunately kaleidoscopes don&#39;t allow viewing or folding :&#39;(</span></span>
<span id="cb8-24"><a href="#cb8-24" aria-hidden="true" tabindex="-1"></a><span class="co">-- They can still be composed with lenses and traversals, but the resulting optic</span></span>
<span id="cb8-25"><a href="#cb8-25" aria-hidden="true" tabindex="-1"></a><span class="co">-- can only be used as a setter, or as a traversal with Distributive Functors.</span></span>
<span id="cb8-26"><a href="#cb8-26" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> [[<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>], [<span class="dv">4</span>, <span class="dv">5</span>, <span class="dv">6</span>]] <span class="op">^..</span> reflected <span class="op">.</span> reflected</span>
<span id="cb8-27"><a href="#cb8-27" aria-hidden="true" tabindex="-1"></a><span class="fu">error</span><span class="op">:</span></span>
<span id="cb8-28"><a href="#cb8-28" aria-hidden="true" tabindex="-1"></a>    • <span class="dt">No</span> <span class="kw">instance</span> for (<span class="dt">Reflector</span></span>
<span id="cb8-29"><a href="#cb8-29" aria-hidden="true" tabindex="-1"></a>                         (<span class="dt">Data.Profunctor.Types.Forget</span> [<span class="dt">Integer</span>]))</span>
<span id="cb8-30"><a href="#cb8-30" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-31"><a href="#cb8-31" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> [[<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>], [<span class="dv">4</span>, <span class="dv">5</span>, <span class="dv">6</span>]] <span class="op">&amp;</span> traversed <span class="op">.</span> reflected <span class="op">%~</span> (<span class="op">*</span><span class="dv">10</span>)</span>
<span id="cb8-32"><a href="#cb8-32" aria-hidden="true" tabindex="-1"></a>[[<span class="dv">10</span>,<span class="dv">20</span>,<span class="dv">30</span>],[<span class="dv">40</span>,<span class="dv">50</span>,<span class="dv">60</span>]]</span></code></pre></div>
<p>Okay, so that covers <code>review</code>, <code>set</code> and
<code>over</code>, what about <code>&gt;-</code>? This is where things
start to get fun!</p>
<p>Remember from the last post that <code>&gt;-</code> has this
type:</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">(&gt;-) ::</span> <span class="dt">Optic</span> (<span class="dt">Costar</span> f) s t a b <span class="ot">-&gt;</span> (f a <span class="ot">-&gt;</span> b) <span class="ot">-&gt;</span> f s <span class="ot">-&gt;</span> t</span></code></pre></div>
<p>So this means it aggregates some <strong>outer</strong> container
<code>f</code> over the focuses of the provided optic. The hardest part
here is keeping track of which container is the collection handled by
<code>&gt;-</code> and which is the <code>Applicative</code> handled by
<code>reflected</code>. To help keep things separate I'll introduce the
simple <code>Pair</code> type, defined like so:</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">data</span> <span class="dt">Pair</span> a <span class="ot">=</span> <span class="dt">Pair</span> a a</span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>, <span class="dt">Ord</span>, <span class="dt">Functor</span>, <span class="dt">Foldable</span>, <span class="dt">Traversable</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="kw">instance</span> <span class="dt">Applicative</span> <span class="dt">Pair</span> <span class="kw">where</span></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>  <span class="fu">pure</span> a <span class="ot">=</span> <span class="dt">Pair</span> a a</span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Pair</span> f f&#39; <span class="op">&lt;*&gt;</span> <span class="dt">Pair</span> a a&#39; <span class="ot">=</span> <span class="dt">Pair</span> (f a) (f&#39; a&#39;)</span></code></pre></div>
<p>Now let's run a few simple aggregations to <em>start</em> to
understand <code>reflected</code>.</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="co">-- Here &#39;reflected&#39; uses the List&#39;s Applicative instance </span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- to group elements from each of the values in the outer Pair.</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a><span class="co">-- By using `show` as our `(f a -&gt; b)` aggregation we can see </span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a><span class="co">-- each grouping was passed to our aggregation function.</span></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="dt">Pair</span> [<span class="dv">1</span>, <span class="dv">2</span>] [<span class="dv">3</span>, <span class="dv">4</span>] <span class="op">&amp;</span> reflected <span class="op">&gt;-</span> <span class="fu">show</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>[<span class="st">&quot;Pair 1 3&quot;</span>,<span class="st">&quot;Pair 1 4&quot;</span>,<span class="st">&quot;Pair 2 3&quot;</span>,<span class="st">&quot;Pair 2 4&quot;</span>]</span></code></pre></div>
<p>A few things to notice here. First, the structure of outer collection
gets shifted to the inside where it was aggregated, the
<code>Pair</code> was flattened by our aggregation, leaving only the
list's structure. Secondly we can see that we have a value representing
each possible pairing of the two lists in our pair.
<code>reflected</code> used the Applicative instance of the list to
determine the groupings, and the Applicative for lists finds all
possible pairings. Basically it did this:</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">&gt;&gt;&gt;</span> liftA2 <span class="dt">Pair</span> [<span class="dv">1</span>, <span class="dv">2</span>] [<span class="dv">3</span>, <span class="dv">4</span>]</span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>[<span class="dt">Pair</span> <span class="dv">1</span> <span class="dv">3</span>, <span class="dt">Pair</span> <span class="dv">1</span> <span class="dv">4</span>, <span class="dt">Pair</span> <span class="dv">2</span> <span class="dv">3</span>, <span class="dt">Pair</span> <span class="dv">2</span> <span class="dv">4</span>]</span></code></pre></div>
<p>What happens if we run the same thing with the containers
flip-flopped? Then <code>reflected</code> will group elements using the
<code>Pair</code> applicative which matches the elements of each pair
zip-wise.</p>
<p>Note that the reason we can flip-flop them like this is that Lists
and Pairs each have <code>Applicative</code> AND
<code>Traversable</code> instances. This time we're using the List's
Traversable instance and the Pair's Applicative.</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="dt">Pair</span> <span class="dv">1</span> <span class="dv">2</span>, <span class="dt">Pair</span> <span class="dv">3</span> <span class="dv">4</span>] <span class="op">&amp;</span> reflected <span class="op">&gt;-</span> <span class="fu">show</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Pair</span> <span class="st">&quot;[1,3]&quot;</span> <span class="st">&quot;[2,4]&quot;</span></span></code></pre></div>
<p>This time we can see we've grouped the elements into lists by their
positions in the pair! Again, the outer structure was flattened by the
aggregation after being grouped using the inner applicative
instance.</p>
<p>Let's try one more; we'll use a Map for the outer container.</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="op">&gt;&gt;&gt;</span> M.fromList [(<span class="ch">&#39;a&#39;</span>, <span class="dt">Pair</span> <span class="dv">1</span> <span class="dv">2</span>), (<span class="ch">&#39;b&#39;</span>, <span class="dt">Pair</span> <span class="dv">3</span> <span class="dv">4</span>)] <span class="op">&amp;</span> reflected <span class="op">&gt;-</span> <span class="fu">show</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Pair</span> <span class="st">&quot;fromList [(&#39;a&#39;,1),(&#39;b&#39;,3)]&quot;</span> <span class="st">&quot;fromList [(&#39;a&#39;,2),(&#39;b&#39;,4)]&quot;</span></span></code></pre></div>
<p>This creates two separate maps which have been grouped into Maps
using the Applicative instance of the inner Pair! In this case it
grouped elements zipwise across maps! Take a moment to see how this
behavior is perhaps not very intuitive, but is nonetheless a very useful
way of grouping data.</p>
<h2 id="back-to-measurements">Back to measurements</h2>
<p>So, back to our flower problem from the previous post, now that we
very <em>roughly</em> understand how <code>reflected</code> groups
elements for aggregation we'll see how we can use it to group respective
measurements of our flowers.</p>
<p>Here's our simplified representation of our problem, we've got a
collection of flower measurements. Each element of each list represents
a unique measurement, for example maybe the first measurement in each
list (the first column) represents leaf length, and the last measurement
in each (the last column) represents stem length. Here's our silly
simplified data set:</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">allMeasurements ::</span> [[<span class="dt">Float</span>]]</span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>allMeasurements <span class="ot">=</span></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a>      [ [<span class="dv">1</span>  , <span class="dv">2</span>  , <span class="dv">3</span>  , <span class="dv">4</span>  ]</span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a>      , [<span class="dv">10</span> , <span class="dv">20</span> , <span class="dv">30</span> , <span class="dv">40</span> ]</span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a>      , [<span class="dv">100</span>, <span class="dv">200</span>, <span class="dv">300</span>, <span class="dv">400</span>]</span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a>      ]</span></code></pre></div>
<p>Our task is to get the average of the <strong>each individual
measurement</strong>, i.e. the average of each <strong>column</strong>
rather than each <strong>row</strong>, averaging different measurement
types together doesn't make sense. We've seen how <code>reflected</code>
can help us group data across an outer container, but if we try to use
<code>reflected</code> here it will find ALL POSSIBLE GROUPINGS! Let's
see how this gong-show unfolds:</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="op">&gt;&gt;&gt;</span> allMeasurements <span class="op">&amp;</span> reflected <span class="op">&gt;-</span> <span class="fu">show</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a>[<span class="st">&quot;[1,10,100]&quot;</span>,<span class="st">&quot;[1,10,200]&quot;</span>,<span class="st">&quot;[1,10,300]&quot;</span>,<span class="st">&quot;[1,10,400]&quot;</span>,<span class="st">&quot;[1,20,100]&quot;</span>,<span class="st">&quot;[1,20,200]&quot;</span></span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a>,<span class="st">&quot;[1,20,300]&quot;</span>,<span class="st">&quot;[1,20,400]&quot;</span>,<span class="st">&quot;[1,30,100]&quot;</span>,<span class="st">&quot;[1,30,200]&quot;</span>,<span class="st">&quot;[1,30,300]&quot;</span>,<span class="st">&quot;[1,30,400]&quot;</span></span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a>, <span class="op">...</span> ad<span class="op">-</span>nauseum</span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a>]</span></code></pre></div>
<p>Hrmmm, this makes sense when we think about it; we're grouping
elements using the list applicative which performs a cartesian product
yielding all possible combinations! Instead we really want to group
elements by their position within the list, we'll need a different
<code>Applicative</code> instance! Since we want the applicative to
<em>zip</em> each matching element together I suspect a
<code>ZipList</code> might be just what the doctor ordered!</p>
<p>If you're unfamiliar with <code>ZipList</code> it's a newtype around
lists provided in <code>Control.Applicative</code>. Take a look at how
its Applicative instance differs from plain old lists:</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">-- List Applicative is cartesian product; e.g. all combinations.</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> liftA2 (,) [<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>] [<span class="dv">4</span>, <span class="dv">5</span>, <span class="dv">6</span>]</span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a>[(<span class="dv">1</span>,<span class="dv">4</span>),(<span class="dv">1</span>,<span class="dv">5</span>),(<span class="dv">1</span>,<span class="dv">6</span>),(<span class="dv">2</span>,<span class="dv">4</span>),(<span class="dv">2</span>,<span class="dv">5</span>),(<span class="dv">2</span>,<span class="dv">6</span>),(<span class="dv">3</span>,<span class="dv">4</span>),(<span class="dv">3</span>,<span class="dv">5</span>),(<span class="dv">3</span>,<span class="dv">6</span>)]</span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a><span class="co">-- ZipList Applicative does zipwise pairing instead!</span></span>
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> liftA2 (,) (<span class="dt">ZipList</span> [<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>]) (<span class="dt">ZipList</span> [<span class="dv">4</span>, <span class="dv">5</span>, <span class="dv">6</span>])</span>
<span id="cb17-7"><a href="#cb17-7" aria-hidden="true" tabindex="-1"></a><span class="dt">ZipList</span> [(<span class="dv">1</span>,<span class="dv">4</span>),(<span class="dv">2</span>,<span class="dv">5</span>),(<span class="dv">3</span>,<span class="dv">6</span>)]</span></code></pre></div>
<p>That looks more like what we want, the results end up grouped
according to their position in the list.</p>
<p>Let's try this instead:</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="ot">zippyMeasurements ::</span> [<span class="dt">ZipList</span> <span class="dt">Float</span>]</span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a>zippyMeasurements <span class="ot">=</span></span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a>      [ <span class="dt">ZipList</span> [<span class="dv">1</span>  , <span class="dv">2</span>  , <span class="dv">3</span>  , <span class="dv">4</span>  ]</span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a>      , <span class="dt">ZipList</span> [<span class="dv">10</span> , <span class="dv">20</span> , <span class="dv">30</span> , <span class="dv">40</span> ]</span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a>      , <span class="dt">ZipList</span> [<span class="dv">100</span>, <span class="dv">200</span>, <span class="dv">300</span>, <span class="dv">400</span>]</span>
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a>      ]</span>
<span id="cb18-7"><a href="#cb18-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-8"><a href="#cb18-8" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> zippyMeasurements <span class="op">&amp;</span> reflected <span class="op">&gt;-</span> <span class="fu">show</span></span>
<span id="cb18-9"><a href="#cb18-9" aria-hidden="true" tabindex="-1"></a><span class="dt">ZipList</span> [ <span class="st">&quot;[1,10,100]&quot;</span></span>
<span id="cb18-10"><a href="#cb18-10" aria-hidden="true" tabindex="-1"></a>        , <span class="st">&quot;[2,20,200]&quot;</span></span>
<span id="cb18-11"><a href="#cb18-11" aria-hidden="true" tabindex="-1"></a>        , <span class="st">&quot;[3,30,300]&quot;</span></span>
<span id="cb18-12"><a href="#cb18-12" aria-hidden="true" tabindex="-1"></a>        , <span class="st">&quot;[4,40,400]&quot;</span></span>
<span id="cb18-13"><a href="#cb18-13" aria-hidden="true" tabindex="-1"></a>        ]</span></code></pre></div>
<p>Much better! It's common to want this alternate Applicative behaviour
for lists, so I'll define a new kaleidoscope which uses this zippy
behaviour for lists:</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="co">-- Use an iso to wrap/unwrap the list in ZipList before reflecting</span></span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a><span class="ot">zipWise ::</span> <span class="dt">Kaleidoscope</span> [a] [b] a b</span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a>zipWise <span class="ot">=</span> iso <span class="dt">ZipList</span> getZipList <span class="op">.</span> reflected</span></code></pre></div>
<p>Great! Now we can use <code>zipWise</code> to do our grouping, and
we'll run <code>mean</code> as our aggregation rather than
<code>show</code>'ing</p>
<div class="sourceCode" id="cb20"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- Here&#39;s an averaging function</span></span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a><span class="ot">mean ::</span> <span class="dt">Foldable</span> f <span class="ot">=&gt;</span> f <span class="dt">Float</span> <span class="ot">-&gt;</span> <span class="dt">Float</span></span>
<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a>mean xs <span class="ot">=</span> <span class="fu">sum</span> xs <span class="op">/</span> <span class="fu">fromIntegral</span> (<span class="fu">length</span> xs)</span>
<span id="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-5"><a href="#cb20-5" aria-hidden="true" tabindex="-1"></a><span class="co">-- `zipWise` will group measurements by type (e.g. get lists representing columns)</span></span>
<span id="cb20-6"><a href="#cb20-6" aria-hidden="true" tabindex="-1"></a><span class="co">-- then we can take the average of each column, which will be collected back into a single row.</span></span>
<span id="cb20-7"><a href="#cb20-7" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> allMeasurements <span class="op">&amp;</span> zipWise <span class="op">&gt;-</span> mean</span>
<span id="cb20-8"><a href="#cb20-8" aria-hidden="true" tabindex="-1"></a>[<span class="fl">37.0</span>, <span class="fl">74.0</span>, <span class="fl">111.0</span>, <span class="fl">148.0</span>]</span></code></pre></div>
<p>Cool! We use any aggregation function in place of <code>mean</code>,
so we could get the <code>sum</code>, <code>median</code>,
<code>maximum</code>, or <code>minimum</code> of each column, whatever
you like!</p>
<h2 id="finishing-the-example">Finishing the example</h2>
<p>Let's finish up the example from the previous post; if you haven't
read that recently this part might not make much sense.</p>
<p>Our new <code>zipWise</code> kaleidoscope is almost what we need, but
we'll need another iso to let it accept the <code>Measurements</code>
wrapper our flowers use:</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">aggregate ::</span> <span class="dt">Kaleidoscope&#39;</span> <span class="dt">Measurements</span> <span class="dt">Float</span></span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a>aggregate <span class="ot">=</span> iso getMeasurements <span class="dt">Measurements</span> <span class="op">.</span> zipWise</span></code></pre></div>
<p>Kaleidoscopes compose nicely with the algebraic lenses we built in
the previous post, meaning we can use the <code>measurements</code>
algebraic lens we built and compose it with our new
<code>aggregate</code> kaleidoscope! Using all the same
<code>flowers</code> from the previous post:</p>
<div class="sourceCode" id="cb22"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> flowers <span class="op">&amp;</span> measurements <span class="op">.</span> aggregate <span class="op">&gt;-</span> mean</span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Flower</span> <span class="dt">Versicolor</span> (<span class="dt">Measurements</span> [<span class="fl">3.5</span>,<span class="fl">3.5</span>,<span class="fl">3.5</span>,<span class="fl">2.25</span>])</span></code></pre></div>
<p>This is doing a LOT for us; it takes a list of flowers, focuses their
measurements, averages them zipwise across their independent
measurements, then <em>classifies</em> the complete set of average
measurements as a species using euclidean difference over measurements
with the original data set! As it turns out, the 'average' flower is
closest to the <code>Versicolor</code> species (in my completely made up
data set)!</p>
<h2 id="other-nifty-tricks">Other nifty tricks</h2>
<p>There's an alternative version of our <code>Reflector</code> which
depends on <code>Apply</code> and <code>Traversable1</code> instead of
<code>Applicative</code> and <code>Traversable</code>! It doesn't allow
<code>review</code>, but opens up <code>reflected</code> to work on
anything implementing <code>Apply</code>; which is particularly handy
since that allows us to now <code>reflect</code> our way into Maps!</p>
<p>Here's the alternative version of our Reflector class:</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="kw">import</span> <span class="dt">Data.Profunctor</span></span>
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Profunctor.MStrong</span></span>
<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Functor.Apply</span></span>
<span id="cb23-4"><a href="#cb23-4" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Semigroup.Traversable</span></span>
<span id="cb23-5"><a href="#cb23-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb23-6"><a href="#cb23-6" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">MStrong</span> p <span class="ot">=&gt;</span> <span class="dt">Reflector</span> p <span class="kw">where</span></span>
<span id="cb23-7"><a href="#cb23-7" aria-hidden="true" tabindex="-1"></a><span class="ot">  reflected ::</span> <span class="dt">Apply</span> f <span class="ot">=&gt;</span> p a b <span class="ot">-&gt;</span> p (f a) (f b)</span>
<span id="cb23-8"><a href="#cb23-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb23-9"><a href="#cb23-9" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Traversable1</span> f <span class="ot">=&gt;</span> <span class="dt">Reflector</span> (<span class="dt">Costar</span> f) <span class="kw">where</span></span>
<span id="cb23-10"><a href="#cb23-10" aria-hidden="true" tabindex="-1"></a>  reflected (<span class="dt">Costar</span> f) <span class="ot">=</span> <span class="dt">Costar</span> (<span class="fu">fmap</span> f <span class="op">.</span> sequence1)</span></code></pre></div>
<p>This is only a peek at what's possible, but with this version we can
use <code>reflected</code> to group elements key-wise across all Maps in
a non-empty collection.</p>
<p>Let's say we manage several business and have a list of all their
profits and expenses. We can group and aggregate over all of their
expenses and profits respectively! Again, think of reflected as allowing
you to do "column-wise" aggregations, although certain Applicatives
provide other intuitions.</p>
<p>Here's the sum of all profits and expenses across all of our
businesses</p>
<div class="sourceCode" id="cb24"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="kw">let</span> xs <span class="ot">=</span> M.fromList [(<span class="st">&quot;profits&quot;</span>, <span class="dv">1</span>), (<span class="st">&quot;expenses&quot;</span>, <span class="dv">2</span>)] </span>
<span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a>             <span class="op">:|</span> [ M.fromList [(<span class="st">&quot;profits&quot;</span>, <span class="dv">10</span>), (<span class="st">&quot;expenses&quot;</span>, <span class="dv">20</span>)]</span>
<span id="cb24-3"><a href="#cb24-3" aria-hidden="true" tabindex="-1"></a>                , M.fromList [(<span class="st">&quot;profits&quot;</span>, <span class="dv">100</span>), (<span class="st">&quot;expenses&quot;</span>, <span class="dv">200</span>)]</span>
<span id="cb24-4"><a href="#cb24-4" aria-hidden="true" tabindex="-1"></a>                ]</span>
<span id="cb24-5"><a href="#cb24-5" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> xs <span class="op">&amp;</span> reflected <span class="op">&gt;-</span> <span class="fu">sum</span></span>
<span id="cb24-6"><a href="#cb24-6" aria-hidden="true" tabindex="-1"></a>fromList [(<span class="st">&quot;expenses&quot;</span>,<span class="dv">222</span>),(<span class="st">&quot;profits&quot;</span>,<span class="dv">111</span>)]</span>
<span id="cb24-7"><a href="#cb24-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-8"><a href="#cb24-8" aria-hidden="true" tabindex="-1"></a><span class="co">-- Average expenses, average profit</span></span>
<span id="cb24-9"><a href="#cb24-9" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> xs <span class="op">&amp;</span> reflected <span class="op">&gt;-</span> mean</span>
<span id="cb24-10"><a href="#cb24-10" aria-hidden="true" tabindex="-1"></a>fromList [(<span class="st">&quot;expenses&quot;</span>,<span class="fl">74.0</span>),(<span class="st">&quot;profits&quot;</span>,<span class="fl">37.0</span>)]</span>
<span id="cb24-11"><a href="#cb24-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-12"><a href="#cb24-12" aria-hidden="true" tabindex="-1"></a><span class="co">-- Largest expenses and profit</span></span>
<span id="cb24-13"><a href="#cb24-13" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> xs <span class="op">&amp;</span> reflected <span class="op">&gt;-</span> <span class="fu">maximum</span></span>
<span id="cb24-14"><a href="#cb24-14" aria-hidden="true" tabindex="-1"></a>fromList [(<span class="st">&quot;expenses&quot;</span>,<span class="dv">200</span>),(<span class="st">&quot;profits&quot;</span>,<span class="dv">100</span>)]</span></code></pre></div>
<p>This is still a new, exciting, and unexplored area of optics; but I
suspect that once libraries begin to adopt it we'll have an even more
adaptable model for querying and aggregating across many records. Optics
are getting close to the expressive power of dedicated query languages
like SQL!</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Algebraic lenses</title>
      <link href="https://chrispenner.ca/posts/algebraic"/>
      <id>https://chrispenner.ca/posts/algebraic</id>
      <updated>2019-12-18T00:00:00Z</updated>
      <summary>A profunctor implementation of algebraic lenses</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/math.jpeg" alt="Algebraic lenses">
              <p>This is a blog post about optics, if you're at all interested in
optics I suggest you go check out my book: <a
href="https://leanpub.com/optics-by-example">Optics By Example</a>. It
covers everything you need to go from a beginner to master in all things
optics! Check it out and tell your friends, now onwards to the post
you're here for.</p>
<p>In this post we're going to dig into an exciting new type of optics,
the theory of which is described in <a
href="https://cs.ttu.ee/events/nwpt2019/abstracts/paper14.pdf">this
abstract</a> by Mario Román, Bryce Clarke, Derek Elkins, Jeremy Gibbons,
Bartosz Milewski, Fosco Loregian, and Emily Pillmore. Thanks go out to
these awesome folk for researching optics at a high level! The more that
we realize the Category Theory representations of optics the more we can
convince ourselves that they're a true and beautiful abstraction rather
than just a useful tool we stumbled across.</p>
<p>I'm not really a "Mathy" sort of guy, I did very little formal math
in university, and while I've become comfortable in some of the absolute
basics of Category Theory through my travels in Haskell, I certainly
wouldn't consider myself well-versed. I AM however well versed in the
practical uses of optics, and so of course I need to keep myself up to
speed on new developments, so when this abstract became available I set
to work trying to understand it!</p>
<p>Most of the symbols and Category Theory went straight over my head,
but I managed to pick out a few bits and pieces that we'll look at
today. I'll be translating what little I understand into a language
which I DO understand: Haskell!</p>
<p>If the above wasn't enough of a disclaimer I'll repeat: I don't
really understand most of the math behind this stuff, so it's very
possible I've made a few (or a lot) of errors though to be honest I
think the result I've come to is interesting on its own, even if not a
perfect representation of the ideas in the abstract. Please correct me
if you know better :)</p>
<p>There are several new types of optics presented in the paper, we'll
start by looking at one of them in particular, but will set the
groundwork for the others which I'll hopefully get to in future posts.
Today we'll be looking at "Algebraic lenses"!</p>
<h2 id="translating-from-math">Translating from Math</h2>
<p>We'll start by taking a look at the formal characterization of
algebraic lenses presented in the abstract. By the characterization of
an optic I mean a set of values which completely describe the behaviour
of that optic. For instance a <code>Lens s t a b</code> is characterized
by a getter and a setter: <code>(s -&gt; a, s -&gt; b -&gt; t)</code>
and an <code>Iso s t a b</code> is characterized by its <code>to</code>
and <code>from</code> functions:
<code>(s -&gt; a, b -&gt; t)</code>.</p>
<p>The paper presents the characterization of an algebraic lens like
this: (my apologies for lack of proper LaTeX on my blog 😬)</p>
<ul>
<li>Algebraic Lens: <code>(S → A) × (ψS × B → T)</code></li>
</ul>
<p>My blog has kind of butchered the formatting, so feel free to check
it out in the <a
href="http://events.cs.bham.ac.uk/syco/strings3-syco5/slides/roman.pdf">abstract</a>
instead.</p>
<p>I'm not hip to all these crazy symbols, but as best as I can tell, we
can translate it roughly like this:</p>
<ul>
<li>Algebraic Lens: <code>(s -&gt; a, f s -&gt; b -&gt; t)</code></li>
</ul>
<p>If you squint a bit, this looks really close to the characterization
of a standard lens, the only difference being that instead of a
<em>single</em> <code>s</code> we have some container <code>f</code>
filled with them. The type of container further specifies what type of
algebraic lens we're dealing with. For instance, the paper calls it a
<code>List Lens</code> if <code>f</code> is chosen to be a list
<code>[]</code>, but we can really define optics for nearly any choice
of <code>f</code>, though Traversable and Foldable types are a safe bet
to start.</p>
<p>So, what can we actually do with this characterization? Well for
starters it implies we can pass it more than one <code>s</code> at once,
which is already different than a normal lens, but we can also use all
of those <code>s</code>'s alongside the result of the continuation (i.e.
<code>b</code>) to choose our return value <code>t</code>. That probably
sounds pretty overly generalized, and that's because it is! We're
dealing with a mathematical definition, so it's intentionally as general
as possible.</p>
<p>To put it into slightly more concrete terms, an Algebraic lens allows
us to run some <em>aggregation</em> over a collection of substates of
our input, then use the result of the aggregation to pick some result to
return.</p>
<p>The example given in the paper (which we'll implement soon) uses an
algebraic lens to do classification of flower measurements into
particular species. It uses the "projection" function from the
characterization (e.g. <code>s -&gt; a</code>) to select the
measurements from a <code>Flower</code>, and the "selection" function
(<code>f s -&gt; b -&gt; t</code>) to take a <strong>list</strong> of
Flowers, and a reference set of measurements, to classify those
measurements into a species, returning a flower with the selected
measurements and species.</p>
<p>We'll learn more about that as we implement it!</p>
<h2 id="first-guesses-at-an-implementation">First guesses at an
implementation</h2>
<p>In the abstract we're given the <em>prose</em> for what the provided
examples are intended to do, unfortunately we're only given a few very
small code snippets without any source code or even type-signatures to
help us out, so I'll mostly be guessing my way through this. As far as I
can tell the paper is more concerned with proving the math first, since
an implementation <strong>must</strong> exist if the math works out
right? Let's see if we can take on the role of <strong>applied</strong>
mathematician and get some code we can actually run 😃. I'll need to
take a few creative liberties to get everything wired together.</p>
<p>Here are the examples given in the abstract:</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="co">-- Assume &#39;iris&#39; is a data-set (e.g. list) of flower objects</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> (iris <span class="op">!!</span> <span class="dv">1</span>) <span class="op">^.</span> measurements</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>(<span class="fl">4.9</span> , <span class="fl">3.0</span> , <span class="fl">1.4</span> , <span class="fl">0.2</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="op">&gt;&gt;&gt;</span> iris <span class="op">?.</span> measurements ( <span class="dt">Measurements</span> <span class="fl">4.8</span> <span class="fl">3.1</span> <span class="fl">1.5</span> <span class="fl">0.1</span>)</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="dt">Iris</span> <span class="dt">Setosa</span> (<span class="fl">4.8</span> , <span class="fl">3.1</span> , <span class="fl">1.5</span> , <span class="fl">0.1</span>)</span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> iris <span class="op">&gt;-</span> measurements <span class="op">.</span> aggregateWith mean</span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="dt">Iris</span> <span class="dt">Versicolor</span> (<span class="fl">5.8</span>, <span class="fl">3.0</span>, <span class="fl">3.7</span>, <span class="fl">1.1</span>)</span></code></pre></div>
<p>We're not provided with the implementation of <code>?.</code>,
<code>&gt;-</code>, <code>Measurements</code>,
<code>measurements</code>, OR <code>aggregateWith</code>, nor do we have
the data-set that builds up <code>iris</code>... Looks like we've got
our work cut out for us here 😓</p>
<p>To start I'll make some assumptions to build up a dummy data-set of
flowers to experiment with:</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="co">-- Some flower species</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Species</span> <span class="ot">=</span> <span class="dt">Setosa</span> <span class="op">|</span> <span class="dt">Versicolor</span> <span class="op">|</span> <span class="dt">Virginica</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> <span class="dt">Show</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="co">-- Our measurements will just be a list of floats for now</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Measurements</span> <span class="ot">=</span> <span class="dt">Measurements</span> {<span class="ot">getMeasurements ::</span> [<span class="dt">Float</span>]}</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> <span class="dt">Show</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 class="co">-- A flower consists of a species and some measurements</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Flower</span> <span class="ot">=</span> <span class="dt">Flower</span> {<span class="ot"> flowerSpecies ::</span> <span class="dt">Species</span></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a>                     ,<span class="ot"> flowerMeasurements ::</span> <span class="dt">Measurements</span>}</span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> <span class="dt">Show</span></span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a><span class="ot">versicolor ::</span> <span class="dt">Flower</span></span>
<span id="cb2-15"><a href="#cb2-15" aria-hidden="true" tabindex="-1"></a>versicolor <span class="ot">=</span> <span class="dt">Flower</span> <span class="dt">Versicolor</span> (<span class="dt">Measurements</span> [<span class="dv">2</span>, <span class="dv">3</span>, <span class="dv">4</span>, <span class="dv">2</span>])</span>
<span id="cb2-16"><a href="#cb2-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-17"><a href="#cb2-17" aria-hidden="true" tabindex="-1"></a><span class="ot">setosa ::</span> <span class="dt">Flower</span></span>
<span id="cb2-18"><a href="#cb2-18" aria-hidden="true" tabindex="-1"></a>setosa <span class="ot">=</span> <span class="dt">Flower</span> <span class="dt">Setosa</span> (<span class="dt">Measurements</span> [<span class="dv">5</span>, <span class="dv">4</span>, <span class="dv">3</span>, <span class="fl">2.5</span>])</span>
<span id="cb2-19"><a href="#cb2-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-20"><a href="#cb2-20" aria-hidden="true" tabindex="-1"></a><span class="ot">flowers ::</span> [<span class="dt">Flower</span>]</span>
<span id="cb2-21"><a href="#cb2-21" aria-hidden="true" tabindex="-1"></a>flowers <span class="ot">=</span> [versicolor, setosa]</span></code></pre></div>
<p>That gives us something to fool around with at least, even if it's
not exactly like the data-set used in the paper.</p>
<p>Now for the fun part, we need to figure out how we can somehow cram a
classification algorithm into an optic! They loosely describe
<code>measurements</code> as a list-lens which "encapsulates some
learning algorithm which classifies measurements into a species", but
the concrete programmatic definition of that will be up to my best
judgement I suppose.</p>
<p>I'll be implementing these as Profunctor optics, they tend to work
out a bit <strong>cleaner</strong> than the Van-Laarhoven approach,
especially when working with "Grate-Like" optics which is where an
algebraic-lens belongs. The sheer amount of guessing and filling in
blanks I had to do means I stared at this for a good long while before I
figured out a way to make this work. One of the tough parts is that the
examples show the optic work for a <strong>single</strong> flower (like
the <code>(iris !! 1) ^. measurements</code> example), but it somehow
also runs a classifier over a <strong>list</strong> of flowers as in the
<code>iris ?. measurements ( Measurements 4.8 3.1 1.5 0.1)</code>
example. We need to find the minimal profunctor constraints which allow
us to lift the characterization into an actual runnable optic!</p>
<p>I've been on a bit of a Corepresentable kick lately and it seemed
like a good enough place to start. It also has the benefit of being
easily translated into Van-Laarhoven optics if needed.</p>
<p>Here was my first crack at it:</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">import</span> <span class="dt">Data.Profunctor</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Profunctor.Sieve</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Profunctor.Rep</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Foldable</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 class="kw">type</span> <span class="dt">Optic</span> p s t a b <span class="ot">=</span> p a b <span class="ot">-&gt;</span> p s t</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 class="ot">listLens ::</span> <span class="kw">forall</span> p f s t a b</span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a>         <span class="op">.</span> (<span class="dt">Corepresentable</span> p, <span class="dt">Corep</span> p <span class="op">~</span> f, <span class="dt">Foldable</span> f)</span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a>         <span class="ot">=&gt;</span> (s <span class="ot">-&gt;</span> a)</span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a>         <span class="ot">-&gt;</span> ([s] <span class="ot">-&gt;</span> b <span class="ot">-&gt;</span> t)</span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a>         <span class="ot">-&gt;</span> <span class="dt">Optic</span> p s t a b</span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a>listLens project flatten p <span class="ot">=</span> cotabulate run</span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true" tabindex="-1"></a><span class="ot">    run ::</span> f s <span class="ot">-&gt;</span> t</span>
<span id="cb3-16"><a href="#cb3-16" aria-hidden="true" tabindex="-1"></a>    run fs <span class="ot">=</span> flatten (toList fs) (cosieve p <span class="op">.</span> <span class="fu">fmap</span> project <span class="op">$</span> fs)</span></code></pre></div>
<p>This is a LOT to take in, let's address it in pieces.</p>
<p>First things first, a profunctor optic is simply a morphism over a
profunctor, something like: <code>p a b -&gt; p s t</code>.</p>
<p>Next, the <code>Corepresentable</code> constraint:</p>
<p><a
href="https://hackage.haskell.org/package/profunctors-5.5.1/docs/Data-Profunctor-Rep.html#t:Corepresentable"><strong>Corepresentable</strong></a>
has <a
href="https://hackage.haskell.org/package/profunctors-5.5.1/docs/Data-Profunctor-Sieve.html#t:Cosieve"><code>Cosieve</code></a>
as a superclass, and so provides us with both of the following
methods:</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="dt">Cosieve</span> p f       <span class="ot">=&gt; cosieve    ::</span> p a b <span class="ot">-&gt;</span> f a <span class="ot">-&gt;</span> b</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Corepresentable</span> p <span class="ot">=&gt; cotabulate ::</span> (<span class="dt">Corep</span> p d <span class="ot">-&gt;</span> c) <span class="ot">-&gt;</span> p d c</span></code></pre></div>
<p>These two functions together allow us to round-trip our profunctor
from <code>p a b</code> into some <code>f a -&gt; b</code> and then
back! In fact, this is the essence of what <code>Corepresentable</code>
<em>means</em>, we can "<strong>represent</strong>" the profunctor as a
function from a value in some context <code>f</code> to the result.</p>
<p>Profunctors in general <strong>can't simply be applied</strong> like
functions can, these two functions allow us to reflect an opaque and
mysterious generic profunctor into a real function that we can
<strong>actually run</strong>! In our implementation we fmap
<code>project</code> over the <code>f s</code>'s to get
<code>f a</code>, then run that through the provided continuation:
<code>f a -&gt; b</code> which we obtain by running <code>cosieve</code>
on the profunctor argument, then we can flatten the whole thing using
the user-provided <em>classification</em>-style function.</p>
<p>Don't worry if this doesn't make a ton of sense on its own, it took
me a while to figure out. At the end of the day, we have a helper which
allows us to write a list-lens which composes with any
<code>Corepresentable</code> profunctor. This allows us to write our
<code>measurements</code> classifier, but we'll need a few helper
functions first.</p>
<p>First we'll write a helper to compute the Euclidean distance between
two flowers' measurements (e.g. we'll compute the difference between
each set of measurements, then sum the difference):</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">measurementDistance ::</span> <span class="dt">Measurements</span> <span class="ot">-&gt;</span> <span class="dt">Measurements</span> <span class="ot">-&gt;</span> <span class="dt">Float</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>measurementDistance (<span class="dt">Measurements</span> xs) (<span class="dt">Measurements</span> ys) <span class="ot">=</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>    <span class="fu">sqrt</span> <span class="op">.</span> <span class="fu">sum</span> <span class="op">$</span> <span class="fu">zipWith</span> diff xs ys</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>    diff a b <span class="ot">=</span> (a <span class="op">-</span> b) <span class="op">**</span> <span class="dv">2</span></span></code></pre></div>
<p>This will tell us how similar two measurements are, the lower the
result, the more similar they are.</p>
<p>Next we'll write a function which when given a reference set of
flowers will detect the flower which is most similar to a given set of
measurements. It will then build a flower by combining the closest
species and the given measurements.</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">classify ::</span> [<span class="dt">Flower</span>] <span class="ot">-&gt;</span> <span class="dt">Measurements</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> <span class="dt">Flower</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>classify flowers m</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="fu">null</span> flowers <span class="ot">=</span> <span class="dt">Nothing</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">let</span> <span class="dt">Flower</span> species _ <span class="ot">=</span> minimumBy</span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>                          (comparing (measurementDistance m <span class="op">.</span> flowerMeasurements))</span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a>                          flowers</span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a>   <span class="kw">in</span> <span class="dt">Just</span> <span class="op">$</span> <span class="dt">Flower</span> species m</span></code></pre></div>
<p>This function returns its result in <code>Maybe</code>, since we
can't classify anything if we're given an empty data-set.</p>
<p>Now we have our pieces, we can build the <code>measurements</code>
list-lens!</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">measurements ::</span> (<span class="dt">Corepresentable</span> p, <span class="dt">Corep</span> p <span class="op">~</span> f, <span class="dt">Foldable</span> f) </span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>             <span class="ot">=&gt;</span> <span class="dt">Optic</span> p <span class="dt">Flower</span> (<span class="dt">Maybe</span> <span class="dt">Flower</span>) <span class="dt">Measurements</span> <span class="dt">Measurements</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>measurements <span class="ot">=</span> listLens flowerMeasurements classify</span></code></pre></div>
<p>We specify that the container type used in the
<code>Corepresentable</code> instance must be foldable so that we can
convert it into a list to do our classification.</p>
<p>Okay! Now we have enough to try some things out! The first example
given in the abstract is:</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> (iris <span class="op">!!</span> <span class="dv">1</span>) <span class="op">^.</span> measurements</span></code></pre></div>
<p>Which we'll translate into:</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> (flowers <span class="op">!!</span> <span class="dv">1</span>) <span class="op">^.</span> measurements</span></code></pre></div>
<p>But unfortunately we get an error:</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="dt">No</span> <span class="kw">instance</span> for (<span class="dt">Corepresentable</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>                      (<span class="dt">Data.Profunctor.Types.Forget</span> <span class="dt">Measurements</span>))</span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>    arising from a use <span class="kw">of</span> ‘measurements’</span></code></pre></div>
<p>By the way, all the examples in this post are implemented using my
<strong>highly experimental</strong> Haskell profunctor optics
implementation <a
href="https://github.com/ChrisPenner/proton"><strong>proton</strong></a>.
Feel free to play with it, but don't use it in anything important.</p>
<p>Hrmm, looks like <code>(^.)</code> uses <code>Forget</code> for its
profunctor and it doesn't have a <code>Corepresentable</code> instance!
We'll come back to that soon, let's see if we can get anything else
working first.</p>
<p>The next example is:</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>iris <span class="op">?.</span> measurements (<span class="dt">Measurements</span> <span class="fl">4.8</span> <span class="fl">3.1</span> <span class="fl">1.5</span> <span class="fl">0.1</span>)</span></code></pre></div>
<p>I'll admit I don't understand how this example could possibly work,
optics necessarily have the type <code>p a b -&gt; p s t</code>, so how
are they passing a <code>Measurements</code> object directly into the
optic? Perhaps it has some other signature, but we know that's not true
from the previous example which uses it directly as a lens! Hrmm, I
strongly suspect that this is a typo, mistake, or most likely this
example is actually just short-hand pseudocode of what an implementation
<em>might</em> look like and we're discovering a few rough edges.
Perhaps the writers of the paper thought of something sneaky that I
missed. Without the source code for the example we'll never know, but
since I can't see how this version could work, let's modify it into
something <em>close</em> which I <strong>can</strong> figure out.</p>
<p>It appears as though <code>(?.)</code> is an <strong>action</strong>
which runs the optic. Actions in profunctor optics tend to specialize
the optic to a specific profunctor, then pass the other arguments
through it using that profunctor as a carrier. We know we need a
profunctor that's <code>Corepresentable</code>, and the simplest
instance for that is definitely <code>Costar</code>! Here's what it
looks like:</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">newtype</span> <span class="dt">Costar</span> f a b <span class="ot">=</span> <span class="dt">Costar</span> (f a <span class="ot">-&gt;</span> b)</span></code></pre></div>
<p><code>Costar</code> is basically the "free" Corepresentable, it's
just a new-type wrapper around a function from values in a container to
a result. You might also know it by the name <code>Cokleisli</code>,
they're the same type, but <code>Costar</code> is the one we typically
use with Profunctors.</p>
<p>If we swap the arguments in the example around a bit, we can write an
action which runs the optic using Costar like this:</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">(?.) ::</span> (<span class="dt">Foldable</span> f) <span class="ot">=&gt;</span> f s <span class="ot">-&gt;</span> <span class="dt">Optic</span> (<span class="dt">Costar</span> f) s t a b <span class="ot">-&gt;</span> b <span class="ot">-&gt;</span> t</span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>(<span class="op">?.</span>) xs f a <span class="ot">=</span> (runCostar <span class="op">$</span> f (<span class="dt">Costar</span> (<span class="fu">const</span> a))) xs</span></code></pre></div>
<p>The example seems to use a static value for the comparison, so I use
<code>const</code> to embed that value into the <code>Costar</code>
profunctor, then run that through the provided profunctor morphism (i.e.
optic).</p>
<p>This lets us write the example like this instead:</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="op">&gt;&gt;&gt;</span> flowers <span class="op">?.</span> measurements <span class="op">$</span> <span class="dt">Measurements</span> [<span class="dv">5</span>, <span class="dv">4</span>, <span class="dv">3</span>, <span class="dv">1</span>]</span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> (<span class="dt">Flower</span> <span class="dt">Setosa</span> (<span class="dt">Measurements</span> [<span class="fl">5.0</span>,<span class="fl">4.0</span>,<span class="fl">3.0</span>,<span class="fl">1.0</span>]))</span></code></pre></div>
<p>Which is <em>really</em> close to the original, we just added a
<code>$</code> to make it work.</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> iris <span class="op">?.</span> measurements (<span class="dt">Measurements</span> <span class="fl">4.8</span> <span class="fl">3.1</span> <span class="fl">1.5</span> <span class="fl">0.1</span>)</span></code></pre></div>
<p>Let's see if this is actually working properly. We're passing a
"fixed" measurement in as our aggregation function, meaning we're
comparing every flower in our list to these specific measurements and
will find the flower that's "closest". We then build a flower using the
species closest to those measurements alongside the provided
measurements. To test that this is actually working properly, let's try
again with measurements that match our <code>versicolor</code> flower
more closely:</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="op">&gt;&gt;&gt;</span> setosa</span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Flower</span> <span class="dt">Setosa</span> (<span class="dt">Measurements</span> [<span class="fl">5.0</span>,<span class="fl">4.0</span>,<span class="fl">3.0</span>,<span class="fl">2.5</span>])</span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> versicolor</span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Flower</span> <span class="dt">Versicolor</span> (<span class="dt">Measurements</span> [<span class="fl">2.0</span>,<span class="fl">3.0</span>,<span class="fl">4.0</span>,<span class="fl">2.0</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="co">-- By choosing measurements close to the `versicolor` in our data-set</span></span>
<span id="cb16-7"><a href="#cb16-7" aria-hidden="true" tabindex="-1"></a><span class="co">-- we expect the measurements to be classified as Versicolor</span></span>
<span id="cb16-8"><a href="#cb16-8" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> flowers <span class="op">?.</span> measurements <span class="op">$</span> <span class="dt">Measurements</span> [<span class="fl">1.9</span>, <span class="fl">3.2</span>, <span class="fl">3.8</span>, <span class="dv">2</span>]</span>
<span id="cb16-9"><a href="#cb16-9" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> (<span class="dt">Flower</span> <span class="dt">Versicolor</span> (<span class="dt">Measurements</span> [<span class="fl">1.9</span>,<span class="fl">3.2</span>,<span class="fl">3.8</span>,<span class="fl">2.0</span>]))</span></code></pre></div>
<p>We can see that indeed it now switches the classification to
<code>Versicolor</code>! It appears to be working!</p>
<p>Even though this version looks a lot like the example in the
abstract, it doesn't quite feel in line with style of existing optics
libraries so I'll flip the arguments around a bit further: (I'll rename
the combinator to <code>?-</code> to avoid confusion with the
original)</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="ot">(?-) ::</span> (<span class="dt">Foldable</span> f) <span class="ot">=&gt;</span> f s <span class="ot">-&gt;</span> <span class="dt">Optic</span> (<span class="dt">Costar</span> f) s t a b <span class="ot">-&gt;</span> b <span class="ot">-&gt;</span> t</span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a>(<span class="op">?-</span>) xs f a <span class="ot">=</span> (runCostar <span class="op">$</span> f (<span class="dt">Costar</span> (<span class="fu">const</span> a))) xs</span></code></pre></div>
<p>The behaviour is the same, but flipping the arguments allows it to
fit the "feel" of other optics combinators better (IMHO), we use it like
this:</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="op">&gt;&gt;&gt;</span> flowers <span class="op">&amp;</span> measurements <span class="op">?-</span> <span class="dt">Measurements</span> [<span class="dv">5</span>, <span class="dv">4</span>, <span class="dv">3</span>, <span class="dv">1</span>]</span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> (<span class="dt">Flower</span> <span class="dt">Setosa</span> (<span class="dt">Measurements</span> [<span class="fl">5.0</span>,<span class="fl">4.0</span>,<span class="fl">3.0</span>,<span class="fl">2.5</span>]))</span></code></pre></div>
<p>We pass in the data-set, and "assign" our comparison value to be the
single Measurement we're considering.</p>
<h2 id="making-measurements-a-proper-lens">Making
<code>measurements</code> a proper lens</h2>
<p>Before moving on any further, let's see if we can fix up
<code>measurements</code> so we can use <code>(^.)</code> on a single
flower like the first example does. Remember, <code>(^.)</code> uses
<code>Forget</code> as the concrete profunctor instead of
<code>Costar</code>, so whatever we do, it has to have a valid instance
for the <code>Forget</code> profunctor which looks like this:</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">newtype</span> <span class="dt">Forget</span> r a b <span class="ot">=</span> <span class="dt">Forget</span> (a <span class="ot">-&gt;</span> r)</span></code></pre></div>
<p>As an exercise for the reader, try to implement
<code>Corepresentable</code> for <code>Forget</code> (or even
<code>Cosieve</code>) and you'll see it's not possible, so we'll need to
find a new tactic. Perhaps there's some other <em>weaker</em>
abstraction we can invent which works for our purposes.</p>
<p>The end-goal here is to create an optic out of the characterization
of an algebraic lens, so what if we just encode that exact idea into a
typeclass? It's so simple it just might work! Probably should have
started here, sticking with the optics metaphor: hindsight is 20/20.</p>
<div class="sourceCode" id="cb20"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE MultiParamTypeClasses #-}</span></span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE FunctionalDependencies #-}</span></span>
<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Profunctor</span> p <span class="ot">=&gt;</span> <span class="dt">Algebraic</span> f p <span class="op">|</span> p <span class="ot">-&gt;</span> f <span class="kw">where</span></span>
<span id="cb20-5"><a href="#cb20-5" aria-hidden="true" tabindex="-1"></a><span class="ot">  algebraic ::</span> (s <span class="ot">-&gt;</span> a) <span class="ot">-&gt;</span> (f s <span class="ot">-&gt;</span> b <span class="ot">-&gt;</span> t) <span class="ot">-&gt;</span> p a b <span class="ot">-&gt;</span> p s t</span>
<span id="cb20-6"><a href="#cb20-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-7"><a href="#cb20-7" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">AlgebraicLens</span> f s t a b <span class="ot">=</span> <span class="kw">forall</span> p<span class="op">.</span> <span class="dt">Algebraic</span> f p <span class="ot">=&gt;</span> p a b <span class="ot">-&gt;</span> p s t</span>
<span id="cb20-8"><a href="#cb20-8" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">AlgebraicLens&#39;</span> f s a <span class="ot">=</span> <span class="dt">AlgebraicLens</span> f s s a a</span></code></pre></div>
<p>By keeping <code>f</code> general we can write list-lenses or any
other type of algebraic lens. I added a functional dependency here to
help with type-inference. This class represents <strong>exactly</strong>
what we want an algebraic lens to do. It's entirely possible there's a
more general profunctor class which has equivalent power, if I'm missing
one please let me know!</p>
<p>Now that we have a typeclass we'll implement an instance for Costar
so we can still use our <code>(?.)</code> and <code>(?-)</code>
actions:</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="kw">instance</span> <span class="dt">Functor</span> f <span class="ot">=&gt;</span> <span class="dt">Algebraic</span> f (<span class="dt">Costar</span> f) <span class="kw">where</span></span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a>  algebraic project flatten p <span class="ot">=</span> cotabulate run</span>
<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">where</span></span>
<span id="cb21-4"><a href="#cb21-4" aria-hidden="true" tabindex="-1"></a>      run fs <span class="ot">=</span> flatten fs (cosieve (lmap project p) fs)</span></code></pre></div>
<p>Technically this implementation works on <strong>any</strong>
Corepresentable profunctor, not just Costar, so we could re-use this for
a few other profunctors too!</p>
<p>Did we make any progress? We need to see if we can implement an
instance of <code>Algebraic</code> for <code>Forget</code>, if we can
manage that, then we can use <code>view</code> over our
<code>measurements</code> optic just like the example does.</p>
<div class="sourceCode" id="cb22"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Algebraic</span> <span class="dt">Proxy</span> (<span class="dt">Forget</span> r) <span class="kw">where</span></span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a>  algebraic project _flatten (<span class="dt">Forget</span> f) <span class="ot">=</span> <span class="dt">Forget</span> (f <span class="op">.</span> project)</span></code></pre></div>
<p>Well that was pretty painless! This allows us to do what our
<code>Corepresentable</code> requirement didn't.</p>
<p>I've arbitrarily chosen <code>Proxy</code> as the carrier type
because it's empty and doesn't contain any values. The carrier itself
isn't every used, but I needed to pick something and this seemed like a
good a choice as any. Perhaps a higher-rank void type would be more
appropriate, but we'll cross that bridge when we have to.</p>
<p>With that, we just need to re-implement our <code>measurements</code>
optic using <code>Algebraic</code>:</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">measurements ::</span> <span class="dt">Foldable</span> f </span>
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a>             <span class="ot">=&gt;</span> <span class="dt">AlgebraicLens</span> f <span class="dt">Flower</span> (<span class="dt">Maybe</span> <span class="dt">Flower</span>) <span class="dt">Measurements</span> <span class="dt">Measurements</span></span>
<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a>measurements <span class="ot">=</span> algebraic flowerMeasurements classify</span></code></pre></div>
<p>The name <code>measurements</code> is a bit of a misnomer, it does
classification and selection, which is quite a bit more than just
selecting the measurements! Perhaps a better name would be
<code>measurementsClassifier</code> or something. I'll stick to the name
used in the abstract for now.</p>
<p>Now we can view through our <code>measurements</code> optic directly!
This fulfills the first example perfectly!</p>
<div class="sourceCode" id="cb24"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> (flowers <span class="op">!!</span> <span class="dv">1</span>) <span class="op">^.</span> measurements</span>
<span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Measurements</span> [<span class="fl">5.0</span>,<span class="fl">4.0</span>,<span class="fl">3.0</span>,<span class="fl">2.5</span>]</span></code></pre></div>
<p>Awesome! All that's left to have a <strong>proper</strong> lens is to
be able to <strong>set</strong> as well. In profunctor optics, the set
and modify actions simply use the <code>(-&gt;)</code> profunctor, so
we'll need an instance for that. Technically <code>(-&gt;)</code> is
isomorphic to <code>Costar Identity</code>, so we could use the exact
same implementation we used for our <code>Costar</code> instance but
there's a simpler implementation if we specialize. It turns out that
<code>Identity</code> makes a good carrier type since it holds exactly
one argument.</p>
<div class="sourceCode" id="cb25"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Algebraic</span> <span class="dt">Identity</span> (<span class="ot">-&gt;</span>) <span class="kw">where</span></span>
<span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a>  algebraic project flatten p <span class="ot">=</span> run</span>
<span id="cb25-3"><a href="#cb25-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">where</span></span>
<span id="cb25-4"><a href="#cb25-4" aria-hidden="true" tabindex="-1"></a>      run s <span class="ot">=</span> flatten (<span class="dt">Identity</span> s) (p <span class="op">.</span> project <span class="op">$</span> s)</span></code></pre></div>
<p>Now we can modify or set measurements through our algebraic lens
too:</p>
<div class="sourceCode" id="cb26"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> versicolor <span class="op">&amp;</span> measurements <span class="op">.~</span> <span class="dt">Measurements</span> [<span class="dv">9</span>, <span class="dv">8</span>, <span class="dv">7</span>, <span class="dv">6</span>]</span>
<span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Flower</span> <span class="dt">Versicolor</span> <span class="dt">Measurements</span> [<span class="fl">9.0</span>,<span class="fl">8.0</span>,<span class="fl">7.0</span>,<span class="fl">6.0</span>]</span></code></pre></div>
<p>Since we can get and set, our algebraic lens is indeed a full-blown
lens! This is surprisingly interesting interesting since we didn't make
any use of <code>Strong</code> which is how most lenses are implemented,
and in fact <code>Costar</code> <strong>isn't</strong> a Strong
profunctor!</p>
<p>You might be curious how this actually works at all, behind the
scenes the algebraic lens receives the new measurements as though it
were the result of an aggregation, then uses those measurements with the
Species of the single input flower (which of course hasn't changed),
thus appearing to modify the flower's measurements! It's the "long way
round" but it behaves exactly the same as a simpler lens would.</p>
<p>Here's one last interesting instance just for fun:</p>
<div class="sourceCode" id="cb27"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Algebraic</span> <span class="dt">Proxy</span> <span class="dt">Tagged</span> <span class="kw">where</span></span>
<span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a>  algebraic project flatten (<span class="dt">Tagged</span> b) <span class="ot">=</span> <span class="dt">Tagged</span> (flatten <span class="dt">Proxy</span> b)</span></code></pre></div>
<p><code>Tagged</code> is used for the <code>review</code> actions,
which means we can try running our algebraic lens as a review:</p>
<div class="sourceCode" id="cb28"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb28-1"><a href="#cb28-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> review measurements (<span class="dt">Measurements</span> [<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>, <span class="dv">4</span>])</span>
<span id="cb28-2"><a href="#cb28-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Nothing</span></span></code></pre></div>
<p>I suppose that's what we can expect, we're effectively classifying
measurements without any data-set, so our <code>classify</code> function
'fails' with it's Nothing value. It's very cool to know that we can (in
general) run algebraic lenses in reverse like this!</p>
<h2 id="running-custom-aggregations">Running custom aggregations</h2>
<p>We have one more example left to look at:</p>
<div class="sourceCode" id="cb29"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb29-1"><a href="#cb29-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> iris <span class="op">&gt;-</span> measurements <span class="op">.</span> aggregateWith mean</span>
<span id="cb29-2"><a href="#cb29-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Iris</span> <span class="dt">Versicolor</span> (<span class="fl">5.8</span> , <span class="fl">3.0</span> , <span class="fl">3.7</span> , <span class="fl">1.1</span>)</span></code></pre></div>
<p>In this example they compute the <strong>mean</strong> of
<strong>each</strong> of the respective measurements across their whole
data-set, then find the species of flower which best represents the
"average flower" of the data-set.</p>
<p>In order to implement this we'd need to implement
<code>aggregateWith</code>, which is a <code>Kaleidoscope</code>, and
that's a whole different type of optic, so we'll continue this thread in
a subsequent post but we can get <strong>most</strong> of the way there
with what we've got already if we write a slightly smarter aggregation
function.</p>
<p>To spoil kaleidoscopes just a little, <code>aggregateWith</code>
allows running aggregations over lists of <em>associated</em>
measurements. That is to say that it <strong>groups up</strong> each set
of related measurements across all of the flowers, then takes the mean
of each <strong>set</strong> of measurements (i.e. the mean all the
first measurements, the mean of all the second measurements, etc.). If
we don't mind the inconvenience, we can implement this exact same
example by baking that logic into an aggregation function and thus avoid
the need for a Kaleidoscope until the next blog post 😉</p>
<p>Right now our <code>measurements</code> function
<strong>focuses</strong> the <code>Measurements</code> of a set of
flowers, the only action we have right now ignores the data-set entirely
and accepts a specific measurement as input, but we can easily modify it
to take a custom aggregation function:</p>
<div class="sourceCode" id="cb30"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb30-1"><a href="#cb30-1" aria-hidden="true" tabindex="-1"></a><span class="kw">infixr</span> <span class="dv">4</span> <span class="op">&gt;-</span></span>
<span id="cb30-2"><a href="#cb30-2" aria-hidden="true" tabindex="-1"></a><span class="ot">(&gt;-) ::</span> <span class="dt">Optic</span> (<span class="dt">Costar</span> f) s t a b <span class="ot">-&gt;</span> (f a <span class="ot">-&gt;</span> b) <span class="ot">-&gt;</span> f s <span class="ot">-&gt;</span> t</span>
<span id="cb30-3"><a href="#cb30-3" aria-hidden="true" tabindex="-1"></a>(<span class="op">&gt;-</span>) opt aggregator xs <span class="ot">=</span> (runCostar <span class="op">$</span> opt (<span class="dt">Costar</span> aggregator)) xs</span></code></pre></div>
<p>My version of the combinator re-arranges the arguments a bit (again)
to make it read a bit more like <code>%~</code> and friends. It takes an
algebraic lens on the left and an aggregation function on the right.
It'll run the custom aggregation and hand off the result to the
algebraic lens.</p>
<p>This lets us write the above example like this:</p>
<div class="sourceCode" id="cb31"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb31-1"><a href="#cb31-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> flowers <span class="op">&amp;</span> measurements <span class="op">&gt;-</span> avgMeasurement</span></code></pre></div>
<p>But we'll need to define the <code>avgMeasurement</code> function
first. It needs to take a Foldable container filled with measurements
and compute the average value for each of the four measurements. If
we're clever about it <code>transpose</code> can re-group all the
measurements exactly how we want!</p>
<div class="sourceCode" id="cb32"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb32-1"><a href="#cb32-1" aria-hidden="true" tabindex="-1"></a><span class="ot">mean ::</span> <span class="dt">Fractional</span> a <span class="ot">=&gt;</span> [a] <span class="ot">-&gt;</span> a</span>
<span id="cb32-2"><a href="#cb32-2" aria-hidden="true" tabindex="-1"></a>mean [] <span class="ot">=</span>  <span class="dv">0</span></span>
<span id="cb32-3"><a href="#cb32-3" aria-hidden="true" tabindex="-1"></a>mean xs <span class="ot">=</span> <span class="fu">sum</span> xs <span class="op">/</span> <span class="fu">fromIntegral</span> (<span class="fu">length</span> xs)</span>
<span id="cb32-4"><a href="#cb32-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb32-5"><a href="#cb32-5" aria-hidden="true" tabindex="-1"></a><span class="ot">avgMeasurement ::</span> <span class="dt">Foldable</span> f <span class="ot">=&gt;</span> f <span class="dt">Measurements</span> <span class="ot">-&gt;</span> <span class="dt">Measurements</span></span>
<span id="cb32-6"><a href="#cb32-6" aria-hidden="true" tabindex="-1"></a>avgMeasurement ms <span class="ot">=</span> <span class="dt">Measurements</span> (mean <span class="op">&lt;$&gt;</span> groupedMeasurements)</span>
<span id="cb32-7"><a href="#cb32-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb32-8"><a href="#cb32-8" aria-hidden="true" tabindex="-1"></a><span class="ot">    groupedMeasurements ::</span> [[<span class="dt">Float</span>]]</span>
<span id="cb32-9"><a href="#cb32-9" aria-hidden="true" tabindex="-1"></a>    groupedMeasurements <span class="ot">=</span> transpose (getMeasurements <span class="op">&lt;$&gt;</span> toList ms)</span></code></pre></div>
<p>We manually pair all the associated elements, then construct a new
set of measurements where each value is the average of that measurement
across all the inputs.</p>
<p>Now we can finally find out what species the <em>average flower</em>
is closest to!</p>
<div class="sourceCode" id="cb33"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb33-1"><a href="#cb33-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> flowers <span class="op">&amp;</span> measurements <span class="op">&gt;-</span> avgMeasurement</span>
<span id="cb33-2"><a href="#cb33-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> (<span class="dt">Flower</span> <span class="dt">Versicolor</span> (<span class="dt">Measurements</span> [<span class="fl">3.5</span>,<span class="fl">3.5</span>,<span class="fl">3.5</span>,<span class="fl">2.25</span>]))</span></code></pre></div>
<p>Looks like it's closest to the Versicolor species!</p>
<p>We can substitute <code>avgMeasurement</code> for any sort of
aggregation function of type
<code>[Measurements] -&gt; Measurements</code> and this expression will
run it on our data-set and return the species which is closest to those
measurements. Pretty cool stuff!</p>
<h2 id="custom-container-types">Custom container types</h2>
<p>We've stuck with a list so far since it's easy to think about, but
algebraic lenses work over any container type so long as you can
implement the aggregation functions you want on them. In this case we
only require Foldable for our classifier, so we can hot-swap our list
for a Map without any changes!</p>
<div class="sourceCode" id="cb34"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb34-1"><a href="#cb34-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> M.fromList [(<span class="fl">1.2</span>, setosa), (<span class="fl">0.6</span>, versicolor)] </span>
<span id="cb34-2"><a href="#cb34-2" aria-hidden="true" tabindex="-1"></a>      <span class="op">&amp;</span> measurements <span class="op">&gt;-</span> avgMeasurement</span>
<span id="cb34-3"><a href="#cb34-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> (<span class="dt">Flower</span> <span class="dt">Versicolor</span> (<span class="dt">Measurements</span> [<span class="fl">3.5</span>,<span class="fl">3.5</span>,<span class="fl">3.5</span>,<span class="fl">2.25</span>]))</span></code></pre></div>
<p>This gives us the same answer of course since the foldable instance
simply ignores the keys, but the container type is carried through any
composition of algebraic lenses! That means our aggregation function now
has type: <code>Map Float Measurements -&gt; Measurements</code>, see
how it still projects from <code>Flower</code> into
<code>Measurements</code> even inside the map? Let's say we want to run
a scaling factor over each of our measurements as part of aggregating
them, we can bake it into the aggregation like this:</p>
<div class="sourceCode" id="cb35"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb35-1"><a href="#cb35-1" aria-hidden="true" tabindex="-1"></a><span class="ot">scaleBy ::</span> <span class="dt">Float</span> <span class="ot">-&gt;</span> <span class="dt">Measurements</span> <span class="ot">-&gt;</span> <span class="dt">Measurements</span></span>
<span id="cb35-2"><a href="#cb35-2" aria-hidden="true" tabindex="-1"></a>scaleBy w (<span class="dt">Measurements</span> m) <span class="ot">=</span> <span class="dt">Measurements</span> (<span class="fu">fmap</span> (<span class="op">*</span>w) m)</span>
<span id="cb35-3"><a href="#cb35-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb35-4"><a href="#cb35-4" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> M.fromList [(<span class="fl">1.2</span>, setosa), (<span class="fl">0.6</span>, versicolor)] </span>
<span id="cb35-5"><a href="#cb35-5" aria-hidden="true" tabindex="-1"></a>      <span class="op">&amp;</span> measurements <span class="op">&gt;-</span> avgMeasurement <span class="op">.</span> <span class="fu">fmap</span> (<span class="fu">uncurry</span> scaleBy) <span class="op">.</span> M.toList</span>
<span id="cb35-6"><a href="#cb35-6" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> (<span class="dt">Flower</span> <span class="dt">Versicolor</span> (<span class="dt">Measurements</span> [<span class="fl">3.5</span>,<span class="fl">3.5</span>,<span class="fl">3.5</span>,<span class="fl">2.25</span>]))</span></code></pre></div>
<p>Running the aggregation with these scaling factors changed our result
and shows us what the average flower would be if we scaled each flower
by the amount provided in the input map.</p>
<p>This isn't a perfect example of what other containers could be used
for, but I'm sure folks will be dreaming up clever ideas in no time!</p>
<h2 id="other-aggregation-types">Other aggregation types</h2>
<p>Just as we can customize the container type and the aggregation
function we pass in we can also build algebraic lenses from any manor of
custom "classification" we want to perform. Let's write a new list-lens
which partitions the input values based on the result of the
aggregation. In essence classifying each point in our data-set as above
or below the result of the aggregation.</p>
<div class="sourceCode" id="cb36"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb36-1"><a href="#cb36-1" aria-hidden="true" tabindex="-1"></a><span class="ot">partitioned ::</span> <span class="kw">forall</span> f a<span class="op">.</span> (<span class="dt">Ord</span> a, <span class="dt">Foldable</span> f) <span class="ot">=&gt;</span> <span class="dt">AlgebraicLens</span> f a ([a], [a]) a a</span>
<span id="cb36-2"><a href="#cb36-2" aria-hidden="true" tabindex="-1"></a>partitioned <span class="ot">=</span> algebraic <span class="fu">id</span> splitter</span>
<span id="cb36-3"><a href="#cb36-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb36-4"><a href="#cb36-4" aria-hidden="true" tabindex="-1"></a><span class="ot">    splitter ::</span> f a <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> ([a], [a])</span>
<span id="cb36-5"><a href="#cb36-5" aria-hidden="true" tabindex="-1"></a>    splitter xs ref</span>
<span id="cb36-6"><a href="#cb36-6" aria-hidden="true" tabindex="-1"></a>      <span class="ot">=</span> (<span class="fu">filter</span> (<span class="op">&lt;</span> ref) (toList xs), <span class="fu">filter</span> (<span class="op">&gt;=</span> ref) (toList xs))</span></code></pre></div>
<p>It's completely fine for our <code>s</code> and <code>t</code> to be
completely disparate types like this.</p>
<p>This allows us to split a container of values into those which are
less than the aggregation, or greater/equal to it. We can use it with a
static value like this:</p>
<div class="sourceCode" id="cb37"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb37-1"><a href="#cb37-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> [<span class="dv">1</span><span class="op">..</span><span class="dv">10</span>] <span class="op">&amp;</span> partitioned <span class="op">?-</span> <span class="dv">5</span></span>
<span id="cb37-2"><a href="#cb37-2" aria-hidden="true" tabindex="-1"></a>([<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>],[<span class="dv">5</span>,<span class="dv">6</span>,<span class="dv">7</span>,<span class="dv">8</span>,<span class="dv">9</span>,<span class="dv">10</span>])</span></code></pre></div>
<p>Or we can provide our own aggregation function; let's say we want to
split it into values which are less than or greater than the
<strong>mean</strong> of the data-set. We'll use our modified version of
<code>&gt;-</code> for this:</p>
<div class="sourceCode" id="cb38"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb38-1"><a href="#cb38-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> mean [<span class="dv">3</span>, <span class="op">-</span><span class="dv">2</span>, <span class="dv">4</span>, <span class="dv">1</span>, <span class="fl">1.3</span>]</span>
<span id="cb38-2"><a href="#cb38-2" aria-hidden="true" tabindex="-1"></a><span class="fl">1.46</span></span>
<span id="cb38-3"><a href="#cb38-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb38-4"><a href="#cb38-4" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> [<span class="dv">3</span>, <span class="op">-</span><span class="dv">2</span>, <span class="dv">4</span>, <span class="dv">1</span>, <span class="fl">1.3</span>] <span class="op">&amp;</span> partitioned <span class="op">&gt;-</span> mean</span>
<span id="cb38-5"><a href="#cb38-5" aria-hidden="true" tabindex="-1"></a>([<span class="op">-</span><span class="fl">2.0</span>,<span class="fl">1.0</span>,<span class="fl">1.3</span>], [<span class="fl">3.0</span>,<span class="fl">4.0</span>])</span></code></pre></div>
<p>Here's a list-lens which generalizes the idea behind
<code>minimumBy</code>, <code>maximumBy</code>, etc. into an optic. We
allow the user to provide a selection function for indicating the
element they want, then the optic itself will pluck the appropriate
element out of the collection.</p>
<div class="sourceCode" id="cb39"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb39-1"><a href="#cb39-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- Run an aggregation on the first elements of the tuples</span></span>
<span id="cb39-2"><a href="#cb39-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- Select the second tuple element which is paired with the value</span></span>
<span id="cb39-3"><a href="#cb39-3" aria-hidden="true" tabindex="-1"></a><span class="co">-- equal to the aggregation result.</span></span>
<span id="cb39-4"><a href="#cb39-4" aria-hidden="true" tabindex="-1"></a><span class="ot">onFirst ::</span> (<span class="dt">Foldable</span> f, <span class="dt">Eq</span> a) <span class="ot">=&gt;</span> <span class="dt">AlgebraicLens</span> f (a, b) (<span class="dt">Maybe</span> b) a a</span>
<span id="cb39-5"><a href="#cb39-5" aria-hidden="true" tabindex="-1"></a>onFirst <span class="ot">=</span> algebraic <span class="fu">fst</span> picker</span>
<span id="cb39-6"><a href="#cb39-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb39-7"><a href="#cb39-7" aria-hidden="true" tabindex="-1"></a>    picker xs a <span class="ot">=</span> <span class="fu">lookup</span> a <span class="op">$</span> toList xs</span>
<span id="cb39-8"><a href="#cb39-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-9"><a href="#cb39-9" aria-hidden="true" tabindex="-1"></a><span class="co">-- Get the character paired with the smallest number</span></span>
<span id="cb39-10"><a href="#cb39-10" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> [(<span class="dv">3</span>, <span class="ch">&#39;a&#39;</span>), (<span class="dv">10</span>, <span class="ch">&#39;b&#39;</span>), (<span class="dv">2</span>, <span class="ch">&#39;c&#39;</span>)] <span class="op">&amp;</span> onFirst <span class="op">&gt;-</span> <span class="fu">minimum</span></span>
<span id="cb39-11"><a href="#cb39-11" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> <span class="ch">&#39;c&#39;</span></span>
<span id="cb39-12"><a href="#cb39-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-13"><a href="#cb39-13" aria-hidden="true" tabindex="-1"></a><span class="co">-- Get the character paired with the largest number</span></span>
<span id="cb39-14"><a href="#cb39-14" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> [(<span class="dv">3</span>, <span class="ch">&#39;a&#39;</span>), (<span class="dv">10</span>, <span class="ch">&#39;b&#39;</span>), (<span class="dv">2</span>, <span class="ch">&#39;c&#39;</span>)] <span class="op">&amp;</span> onFirst <span class="op">&gt;-</span> <span class="fu">maximum</span></span>
<span id="cb39-15"><a href="#cb39-15" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> <span class="ch">&#39;b&#39;</span></span>
<span id="cb39-16"><a href="#cb39-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-17"><a href="#cb39-17" aria-hidden="true" tabindex="-1"></a><span class="co">-- Get the character paired with the first even number</span></span>
<span id="cb39-18"><a href="#cb39-18" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> [(<span class="dv">3</span>, <span class="ch">&#39;a&#39;</span>), (<span class="dv">10</span>, <span class="ch">&#39;b&#39;</span>), (<span class="dv">2</span>, <span class="ch">&#39;c&#39;</span>)] <span class="op">&amp;</span> onFirst <span class="op">&gt;-</span> <span class="fu">head</span> <span class="op">.</span> <span class="fu">filter</span> <span class="fu">even</span></span>
<span id="cb39-19"><a href="#cb39-19" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> <span class="ch">&#39;b&#39;</span></span></code></pre></div>
<p>If our structure is indexable we can do this much more generally and
build a library of composable optics which dig deeply into structures
and perform selection aggregations over anything we want. It may take a
little work to figure out the cleanest set of combinators, but here's a
simplified example of just how easy it is to start messing around
with:</p>
<div class="sourceCode" id="cb40"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb40-1"><a href="#cb40-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- Pick some substate or projection from each value,</span></span>
<span id="cb40-2"><a href="#cb40-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- The aggregation selects the index of one of these projections and returns it</span></span>
<span id="cb40-3"><a href="#cb40-3" aria-hidden="true" tabindex="-1"></a><span class="co">-- Return the &#39;original state&#39; that lives at the chosen index</span></span>
<span id="cb40-4"><a href="#cb40-4" aria-hidden="true" tabindex="-1"></a><span class="ot">selectingOn ::</span> (s <span class="ot">-&gt;</span> a) <span class="ot">-&gt;</span> <span class="dt">AlgebraicLens</span> [] s (<span class="dt">Maybe</span> s) a (<span class="dt">Maybe</span> <span class="dt">Int</span>)</span>
<span id="cb40-5"><a href="#cb40-5" aria-hidden="true" tabindex="-1"></a>selectingOn project <span class="ot">=</span> algebraic project picker</span>
<span id="cb40-6"><a href="#cb40-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb40-7"><a href="#cb40-7" aria-hidden="true" tabindex="-1"></a>    picker xs i <span class="ot">=</span> (xs <span class="op">!!</span>) <span class="op">&lt;$&gt;</span> i</span>
<span id="cb40-8"><a href="#cb40-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-9"><a href="#cb40-9" aria-hidden="true" tabindex="-1"></a><span class="co">-- Use the `Eq` class and return the index of the aggregation result in the original list</span></span>
<span id="cb40-10"><a href="#cb40-10" aria-hidden="true" tabindex="-1"></a><span class="ot">indexOf ::</span> <span class="dt">Eq</span> s <span class="ot">=&gt;</span> <span class="dt">AlgebraicLens</span> [] s (<span class="dt">Maybe</span> <span class="dt">Int</span>) s s</span>
<span id="cb40-11"><a href="#cb40-11" aria-hidden="true" tabindex="-1"></a>indexOf <span class="ot">=</span> algebraic <span class="fu">id</span> (<span class="fu">flip</span> elemIndex)</span>
<span id="cb40-12"><a href="#cb40-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-13"><a href="#cb40-13" aria-hidden="true" tabindex="-1"></a><span class="co">-- Project each string into its length, </span></span>
<span id="cb40-14"><a href="#cb40-14" aria-hidden="true" tabindex="-1"></a><span class="co">-- then select the index of the string with length 11,</span></span>
<span id="cb40-15"><a href="#cb40-15" aria-hidden="true" tabindex="-1"></a><span class="co">-- Then find and return the element at that index</span></span>
<span id="cb40-16"><a href="#cb40-16" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> [<span class="st">&quot;banana&quot;</span>, <span class="st">&quot;pomegranate&quot;</span>, <span class="st">&quot;watermelon&quot;</span>] </span>
<span id="cb40-17"><a href="#cb40-17" aria-hidden="true" tabindex="-1"></a>      <span class="op">&amp;</span> selectingOn <span class="fu">length</span> <span class="op">.</span> indexOf <span class="op">?-</span> <span class="dv">11</span></span>
<span id="cb40-18"><a href="#cb40-18" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> <span class="st">&quot;pomegranate&quot;</span></span>
<span id="cb40-19"><a href="#cb40-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-20"><a href="#cb40-20" aria-hidden="true" tabindex="-1"></a><span class="co">-- We can can still use a custom aggregation function,</span></span>
<span id="cb40-21"><a href="#cb40-21" aria-hidden="true" tabindex="-1"></a><span class="co">-- This gets the string of the shortest length. </span></span>
<span id="cb40-22"><a href="#cb40-22" aria-hidden="true" tabindex="-1"></a><span class="co">-- Note we didn&#39;t need to change our chain of optics at all!</span></span>
<span id="cb40-23"><a href="#cb40-23" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> [<span class="st">&quot;banana&quot;</span>, <span class="st">&quot;pomegranate&quot;</span>, <span class="st">&quot;watermelon&quot;</span>] </span>
<span id="cb40-24"><a href="#cb40-24" aria-hidden="true" tabindex="-1"></a>      <span class="op">&amp;</span> selectingOn <span class="fu">length</span> <span class="op">.</span> indexOf <span class="op">&gt;-</span> <span class="fu">minimum</span></span>
<span id="cb40-25"><a href="#cb40-25" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> <span class="st">&quot;banana&quot;</span></span></code></pre></div>
<p>I'm sure you can already imagine all sorts of different applications
for this sort of thing. It may seem more awkward than the
straight-forward Haskell way of doing these things, but it's a brand new
idea, it'll take time for the ecosystem to grow around it and for us to
figure out the "best way".</p>
<h2 id="summarizing-algebraic-lenses">Summarizing Algebraic Lenses</h2>
<p>The examples we've looked at here are just a few of many possible
ways we can use Algebraic lenses! Remember that we can generalize the
<code>f</code> container into almost anything! We can use Maps, Lists,
we could even use a function as the container! In addition we can use
any sort of function in place of the classifier, there's no requirement
that it has to return the same type as its input. Algebraic lenses allow
us to compose lenses which focus on a specific portion of state, run a
comparison or aggregation there (e.g. get the maximum or minimum element
from the collection based on some property), then zoom back out and
select the larger element which contains the minimum/maximum
substate!</p>
<p>This means we can embed operations like <code>minimumBy</code>,
<code>findBy</code>, <code>elemIndex</code> and friends as composable
optics! There are many other interesting aggregations to be found in
statistics, linear algebra, and normal day-to-day tasks. I'm very
excited to see where this ends up going, there are a ton of
possibilities which I haven't begun to think about yet.</p>
<p>Algebraic lenses also tend to compose better with Grate-like optics
than traditional <code>Strong Profunctor</code> based lenses, they work
well with getters and folds, and can be used with setters or traversals
for setting or traversing (but not aggregating). They play a role in the
ecosystem and are just one puzzle piece in the world of optics we're
still discovering.</p>
<p>Thanks for reading! We'll dig into Kaleidoscopes soon, so stay
tuned!</p>
<h2 id="updates--edits">Updates &amp; Edits</h2>
<p>After releasing this some authors of the paper pointed out some
helpful notes (thanks Bryce and Mario!)</p>
<p>It turns out that we can further generalize the
<code>Algebraic</code> class further while maintaining its strength.</p>
<p>The suggested model for this is to specify profunctors which are
Strong with respect to Monoids. To understand the meaning of this, let's
take a look at the original Strong typeclass:</p>
<div class="sourceCode" id="cb41"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb41-1"><a href="#cb41-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Profunctor</span> p <span class="ot">=&gt;</span> <span class="dt">Strong</span> p <span class="kw">where</span></span>
<span id="cb41-2"><a href="#cb41-2" aria-hidden="true" tabindex="-1"></a><span class="ot">  first&#39; ::</span> p a b <span class="ot">-&gt;</span> p (a, c) (b, c)</span>
<span id="cb41-3"><a href="#cb41-3" aria-hidden="true" tabindex="-1"></a><span class="ot">  second&#39; ::</span> p a b <span class="ot">-&gt;</span> p (c, a) (c, b)</span></code></pre></div>
<p>The idea is that a Strong profunctor can allow additional values to
be passed through freely. We can restrict this idea slightly by
requiring the value which we're passing through to be a Monoid:</p>
<div class="sourceCode" id="cb42"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb42-1"><a href="#cb42-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Profunctor</span> p <span class="ot">=&gt;</span> <span class="dt">MStrong</span> p <span class="kw">where</span></span>
<span id="cb42-2"><a href="#cb42-2" aria-hidden="true" tabindex="-1"></a><span class="ot">  mfirst&#39; ::</span>  <span class="dt">Monoid</span> m <span class="ot">=&gt;</span> p a b <span class="ot">-&gt;</span> p (a, m) (b, m)</span>
<span id="cb42-3"><a href="#cb42-3" aria-hidden="true" tabindex="-1"></a>  mfirst&#39; <span class="ot">=</span> dimap swap swap <span class="op">.</span> msecond&#39;</span>
<span id="cb42-4"><a href="#cb42-4" aria-hidden="true" tabindex="-1"></a><span class="ot">  msecond&#39; ::</span>  <span class="dt">Monoid</span> m <span class="ot">=&gt;</span> p a b <span class="ot">-&gt;</span> p (m, a) (m, b)</span>
<span id="cb42-5"><a href="#cb42-5" aria-hidden="true" tabindex="-1"></a>  msecond&#39; <span class="ot">=</span> dimap swap swap <span class="op">.</span> mfirst&#39;</span>
<span id="cb42-6"><a href="#cb42-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb42-7"><a href="#cb42-7" aria-hidden="true" tabindex="-1"></a>  <span class="ot">{-# MINIMAL mfirst&#39; | msecond&#39; #-}</span></span></code></pre></div>
<p>This gives us more power when writing instances, we can "summon" a
<code>c</code> from nowhere via <code>mempty</code> if needed, but can
also combine multiple <code>c</code>'s together via <code>mappend</code>
if needed. Let's write all the needed instances of our new class:</p>
<div class="sourceCode" id="cb43"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb43-1"><a href="#cb43-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">MStrong</span> (<span class="dt">Forget</span> r) <span class="kw">where</span></span>
<span id="cb43-2"><a href="#cb43-2" aria-hidden="true" tabindex="-1"></a>  msecond&#39; <span class="ot">=</span> second&#39;</span>
<span id="cb43-3"><a href="#cb43-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb43-4"><a href="#cb43-4" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">MStrong</span> (<span class="ot">-&gt;</span>) <span class="kw">where</span></span>
<span id="cb43-5"><a href="#cb43-5" aria-hidden="true" tabindex="-1"></a>  msecond&#39; <span class="ot">=</span> second&#39;</span>
<span id="cb43-6"><a href="#cb43-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb43-7"><a href="#cb43-7" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">MStrong</span> <span class="dt">Tagged</span> <span class="kw">where</span></span>
<span id="cb43-8"><a href="#cb43-8" aria-hidden="true" tabindex="-1"></a>  msecond&#39; (<span class="dt">Tagged</span> b) <span class="ot">=</span> <span class="dt">Tagged</span> (<span class="fu">mempty</span>, b)</span>
<span id="cb43-9"><a href="#cb43-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb43-10"><a href="#cb43-10" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Traversable</span> f <span class="ot">=&gt;</span> <span class="dt">MStrong</span> (<span class="dt">Costar</span> f) <span class="kw">where</span></span>
<span id="cb43-11"><a href="#cb43-11" aria-hidden="true" tabindex="-1"></a>  msecond&#39; (<span class="dt">Costar</span> f) <span class="ot">=</span> <span class="dt">Costar</span> (go f)</span>
<span id="cb43-12"><a href="#cb43-12" aria-hidden="true" tabindex="-1"></a>    <span class="kw">where</span></span>
<span id="cb43-13"><a href="#cb43-13" aria-hidden="true" tabindex="-1"></a>      go f fma <span class="ot">=</span> f <span class="op">&lt;$&gt;</span> <span class="fu">sequenceA</span> fma</span></code></pre></div>
<p>The first two instances simply rely on Strong, all Strong profunctors
are trivially <code>MStrong</code> in this manner. To put it
differently, <code>MStrong</code> is superclass of <code>Strong</code>
(although this isn't reflected in libraries at the moment). I won't
bother writing out all the other trivial instances, just know that all
Strong profunctors have an instance.</p>
<p><code>Tagged</code> and <code>Costar</code> are NOT
<code>Strong</code> profunctors, but by taking advantage of the Monoid
we can come up with suitable instances here! We use <code>mempty</code>
to pull a value from thin air for <code>Tagged</code>, and
<code>Costar</code> uses the <code>Applicative</code> instance of
<code>Monoid m =&gt; (m, a)</code> to sequence its input into the right
shape.</p>
<p>Indeed, this appears to be a more general construction, but at first
glance it seems to be orthogonal; how can we regain our
<code>algebraic</code> function using only the <code>MStrong</code>
constraint?</p>
<div class="sourceCode" id="cb44"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb44-1"><a href="#cb44-1" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Arrow</span> ((&amp;&amp;&amp;))</span>
<span id="cb44-2"><a href="#cb44-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-3"><a href="#cb44-3" aria-hidden="true" tabindex="-1"></a><span class="ot">algebraic ::</span> <span class="kw">forall</span> m p s t a b</span>
<span id="cb44-4"><a href="#cb44-4" aria-hidden="true" tabindex="-1"></a>           <span class="op">.</span> (<span class="dt">Monoid</span> m,  <span class="dt">MStrong</span> p) </span>
<span id="cb44-5"><a href="#cb44-5" aria-hidden="true" tabindex="-1"></a>           <span class="ot">=&gt;</span> (s <span class="ot">-&gt;</span> m) </span>
<span id="cb44-6"><a href="#cb44-6" aria-hidden="true" tabindex="-1"></a>           <span class="ot">-&gt;</span> (s <span class="ot">-&gt;</span> a) </span>
<span id="cb44-7"><a href="#cb44-7" aria-hidden="true" tabindex="-1"></a>           <span class="ot">-&gt;</span> (m <span class="ot">-&gt;</span> b <span class="ot">-&gt;</span> t) </span>
<span id="cb44-8"><a href="#cb44-8" aria-hidden="true" tabindex="-1"></a>           <span class="ot">-&gt;</span> <span class="dt">Optic</span> p s t a b</span>
<span id="cb44-9"><a href="#cb44-9" aria-hidden="true" tabindex="-1"></a>algebraic inject project flatten p</span>
<span id="cb44-10"><a href="#cb44-10" aria-hidden="true" tabindex="-1"></a>  <span class="ot">=</span> dimap (inject <span class="op">&amp;&amp;&amp;</span> <span class="fu">id</span>)  (<span class="fu">uncurry</span> flatten) <span class="op">$</span>  strengthened</span>
<span id="cb44-11"><a href="#cb44-11" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb44-12"><a href="#cb44-12" aria-hidden="true" tabindex="-1"></a><span class="ot">    strengthened ::</span> p (m, s) (m, b)</span>
<span id="cb44-13"><a href="#cb44-13" aria-hidden="true" tabindex="-1"></a>    strengthened <span class="ot">=</span> msecond&#39; (lmap project p)</span></code></pre></div>
<p>This is perhaps not the most elegant definition, but it matches the
type without doing anything outright stupid, so I suppose it will do
(type-hole driven development FTW)!</p>
<p>We require from the user a function which injects the state into a
Monoid, then use <code>MStrong</code> to project that monoid through the
profunctor's action. On the other side we use the result of the
computation alongside the Monoidal summary of the input value(s) to
compute the final aggregation.</p>
<p>We can recover our standard list-lens operations by simply choosing
<code>[s]</code> to be our Monoid.</p>
<div class="sourceCode" id="cb45"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb45-1"><a href="#cb45-1" aria-hidden="true" tabindex="-1"></a><span class="ot">listLens ::</span> <span class="dt">MStrong</span> p <span class="ot">=&gt;</span> (s <span class="ot">-&gt;</span> a) <span class="ot">-&gt;</span> ([s] <span class="ot">-&gt;</span> b <span class="ot">-&gt;</span> t) <span class="ot">-&gt;</span> <span class="dt">Optic</span> p s t a b</span>
<span id="cb45-2"><a href="#cb45-2" aria-hidden="true" tabindex="-1"></a>listLens <span class="ot">=</span> algebraic <span class="fu">pure</span></span></code></pre></div>
<p>In fact, we can easily generalize over any Alternative container.
Alternative's provide a Monoid over their Applicative structure, and we
can use the <code>Alt</code> newtype wrapper from
<code>Data.Monoid</code> to use an Alternative structure as a
<code>Monoid</code>.</p>
<div class="sourceCode" id="cb46"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb46-1"><a href="#cb46-1" aria-hidden="true" tabindex="-1"></a><span class="ot">altLens ::</span> (<span class="dt">Alternative</span> f, <span class="dt">MStrong</span> p) </span>
<span id="cb46-2"><a href="#cb46-2" aria-hidden="true" tabindex="-1"></a>        <span class="ot">=&gt;</span> (s <span class="ot">-&gt;</span> a) <span class="ot">-&gt;</span> (f s <span class="ot">-&gt;</span> b <span class="ot">-&gt;</span> t) <span class="ot">-&gt;</span> <span class="dt">Optic</span> p s t a b</span>
<span id="cb46-3"><a href="#cb46-3" aria-hidden="true" tabindex="-1"></a>altLens project flatten <span class="ot">=</span> malgebraic (<span class="dt">Alt</span> <span class="op">.</span> <span class="fu">pure</span>)  project (flatten <span class="op">.</span> getAlt)</span></code></pre></div>
<p>So now we've got a fully general algebraic lens which allows
aggregating over any monoidal projection of input, including helpers for
doing this over Alternative structures, or lists in particular! This
gives us a significant amount of flexibility and power.</p>
<p>I won't waste everyone's time by testing these new operations here,
take heart that they do indeed work the same as the original definitions
provided above.</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Advent of Optics: Day 4</title>
      <link href="https://chrispenner.ca/posts/advent-of-optics-04"/>
      <id>https://chrispenner.ca/posts/advent-of-optics-04</id>
      <updated>2019-12-04T00:00:00Z</updated>
      <summary>Day 4 of Advent of Code solved with optics</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/pinecones.jpg" alt="Advent of Optics: Day 4">
              <p>Since I'm releasing <a href="https://leanpub.com/optics-by-example">a
book on practical lenses and optics</a> later this month I thought it
would be fun to do a few of this year's Advent of Code puzzles using as
many obscure optics features as possible!</p>
<p>To be clear, the goal is to be obscure, strange and excessive towards
the goal of using as many optics as possible in a given solution, even
if it's awkward, silly, or just plain overkill. These are NOT idiomatic
Haskell solutions, nor are they intended to be. Maybe we'll both learn
something along the way. Let's have some fun!</p>
<p>You can find today's puzzle <a
href="https://adventofcode.com/2019/day/4">here</a>.</p>
<hr />
<p>Hey folks! Today's is a nice clean one! The goal is to find all the
numbers within a given range which pass a series of predicates! The
conditions each number has to match include:</p>
<ul>
<li>Should be within the range; my range is
<code>307237-769058</code></li>
<li>Should be six digits long; my range includes only 6 digit numbers,
so we're all set here</li>
<li>Two adjacent digits in the number should be the same (e.g.
'223456')</li>
<li>The digits should be in monotonically increasing order (e.g.
increase or stay the same from left to right)</li>
</ul>
<p>And that's it!</p>
<p>In normal Haskell we'd make a list of all possibilities, then either
chain a series of <code>filter</code> statements or use
<code>do-notation</code> with guards to narrow it down. Luckily, folds
have filters too!</p>
<p>First things first, since our checks have us analyzing the actual
discrete digits we'll convert our Int to a String so we can talk about
them as characters:</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>main <span class="ot">=</span> ([<span class="dv">307237</span><span class="op">..</span><span class="dv">769058</span>]<span class="ot"> ::</span> [<span class="dt">Int</span>])</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>        <span class="op">&amp;</span> toListOf (traversed <span class="op">.</span> re _Show)</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>        <span class="op">&amp;</span> <span class="fu">print</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="op">&gt;&gt;&gt;</span> main</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>[<span class="st">&quot;307237&quot;</span>,<span class="st">&quot;307238&quot;</span>,<span class="st">&quot;307239&quot;</span>,<span class="st">&quot;307240&quot;</span>,<span class="st">&quot;307241&quot;</span>,<span class="st">&quot;307242&quot;</span>,<span class="st">&quot;307243&quot;</span>,<span class="st">&quot;307244&quot;</span>,<span class="st">&quot;307245&quot;</span>,</span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;307246&quot;</span>, <span class="op">...</span>]</span></code></pre></div>
<p><code>_Show</code> is the same prism we've used for parsing in the
previous examples, but <code>re</code> flips it in reverse and generates
a <code>Getter</code> which calls <code>show</code>! This is equivalent
to <code>to show</code>, but will get you an extra 20 optics
points...</p>
<p>Now let's start adding filters! We'll start by checking that the
digits are all ascending. I could write some convoluted fold which does
this, but the quick and dirty way is simply to sort the digits
lexicographically and see if the ordering changed at all:</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">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> ([<span class="dv">307237</span><span class="op">..</span><span class="dv">769058</span>]<span class="ot"> ::</span> [<span class="dt">Int</span>])</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>        <span class="op">&amp;</span> toListOf (traversed <span class="op">.</span> re _Show</span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>                    <span class="op">.</span> filtered (\s <span class="ot">-&gt;</span> s <span class="op">==</span> <span class="fu">sort</span> s)</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>                   )</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>        <span class="op">&amp;</span> <span class="fu">print</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> main</span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>[<span class="st">&quot;333333&quot;</span>,<span class="st">&quot;333334&quot;</span>,<span class="st">&quot;333335&quot;</span>,<span class="st">&quot;333336&quot;</span>,<span class="st">&quot;333337&quot;</span>,<span class="st">&quot;333338&quot;</span>,<span class="op">...</span>]</span></code></pre></div>
<p><code>filtered</code> removes any focuses from the fold which don't
match the predicate.</p>
<p>We can already see this filters out a ton of possibilities. Not done
yet though; we need to ensure there's at least one double consecutive
digit. I'll reach for my favourite hammer:
<code>lens-regex-pcre</code>:</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">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> ([<span class="dv">307237</span><span class="op">..</span><span class="dv">769058</span>]<span class="ot"> ::</span> [<span class="dt">Int</span>])</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>        <span class="op">&amp;</span> toListOf (traversed <span class="op">.</span> re _Show</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>                    <span class="op">.</span> filtered (\s <span class="ot">-&gt;</span> s <span class="op">==</span> <span class="fu">sort</span> s)</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>                    <span class="op">.</span> filteredBy (packed <span class="op">.</span> [regex|(\d)\1+|])</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>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> main </span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a>[<span class="st">&quot;333333&quot;</span>,<span class="st">&quot;333334&quot;</span>,<span class="st">&quot;333335&quot;</span>,<span class="st">&quot;333336&quot;</span>,<span class="st">&quot;333337&quot;</span>,<span class="st">&quot;333338&quot;</span>,<span class="op">...</span>]</span></code></pre></div>
<p>Unfortunately we don't really see much difference in the first few
options, but trust me, it did something. Let's see how it works:</p>
<p>I'm using <code>filteredBy</code> here instead of
<code>filtered</code>, <code>filteredBy</code> is brand new in
<code>lens &gt;= 4.18</code>, so make sure you've got the latest version
if you want to try this out. It's like <code>filtered</code>, but takes
a Fold instead of a predicate. <code>filteredBy</code> will run the fold
on the current element, and will filter out any focuses for which the
fold yields no results.</p>
<p>The fold I'm passing in converts the String to a <code>Text</code>
using <code>packed</code>, then runs a regex which matches any digit,
then requires at least one more of that digit to be next in the string.
Since <code>regex</code> only yields matches, if no matches are found
the candidate will be filtered out.</p>
<p>That's all the criteria! Now we've got a list of all of them, but all
we really need is the count of them, so we'll switch from
<code>toListOf</code> to <code>lengthOf</code>:</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">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> ([<span class="dv">307237</span><span class="op">..</span><span class="dv">769058</span>]<span class="ot"> ::</span> [<span class="dt">Int</span>])</span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>        <span class="op">&amp;</span> lengthOf ( traversed <span class="op">.</span> re _Show</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>                   <span class="op">.</span> filtered (\s <span class="ot">-&gt;</span> s <span class="op">==</span> <span class="fu">sort</span> s)</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>                   <span class="op">.</span> filteredBy (packed <span class="op">.</span> [regex|(\d)\1+|])</span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>                   )</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>        <span class="op">&amp;</span> <span class="fu">print</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="op">&gt;&gt;&gt;</span> main</span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a><span class="dv">889</span></span></code></pre></div>
<p>That's the right answer, not bad!</p>
<h2 id="part-2">Part 2</h2>
<p>Part 2 only adds one more condition:</p>
<ul>
<li>The number must have a group of exactly 2 consecutive numbers, e.g.
<code>333</code> is no good, but <code>33322</code> is fine.</li>
</ul>
<p>Currently we're just checking that it has at least two consecutive
numbers, but we'll need to be smarter to check for groups of exactly 2.
Luckily, it's not too tricky.</p>
<p>The <code>regex</code> traversal finds ALL non-overlapping matches
within a given piece of text, and the <code>+</code> modifier is greedy,
so we know that for a given string <code>33322</code> our current
pattern will find the matches: <code>["333", "22"]</code>. After that
it's easy enough to just check that we have at least one match of length
2!</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">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> ([<span class="dv">307237</span><span class="op">..</span><span class="dv">769058</span>]<span class="ot"> ::</span> [<span class="dt">Int</span>])</span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>        <span class="op">&amp;</span> lengthOf (traversed <span class="op">.</span> re _Show</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>                   <span class="op">.</span> filtered (\s <span class="ot">-&gt;</span> s <span class="op">==</span> <span class="fu">sort</span> s)</span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>                   <span class="op">.</span> filteredBy (packed <span class="op">.</span> [regex|(\d)\1+|] <span class="op">.</span> match <span class="op">.</span> to T.length <span class="op">.</span> only <span class="dv">2</span>)</span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a>                   )</span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>        <span class="op">&amp;</span> <span class="fu">print</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> main</span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a><span class="dv">589</span></span></code></pre></div>
<p>I just get the match text, get its length, then use
<code>only 2</code> to filter down to only lengths of 2.
<code>filteredBy</code> will detect whether any of the matches make it
through the whole fold and kick out any numbers that don't have a group
of exactly 2 consecutive numbers.</p>
<p>That's it for today! Hopefully tomorrow's is just as optical! 🤞</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Advent of Optics: Day 3</title>
      <link href="https://chrispenner.ca/posts/advent-of-optics-03"/>
      <id>https://chrispenner.ca/posts/advent-of-optics-03</id>
      <updated>2019-12-03T00:00:00Z</updated>
      <summary>Day 3 of Advent of Code solved with optics</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/pinecones.jpg" alt="Advent of Optics: Day 3">
              <p>Since I'm releasing <a href="https://leanpub.com/optics-by-example">a
book on practical lenses and optics</a> later this month I thought it
would be fun to do a few of this year's Advent of Code puzzles using as
many obscure optics features as possible!</p>
<p>To be clear, the goal is to be obscure, strange and excessive towards
the goal of using as many optics as possible in a given solution, even
if it's awkward, silly, or just plain overkill. These are NOT idiomatic
Haskell solutions, nor are they intended to be. Maybe we'll both learn
something along the way. Let's have some fun!</p>
<p>You can find today's puzzle <a
href="https://adventofcode.com/2019/day/3">here</a>.</p>
<hr />
<p>Today's didn't really have any phenomenal optics insights, but I did
learn about some handy types and instances for handling points in space,
so we'll run through it anyways and see if we can have some fun! You
know the drill by now so I'll jump right in.</p>
<p>Sorry, this one's a bit rushed and messy, turns out writing a blog
post every day is pretty time consuming.</p>
<p>We've got two sets of instructions, each representing paths of wires,
and we need to find out <strong>where</strong> in the space they cross,
then determine the distances of those points from the origin.</p>
<p>We'll start as always with parsing in the input! They made it a bit
harder on us this time, but it's certainly nothing that
<code>lens-regex-pcre</code> can't handle. Before we try parsing out the
individual instructions we need to split our instruction sets into one
for each wire! I'll just use the <code>lines</code> function to split
the file in two:</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">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>    TIO.readFile <span class="st">&quot;./src/Y2019/day03.txt&quot;</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>               <span class="op">&lt;&amp;&gt;</span> T.lines</span></code></pre></div>
<p>I'm using that handy <code>&lt;&amp;&gt;</code> pipelining operator,
which basically allows me to pass the contents of a monadic action
through a bunch of operations. It just so happens that
<code>&gt;&gt;=</code> has the right precedence to tack it on the
end!</p>
<p>Now we've got a list of two <code>Text</code>s, with a path in
each!</p>
<p>Keeping a list of the two elements is fine of course, but since this
is a post about optics and obfuscation, we'll pack them into a tuple
just for fun:</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>    TIO.readFile <span class="st">&quot;./src/Y2019/day03.txt&quot;</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>               <span class="op">&lt;&amp;&gt;</span> T.lines</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>               <span class="op">&lt;&amp;&gt;</span> traverseOf both view (ix <span class="dv">0</span>, ix <span class="dv">1</span>)</span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>               <span class="op">&gt;&gt;=</span> <span class="fu">print</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> main</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>(<span class="st">&quot;R999,U626,R854,D200,R696,...&quot;</span>, <span class="st">&quot;D424,L846,U429,L632,U122,...&quot;</span>)</span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> </span></code></pre></div>
<p>This is a fun (and useless) trick! If you look closely, we're
actually applying <code>traverseOf</code> to all of its arguments! What
we're doing is applying <code>view</code> to each traversal (i.e.
<code>ix 0</code>), which creates a <strong>function</strong> over our
list of wire texts. <code>traverseOf</code> then sequences the
<strong>function</strong> as the effect and returns a new function:
<code>[Text] -&gt; (Text, Text)</code> which is pretty cool! When we
pass in the list of wires this is applied and we get the tuple we want
to pass forwards. We're using <code>view</code> on a traversal here, but
it's all good because <code>Text</code> is a Monoid. This of course
means that if the input doesn't have at least two lines of input that
we'll continue on silently without any errors... but there aren't a lot
of adrenaline pumping thrills in software development so I guess I'll
take them where I can get them. We'll just trust that the input is good.
We could use <code>singular</code> or even <code>preview</code> to be
<em>safer</em> if we wanted, but ain't nobody got time for that in a
post about crazy hacks!</p>
<p>Okay! Next step is to figure out the crazy path that these wires are
taking. To do that we'll need to parse the paths into some sort of
pseudo-useful form. I'm going to reach for <code>lens-regex-pcre</code>
again, at least to find each instruction. We want to run this over
<strong>both</strong> sides of our tuple though, so we'll add a quick
incantation for that as well</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">import</span> <span class="dt">Linear</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="ot">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>    TIO.readFile <span class="st">&quot;./src/Y2019/day03.txt&quot;</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>               <span class="op">&lt;&amp;&gt;</span> T.lines</span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>               <span class="op">&lt;&amp;&gt;</span> traverseOf both view (ix <span class="dv">0</span>, ix <span class="dv">1</span>)</span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>               <span class="op">&lt;&amp;&gt;</span> both <span class="op">%~</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a>                     (   toListOf ([regex|\w\d+|] <span class="op">.</span> match <span class="op">.</span> unpacked <span class="op">.</span> _Cons <span class="op">.</span> to parseInput)</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="ot">parseInput ::</span> (<span class="dt">Char</span>, <span class="dt">String</span>) <span class="ot">-&gt;</span> (<span class="dt">Int</span>, <span class="dt">V2</span> <span class="dt">Int</span>)</span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a>parseInput (d, n) <span class="ot">=</span> (,) (<span class="fu">read</span> n) <span class="op">$</span> <span class="kw">case</span> d <span class="kw">of</span></span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a>    <span class="ch">&#39;U&#39;</span> <span class="ot">-&gt;</span> <span class="dt">V2</span> <span class="dv">0</span> (<span class="op">-</span><span class="dv">1</span>)</span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a>    <span class="ch">&#39;D&#39;</span> <span class="ot">-&gt;</span> <span class="dt">V2</span> <span class="dv">0</span> <span class="dv">1</span></span>
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true" tabindex="-1"></a>    <span class="ch">&#39;L&#39;</span> <span class="ot">-&gt;</span> <span class="dt">V2</span> (<span class="op">-</span><span class="dv">1</span>) <span class="dv">0</span></span>
<span id="cb3-16"><a href="#cb3-16" aria-hidden="true" tabindex="-1"></a>    <span class="ch">&#39;R&#39;</span> <span class="ot">-&gt;</span> <span class="dt">V2</span> <span class="dv">1</span> <span class="dv">0</span></span>
<span id="cb3-17"><a href="#cb3-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-18"><a href="#cb3-18" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> main</span>
<span id="cb3-19"><a href="#cb3-19" aria-hidden="true" tabindex="-1"></a>([(<span class="dv">999</span>,<span class="dt">V2</span> <span class="dv">1</span> <span class="dv">0</span>),(<span class="dv">626</span>,<span class="dt">V2</span> <span class="dv">0</span> (<span class="op">-</span><span class="dv">1</span>)),<span class="op">...</span>], [(<span class="dv">854</span>,<span class="dt">V2</span> <span class="dv">1</span> <span class="dv">0</span>),(<span class="dv">200</span>,<span class="dt">V2</span> <span class="dv">0</span> <span class="dv">1</span>),<span class="op">...</span>]</span></code></pre></div>
<p>Okay, there's a lot happening here, first I use the simple regex
<code>\w\d+</code> to find each "instruction", then grab the full match
as <code>Text</code>.</p>
<p>Next in line I <code>unpack</code> it into a <code>String</code>
since I'll need to use <code>Read</code> to parse the
<code>Int</code>s.</p>
<p>After that I use the <code>_Cons</code> prism to split the string
into its first char and the rest, which happens to get us the direction
and the distance to travel respectively.</p>
<p>Then I run <code>parseInput</code> which converts the String into an
Int with <code>read</code>, and converts the cardinal direction into a
vector equivalent of that direction. This is going to come in handy soon
I promise. I'm using <code>V2</code> from the <code>linear</code>
package for my vectors here.</p>
<p>Okay, so now we've parsed a list of instructions, but we need some
way to determine where the wires intersect! The simplest possible way to
do that is just to enumerate every single point that each wire passes
through and see which ones they have in common; simple is good enough
for me!</p>
<p>Okay here's the clever bit, the way we've organized our directions is
going to come in handy, I'm going to create <code>n</code> copies of
each vector in our stream so we effectively have a single instruction
for each movement we'll make!</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>(toListOf ([regex|\w\d+|] <span class="op">.</span> match <span class="op">.</span> unpacked <span class="op">.</span> _Cons <span class="op">.</span> to parseInput <span class="op">.</span> folding (<span class="fu">uncurry</span> <span class="fu">replicate</span>))</span></code></pre></div>
<p><code>uncurry</code> will make <code>replicate</code> into the
function: <code>replicate :: (Int, V2 Int) -&gt; [V2 Int]</code>, and
<code>folding</code> will run that function, then flatten out the list
into the focus of the fold. Ultimately this gives us just a huge list of
unit vectors like this:</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="dt">V2</span> <span class="dv">0</span> <span class="dv">1</span>, <span class="dt">V2</span> <span class="dv">1</span> <span class="dv">0</span>, <span class="dt">V2</span> (<span class="op">-</span><span class="dv">1</span>) <span class="dv">0</span><span class="op">...</span>]</span></code></pre></div>
<p>This is great, but we also need to keep track of which actual
positions this will cause us to walk, we need to
<strong>accumulate</strong> our position across the whole list. Let's
use a <code>scan</code>:</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="kw">import</span> <span class="dt">Control.Category</span> ((&gt;&gt;&gt;))</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="ot">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>    TIO.readFile <span class="st">&quot;./src/Y2019/day03.txt&quot;</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>               <span class="op">&lt;&amp;&gt;</span> T.lines</span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a>               <span class="op">&lt;&amp;&gt;</span> traverseOf both view (ix <span class="dv">0</span>, ix <span class="dv">1</span>)</span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a>               <span class="op">&lt;&amp;&gt;</span> both <span class="op">%~</span></span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a>                     (   toListOf ([regex|\w\d+|] <span class="op">.</span> match <span class="op">.</span> unpacked <span class="op">.</span> _Cons <span class="op">.</span> to parseInput <span class="op">.</span> folding (<span class="fu">uncurry</span> <span class="fu">replicate</span>))</span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a>                     <span class="op">&gt;&gt;&gt;</span> <span class="fu">scanl1</span> (<span class="op">+</span>)</span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a>                     <span class="op">&gt;&gt;&gt;</span> S.fromList</span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a>                     )</span>
<span id="cb6-13"><a href="#cb6-13" aria-hidden="true" tabindex="-1"></a>                     <span class="op">&gt;&gt;=</span> <span class="fu">print</span></span>
<span id="cb6-14"><a href="#cb6-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-15"><a href="#cb6-15" aria-hidden="true" tabindex="-1"></a><span class="co">-- Trying to print this Set crashed my computer, </span></span>
<span id="cb6-16"><a href="#cb6-16" aria-hidden="true" tabindex="-1"></a><span class="co">-- but here&#39;s what it looked like on the way down:</span></span>
<span id="cb6-17"><a href="#cb6-17" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> main</span>
<span id="cb6-18"><a href="#cb6-18" aria-hidden="true" tabindex="-1"></a>(S.fromList [<span class="dt">V2</span> <span class="dv">2003</span> <span class="dv">1486</span>,<span class="dt">V2</span> <span class="dv">2003</span> <span class="dv">1487</span>,<span class="op">...</span>], S.fromList [<span class="dt">V2</span> <span class="dv">1961</span> <span class="dv">86</span>,<span class="dt">V2</span> (<span class="op">-</span><span class="dv">433</span>), <span class="dv">8873</span>,<span class="op">...</span>])</span></code></pre></div>
<p>Normally I really don't like <code>&gt;&gt;&gt;</code>, but it allows
us to keep writing code top-to-bottom here, so I'll allow it just this
once.</p>
<p>The scan uses the <code>Num</code> instance of <code>V2</code> which
adds the <code>x</code> and <code>y</code> components separately. This
causes us to move in the right direction after every step, and keeps
track of where we've been along the way! I dump the data into a set with
<code>S.fromList</code> because next we're going to
<code>intersect</code>!</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">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>    TIO.readFile <span class="st">&quot;./src/Y2019/day03.txt&quot;</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>               <span class="op">&lt;&amp;&gt;</span> T.lines</span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>               <span class="op">&lt;&amp;&gt;</span> traverseOf both view (ix <span class="dv">0</span>, ix <span class="dv">1</span>)</span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>               <span class="op">&lt;&amp;&gt;</span> both <span class="op">%~</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a>                     (   toListOf ([regex|\w\d+|] <span class="op">.</span> match <span class="op">.</span> unpacked <span class="op">.</span> _Cons <span class="op">.</span> to parseInput <span class="op">.</span> folding (<span class="fu">uncurry</span> <span class="fu">replicate</span>))</span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a>                     <span class="op">&gt;&gt;&gt;</span> <span class="fu">scanl1</span> (<span class="op">+</span>)</span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a>                     <span class="op">&gt;&gt;&gt;</span> S.fromList</span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a>                     )</span>
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a>               <span class="op">&lt;&amp;&gt;</span> foldl1Of each S.intersection</span>
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true" tabindex="-1"></a>                     <span class="op">&gt;&gt;=</span> <span class="fu">print</span></span>
<span id="cb7-13"><a href="#cb7-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-14"><a href="#cb7-14" aria-hidden="true" tabindex="-1"></a><span class="co">-- This prints a significantly shorter list and doesn&#39;t crash my computer</span></span>
<span id="cb7-15"><a href="#cb7-15" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> main</span>
<span id="cb7-16"><a href="#cb7-16" aria-hidden="true" tabindex="-1"></a>fromList [<span class="dt">V2</span> (<span class="op">-</span><span class="dv">2794</span>) (<span class="op">-</span><span class="dv">390</span>),<span class="dt">V2</span> (<span class="op">-</span><span class="dv">2794</span>) <span class="dv">42</span>,<span class="op">...</span>]</span></code></pre></div>
<p>Okay we've jumped back out of our <code>both</code> block, now we
need to intersect the sets in our tuple! A normal person would use
<code>uncurry S.intersection</code>, but since this is an optics post
we'll of course use the excessive version
<code>foldl1Of each S.intersection</code> which folds over
<strong>each</strong> set using intersection! A bonus is that this
version won't need to change if we eventually switch to many wires
stored in a tuple or list, it'll <em>just work</em>™.</p>
<p>Almost done! Now we need to find which intersection is
<strong>closest</strong> to the origin. In our case the origin is just
<code>(0, 0)</code>, so we can get the distance by simply summing the
absolute value of the aspects of the Vector (which is acting as a
Point).</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>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>    TIO.readFile <span class="st">&quot;./src/Y2019/day03.txt&quot;</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>               <span class="op">&lt;&amp;&gt;</span> T.lines</span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a>               <span class="op">&lt;&amp;&gt;</span> traverseOf both view (ix <span class="dv">0</span>, ix <span class="dv">1</span>)</span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a>               <span class="op">&lt;&amp;&gt;</span> both <span class="op">%~</span></span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a>                     (   toListOf ([regex|\w\d+|] <span class="op">.</span> match <span class="op">.</span> unpacked <span class="op">.</span> _Cons <span class="op">.</span> to parseInput <span class="op">.</span> folding (<span class="fu">uncurry</span> <span class="fu">replicate</span>))</span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a>                     <span class="op">&gt;&gt;&gt;</span> <span class="fu">scanl1</span> (<span class="op">+</span>)</span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a>                     <span class="op">&gt;&gt;&gt;</span> S.fromList</span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a>                     )</span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a>               <span class="op">&lt;&amp;&gt;</span> foldl1Of each S.intersection</span>
<span id="cb8-12"><a href="#cb8-12" aria-hidden="true" tabindex="-1"></a>               <span class="op">&lt;&amp;&gt;</span> minimumOf (folded <span class="op">.</span> to (<span class="fu">sum</span> <span class="op">.</span> <span class="fu">abs</span>))</span>
<span id="cb8-13"><a href="#cb8-13" aria-hidden="true" tabindex="-1"></a>                     <span class="op">&gt;&gt;=</span> <span class="fu">print</span></span>
<span id="cb8-14"><a href="#cb8-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-15"><a href="#cb8-15" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> main</span>
<span id="cb8-16"><a href="#cb8-16" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> <span class="dv">399</span></span></code></pre></div>
<p>And that's my answer! Wonderful!</p>
<h2 id="part-2">Part 2</h2>
<p>Part 2 is a pretty reasonable twist, now we need to pick the
intersection which is the fewest number of steps <strong>along the
wire</strong> from the origin. We sum together the steps along each wire
and optimize for the smallest total.</p>
<p>Almost all of our code stays the same, but a Set isn't going to cut
it anymore, we need to know which <strong>step</strong> we were on when
we reached each location! <code>Map</code>s are kinda like sets with
extra info, so we'll switch to that instead. Instead of using
<code>S.fromList</code> we'll use <code>toMapOf</code>! We need the
index of each element in the list (which corresponds to it's distance
from the origin along the wire). a simple <code>zip [0..]</code> would
do it, but we'll use the much more obtuse version:</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>toMapOf (reindexed (<span class="op">+</span><span class="dv">1</span>) traversed <span class="op">.</span> withIndex <span class="op">.</span> swapped <span class="op">.</span> ito <span class="fu">id</span>)</span></code></pre></div>
<p>Fun right? <code>traversed</code> has a numerically increasing index
by default, <code>reindexed (+1)</code> makes it start at <code>1</code>
instead (since the first step still counts!). Make sure you don't forget
this or you'll be confused for a few minutes before realizing your
answer is off by 2...</p>
<p><code>toMapOf</code> uses the index as the key, but in our case we
actually need the vector as the key! Again, easiest would be to just use
a proper <code>M.fromList</code>, but we won't give up so easily. We
need to swap our index and our value within our lens path! We can pull
the index down from it's hiding place into value-land using
<code>withIndex</code> which adds the index to your value as a tuple, in
our case: <code>(Int, V2 Int)</code>, then we swap places using the
<code>swapped</code> iso, and reflect the <code>V2 Int</code> into the
index using <code>ito</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="ot">ito ::</span> (s <span class="ot">-&gt;</span> (i, a)) <span class="ot">-&gt;</span> <span class="dt">IndexedGetter</span> i s a</span></code></pre></div>
<p>Now <code>toMapOf</code> properly builds a
<code>Map (V2 Int) Int</code>!</p>
<p>Let's finish off part 2:</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">main2 ::</span> <span class="dt">IO</span> ()</span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>main2 <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>    TIO.readFile <span class="st">&quot;./src/Y2019/day03.txt&quot;</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>               <span class="op">&lt;&amp;&gt;</span> T.lines</span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>               <span class="op">&lt;&amp;&gt;</span> traverseOf both view (ix <span class="dv">0</span>, ix <span class="dv">1</span>)</span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>               <span class="op">&lt;&amp;&gt;</span> each <span class="op">%~</span></span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a>                     (   toListOf ([regex|\w\d+|] <span class="op">.</span> match <span class="op">.</span> unpacked <span class="op">.</span> _Cons <span class="op">.</span> to parseInput <span class="op">.</span> folding (<span class="fu">uncurry</span> <span class="fu">replicate</span>))</span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a>                     <span class="op">&gt;&gt;&gt;</span> <span class="fu">scanl1</span> (<span class="op">+</span>)</span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a>                     <span class="op">&gt;&gt;&gt;</span> toMapOf (reindexed (<span class="op">+</span><span class="dv">1</span>) traversed <span class="op">.</span> withIndex <span class="op">.</span> swapped <span class="op">.</span> ito <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="op">&lt;&amp;&gt;</span> foldl1Of each (M.intersectionWith (<span class="op">+</span>))</span>
<span id="cb11-12"><a href="#cb11-12" aria-hidden="true" tabindex="-1"></a>               <span class="op">&lt;&amp;&gt;</span> <span class="fu">minimum</span></span>
<span id="cb11-13"><a href="#cb11-13" aria-hidden="true" tabindex="-1"></a>               <span class="op">&gt;&gt;=</span> <span class="fu">print</span></span></code></pre></div>
<p>We use <code>M.intersectionWith (+)</code> now so we add the
distances when we hit an intersection, so our resulting Map has the sum
of the two wires' distances at each intersection.</p>
<p>Now we just get the minimum distance and print it! All done!</p>
<p>This one wasn't so "opticsy", but hopefully tomorrow's puzzle will
fit a bit better! Cheers!</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Advent of Optics: Day 2</title>
      <link href="https://chrispenner.ca/posts/advent-of-optics-02"/>
      <id>https://chrispenner.ca/posts/advent-of-optics-02</id>
      <updated>2019-12-02T00:00:00Z</updated>
      <summary>Day two of Advent of Code solved with optics</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/pinecones.jpg" alt="Advent of Optics: Day 2">
              <p>Since I'm releasing <a href="https://leanpub.com/optics-by-example">a
book on practical lenses and optics</a> later this month I thought it
would be fun to do a few of this year's Advent of Code puzzles using as
many obscure optics features as possible!</p>
<p>To be clear, the goal is to be obscure, strange and excessive towards
the goal of using as many optics as possible in a given solution, even
if it's awkward, silly, or just plain overkill. These are NOT idiomatic
Haskell solutions, nor are they intended to be. Maybe we'll both learn
something along the way. Let's have some fun!</p>
<p>You can find today's puzzle <a
href="https://adventofcode.com/2019/day/2">here</a>.</p>
<hr />
<p>Every year of Advent of Code usually has some sort of assembly
language simulator, looks like this year's came up early!</p>
<p>So we have a simple computer with registers which store integers, and
an instruction counter which keeps track of our current execution
location in the "program". There are two operations, addition and
multiplication, indicated by a <code>1</code> or a <code>2</code>
respectively. Each of these operations will also consume the two
integers following the instruction as the addresses of its arguments,
and a final integer representing the address to store the output. We
then increment the instruction counter to the next instruction and
continue. The program halts if ever there's a <code>99</code> in the
operation address.</p>
<p>As usual, we'll need to start by reading in our input. Last time we
could just use <code>words</code> to split the string on whitespace and
everything worked out. This time there are commas in between each int;
so we'll need a slightly different strategy. It's almost certainly
overkill for this, but I've wanting to show it off anyways; so I'll pull
in my <a
href="http://hackage.haskell.org/package/lens-regex-pcre"><code>lens-regex-pcre</code></a>
library for this. If you're following along at home, make sure you have
at LEAST version <code>1.0.0.0</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">{-# LANGUAGE QuasiQuotes #-}</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">import</span> <span class="dt">Control.Lens</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Lens.Regex.Text</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Text.IO</span> <span class="kw">as</span> <span class="dt">TIO</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="ot">solve1 ::</span> <span class="dt">IO</span> ()</span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>solve1 <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>  input <span class="ot">&lt;-</span> TIO.readFile <span class="st">&quot;./src/Y2019/day02.txt&quot;</span> </span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>           <span class="op">&lt;&amp;&gt;</span> toMapOf ([regex|\d+|] <span class="op">.</span> match <span class="op">.</span> _Show <span class="op">@</span><span class="dt">Int</span>)</span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>  <span class="fu">print</span> input</span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> solve1</span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a>[<span class="st">&quot;1&quot;</span>,<span class="st">&quot;0&quot;</span>,<span class="st">&quot;0&quot;</span>,<span class="st">&quot;3&quot;</span>,<span class="st">&quot;1&quot;</span>,<span class="st">&quot;1&quot;</span>,<span class="st">&quot;2&quot;</span><span class="op">...</span>]</span></code></pre></div>
<p>Okay, so to break this down a bit I'm reading in the input file as
<code>Text</code>, then using <code>&lt;&amp;&gt;</code> (which is
flipped (<code>&lt;$&gt;</code>)) to run the following transformation
over the result. <code>&lt;&amp;&gt;</code> is exported from
<code>lens</code>, but is now included in <code>base</code> as part of
<code>Data.Functor</code>, I enjoy using it over <code>&lt;$&gt;</code>
from time to time, it reads more like a 'pipeline', passing things from
left to right.</p>
<p>This pulls out all the integers as <code>Text</code> blocks, but we
still need to parse them, I'll use the <code>unpacked</code> iso to
convert from Text to String, then use the same <code>_Show</code> trick
from yesterday's problem.</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">solve1 ::</span> <span class="dt">IO</span> ()</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>solve1 <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>    input <span class="ot">&lt;-</span> TIO.readFile <span class="st">&quot;./src/Y2019/day02.txt&quot;</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>               <span class="op">&lt;&amp;&gt;</span> toListOf ([regex|\d+|] <span class="op">.</span> match <span class="op">.</span> unpacked <span class="op">.</span> _Show <span class="op">@</span><span class="dt">Int</span>)</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>    <span class="fu">print</span> input</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> solve1</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>[<span class="dv">1</span>,<span class="dv">0</span>,<span class="dv">0</span>,<span class="dv">3</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span><span class="op">...</span>]</span></code></pre></div>
<p>Okay, so we've loaded our register values, but from a glance at the
problem we'll need to have random access to different register values, I
won't worry about performance too much unless it becomes a problem, but
using a list seems a bit silly, so I'll switch from
<code>toListOf</code> into <code>toMapOf</code> to build a Map out of my
results. <code>toMapOf</code> uses the index of your optic as the key by
default, so I can just wrap my optic in <code>indexing</code> (which
adds an increasing integer as an index to an optic) to get a sequential
Int count as the keys for my map:</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">solve1 ::</span> <span class="dt">IO</span> ()</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>solve1 <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>    input <span class="ot">&lt;-</span> TIO.readFile <span class="st">&quot;./src/Y2019/day02.txt&quot;</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>               <span class="op">&lt;&amp;&gt;</span> toMapOf (indexing ([regex|\d+|] <span class="op">.</span> match <span class="op">.</span> unpacked <span class="op">.</span> _Show <span class="op">@</span><span class="dt">Int</span>))</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>    <span class="fu">print</span> input</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="op">&gt;&gt;&gt;</span> solve1</span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>fromList [(<span class="dv">0</span>,<span class="dv">1</span>),(<span class="dv">1</span>,<span class="dv">0</span>),(<span class="dv">2</span>,<span class="dv">0</span>),(<span class="dv">3</span>,<span class="dv">3</span>),(<span class="dv">4</span>,<span class="dv">1</span>)<span class="op">...</span>]</span></code></pre></div>
<p>Great, we've loaded our ints into "memory".</p>
<p>Next step, we're told at the bottom of the program to initialize the
1st and 2nd positions in memory to specific values, yours may differ,
but it told me to set the 1st to <code>12</code> and the second to
<code>2</code>. Easy enough to add that onto our pipeline!</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>input <span class="ot">&lt;-</span> TIO.readFile <span class="st">&quot;./src/Y2019/day02.txt&quot;</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>           <span class="op">&lt;&amp;&gt;</span> toMapOf (indexing ([regex|\d+|] <span class="op">.</span> match <span class="op">.</span> unpacked <span class="op">.</span> _Show <span class="op">@</span><span class="dt">Int</span>))</span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>           <span class="op">&lt;&amp;&gt;</span> ix <span class="dv">1</span> <span class="op">.~</span> <span class="dv">12</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>           <span class="op">&lt;&amp;&gt;</span> ix <span class="dv">2</span> <span class="op">.~</span> <span class="dv">2</span></span></code></pre></div>
<p>That'll 'pipeline' our input through and initialize the registers
correctly.</p>
<p>Okay, now for the hard part, we need to actually RUN our program!
Since we're emulating a stateful computer it only makes sense to use the
<code>State</code> monad right? We've got a map to represent our
registers, but we'll need an integer for our "read-head" too. Let's say
our state is <code>(Int, Map Int Int)</code>, the first slot is the
current read-address, the second is all our register values.</p>
<p>Let's write one iteration of our computation, then we'll figure out
how to run it until the halt.</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">oneStep ::</span> <span class="dt">State</span> (<span class="dt">Int</span>, <span class="dt">M.Map</span> <span class="dt">Int</span> <span class="dt">Int</span>) ()</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>oneStep <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> loadRegister r <span class="ot">=</span> use (_2 <span class="op">.</span> singular (ix r))</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> loadNext <span class="ot">=</span> _1 <span class="op">&lt;&lt;+=</span> <span class="dv">1</span> <span class="op">&gt;&gt;=</span> loadRegister</span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> getArg <span class="ot">=</span> loadNext <span class="op">&gt;&gt;=</span> loadRegister</span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a>    out <span class="ot">&lt;-</span> getOp <span class="op">&lt;$&gt;</span> loadNext <span class="op">&lt;*&gt;</span> getArg <span class="op">&lt;*&gt;</span> getArg</span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>    outputReg <span class="ot">&lt;-</span> loadNext</span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>    _2 <span class="op">.</span> ix outputReg <span class="op">.=</span> out</span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a><span class="ot">getOp ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> (<span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Int</span>)</span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a>getOp <span class="dv">1</span> <span class="ot">=</span> (<span class="op">+</span>)</span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a>getOp <span class="dv">2</span> <span class="ot">=</span> (<span class="op">*</span>)</span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a>getOp n <span class="ot">=</span> <span class="fu">error</span> <span class="op">$</span> <span class="st">&quot;unknown op-code: &quot;</span> <span class="op">&lt;&gt;</span> <span class="fu">show</span> n</span></code></pre></div>
<p>Believe it or not, that's one step of our computation, let's break it
down!</p>
<p>We define a few primitives we'll use at the beginning of the block.
First is <code>loadRegister</code>. <code>loadRegister</code> takes a
register 'address' and gets the value stored there. <code>use</code> is
like <code>get</code> from <code>MonadState</code>, but allows us to get
a specific piece of the state as focused by a lens. We use
<code>ix</code> to get the value at a specific key out of the map (which
is in the second slot of the tuple, hence the <code>_2</code>). However,
<code>ix r</code> is a traversal, not a lens, we could either switch to
<code>preuse</code> which returns a <code>Maybe</code>-wrapped result,
or we can use <code>singular</code> to <strong>force</strong> the result
and simply crash the whole program if its missing. Since we know our
input is valid, I'll just go ahead and <strong>force</strong> it.
Probably don't do this if you're building a REAL intcode computer :P</p>
<p>Next is <code>loadNext</code>, this fetches the current read-location
from the first slot, then loads the value at that register. There's a
bit of a trick here though, we load the read-location with
<code>_1 &lt;&lt;+= 1</code>; this performs the <code>+= 1</code> action
to the location, which increments it by one (we've 'consumed' the
current instruction), but the leading <code>&lt;&lt;</code> says to
return the value there <strong>before</strong> altering it. This lets us
cleanly get and increment the read-location all in one step. We then
load the value in the current location using
<code>loadRegister</code>.</p>
<p>We lastly combine these two combinators to build <code>getArg</code>,
which gets the value at the current read-location, then loads the
register at that address.</p>
<p>We can combine these all now! We <code>loadNext</code> to get the
opcode, converting it to a Haskell function using <code>getOp</code>,
then thread that computation through our two arguments getting an output
value.</p>
<p>Now we can load the output register (which will be the next value at
our read-location), and simply <code>_2 . ix outputReg .= result</code>
to stash it in the right spot.</p>
<p>If you haven't seen these lensy <code>MonadState</code> helpers
before, they're pretty cool. They basically let us write python-style
code in Haskell!</p>
<p>Okay, now let's add this to our pipeline! If we weren't still inside
the <code>IO</code> monad we could use <code>&amp;~</code> to chain
directly through the <code>MonadState</code> action!</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">(&amp;~) ::</span> s <span class="ot">-&gt;</span> <span class="dt">State</span> s a <span class="ot">-&gt;</span> s </span></code></pre></div>
<p>Unfortunately there's no <code>&lt;&amp;~&gt;</code> combinator, so
we'll have to move our pipeline out of <code>IO</code> for that. Not so
tough to do though:</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">solve1 ::</span> <span class="dt">IO</span> ()</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>solve1 <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>    input <span class="ot">&lt;-</span> TIO.readFile <span class="st">&quot;./src/Y2019/day02.txt&quot;</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> result <span class="ot">=</span> input</span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>            <span class="op">&amp;</span> toMapOf (indexing ([regex|\d+|] <span class="op">.</span> match <span class="op">.</span> unpacked <span class="op">.</span> _Show <span class="op">@</span><span class="dt">Int</span>))</span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>            <span class="op">&amp;</span> ix <span class="dv">1</span> <span class="op">.~</span> <span class="dv">12</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a>            <span class="op">&amp;</span> ix <span class="dv">2</span> <span class="op">.~</span> <span class="dv">2</span></span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a>            <span class="op">&amp;</span> (,) <span class="dv">0</span></span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a>            <span class="op">&amp;~</span> <span class="kw">do</span></span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a>                <span class="kw">let</span> loadRegister r <span class="ot">=</span> use (_2 <span class="op">.</span> singular (ix r))</span>
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a>                <span class="kw">let</span> loadNext <span class="ot">=</span> _1 <span class="op">&lt;&lt;+=</span> <span class="dv">1</span> <span class="op">&gt;&gt;=</span> loadRegister</span>
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true" tabindex="-1"></a>                <span class="kw">let</span> getArg <span class="ot">=</span> loadNext <span class="op">&gt;&gt;=</span> loadRegister</span>
<span id="cb7-13"><a href="#cb7-13" aria-hidden="true" tabindex="-1"></a>                out <span class="ot">&lt;-</span> getOp <span class="op">&lt;$&gt;</span> loadNext <span class="op">&lt;*&gt;</span> getArg <span class="op">&lt;*&gt;</span> getArg</span>
<span id="cb7-14"><a href="#cb7-14" aria-hidden="true" tabindex="-1"></a>                outputReg <span class="ot">&lt;-</span> loadNext</span>
<span id="cb7-15"><a href="#cb7-15" aria-hidden="true" tabindex="-1"></a>                _2 <span class="op">.</span> ix outputReg <span class="op">.=</span> out</span>
<span id="cb7-16"><a href="#cb7-16" aria-hidden="true" tabindex="-1"></a>    <span class="fu">print</span> result</span></code></pre></div>
<p>This runs ONE iteration of our program, but we'll need to run the
program until completion! The perfect combinator for this is
<code>untilM</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="ot">untilM ::</span> <span class="dt">Monad</span> m <span class="ot">=&gt;</span> m a <span class="ot">-&gt;</span> m <span class="dt">Bool</span> <span class="ot">-&gt;</span> m [a] </span></code></pre></div>
<p>This let's us write it something like this:</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">&amp;~</span> <span class="fu">flip</span> untilM ((<span class="op">==</span><span class="dv">99</span>) <span class="op">&lt;$&gt;</span> (use _1 <span class="op">&gt;&gt;=</span> loadRegister)) <span class="op">$</span> <span class="kw">do</span> <span class="op">...</span></span></code></pre></div>
<p>This would run our computation step repeatedly until it hits the
<code>99</code> instruction. However, <code>untilM</code> is in the
<code>monad-loops</code> library, and I don't feel like waiting for that
to install, so instead we'll just use recursion.</p>
<p>Hrmm, using recursion here would require me to name my expression, so
we could just use a <code>let</code> expression like this to explicitly
recurse until we hit <code>99</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="op">&amp;~</span> <span class="kw">let</span> loop <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>              <span class="kw">let</span> loadRegister r <span class="ot">=</span> use (_2 <span class="op">.</span> singular (ix r))</span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>              <span class="kw">let</span> loadNext <span class="ot">=</span> _1 <span class="op">&lt;&lt;+=</span> <span class="dv">1</span> <span class="op">&gt;&gt;=</span> loadRegister</span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>              <span class="kw">let</span> getArg <span class="ot">=</span> loadNext <span class="op">&gt;&gt;=</span> loadRegister</span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>              out <span class="ot">&lt;-</span> getOp <span class="op">&lt;$&gt;</span> loadNext <span class="op">&lt;*&gt;</span> getArg <span class="op">&lt;*&gt;</span> getArg</span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a>              outputReg <span class="ot">&lt;-</span> loadNext</span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a>              _2 <span class="op">.</span> ix outputReg <span class="op">.=</span> out</span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a>              use _1 <span class="op">&gt;&gt;=</span> loadRegister <span class="op">&gt;&gt;=</span> \<span class="kw">case</span></span>
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a>                <span class="dv">99</span> <span class="ot">-&gt;</span> <span class="fu">return</span> ()</span>
<span id="cb10-10"><a href="#cb10-10" aria-hidden="true" tabindex="-1"></a>                _ <span class="ot">-&gt;</span> loop</span>
<span id="cb10-11"><a href="#cb10-11" aria-hidden="true" tabindex="-1"></a>   <span class="kw">in</span> loop</span></code></pre></div>
<p>But the <code>let loop = ... in loop</code> construct is kind of
annoying me, not huge fan.</p>
<p>Clearly the right move is to use anonymous recursion! (/sarcasm)</p>
<p>We can /simplify/ this by using <code>fix</code>!</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">fix ::</span> (a <span class="ot">-&gt;</span> a) <span class="ot">-&gt;</span> a</span></code></pre></div>
<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">&amp;~</span> fix (\continue <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> loadRegister r <span class="ot">=</span> use (_2 <span class="op">.</span> singular (ix r))</span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> loadNext <span class="ot">=</span> _1 <span class="op">&lt;&lt;+=</span> <span class="dv">1</span> <span class="op">&gt;&gt;=</span> loadRegister</span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> getArg <span class="ot">=</span> loadNext <span class="op">&gt;&gt;=</span> loadRegister</span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a>    out <span class="ot">&lt;-</span> getOp <span class="op">&lt;$&gt;</span> loadNext <span class="op">&lt;*&gt;</span> getArg <span class="op">&lt;*&gt;</span> getArg</span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a>    outputReg <span class="ot">&lt;-</span> loadNext</span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a>    _2 <span class="op">.</span> ix outputReg <span class="op">.=</span> out</span>
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a>    use _1 <span class="op">&gt;&gt;=</span> loadRegister <span class="op">&gt;&gt;=</span> \<span class="kw">case</span></span>
<span id="cb12-9"><a href="#cb12-9" aria-hidden="true" tabindex="-1"></a>      <span class="dv">99</span> <span class="ot">-&gt;</span> <span class="fu">return</span> ()</span>
<span id="cb12-10"><a href="#cb12-10" aria-hidden="true" tabindex="-1"></a>      _ <span class="ot">-&gt;</span> continue</span>
<span id="cb12-11"><a href="#cb12-11" aria-hidden="true" tabindex="-1"></a>    )</span></code></pre></div>
<p>Beautiful right? Well... some might disagree :P, but definitely fun
and educational!</p>
<p>I'll leave you to study the arcane arts of <code>fix</code> on your
own, but here's a teaser. Working with <code>fix</code> is similar to
explicit recursion, you assume that you already <strong>have</strong>
your result, then you can use it in your computation. In this case, we
<em>assume</em> that <code>continue</code> is a state action which will
loop until the program halts, so we do one step of the computation and
then hand off control to <code>continue</code> which will magically
<strong>solve the rest</strong>. It's basically identical to the
<code>let ... in</code> version, but more obtuse and harder to read, so
obviously we'll keep it!</p>
<p>If we slot this in it'll run the computation until it hits a
<code>99</code>, and <code>&amp;~</code> returns the resulting state, so
all we need to do is view the first instruction location of our
registers to get our answer!</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">solve1 ::</span> <span class="dt">IO</span> ()</span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>solve1 <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a>    input <span class="ot">&lt;-</span> TIO.readFile <span class="st">&quot;./src/Y2019/day02.txt&quot;</span></span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>    <span class="fu">print</span> <span class="op">$</span> input</span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a>            <span class="op">&amp;</span> toMapOf (indexing ([regex|\d+|] <span class="op">.</span> match <span class="op">.</span> unpacked <span class="op">.</span> _Show <span class="op">@</span><span class="dt">Int</span>))</span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a>            <span class="op">&amp;</span> ix <span class="dv">1</span> <span class="op">.~</span> <span class="dv">12</span></span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a>            <span class="op">&amp;</span> ix <span class="dv">2</span> <span class="op">.~</span> <span class="dv">2</span></span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a>            <span class="op">&amp;</span> (,) <span class="dv">0</span></span>
<span id="cb13-9"><a href="#cb13-9" aria-hidden="true" tabindex="-1"></a>            <span class="op">&amp;~</span> fix (\continue <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb13-10"><a href="#cb13-10" aria-hidden="true" tabindex="-1"></a>                <span class="kw">let</span> loadRegister r <span class="ot">=</span> use (_2 <span class="op">.</span> singular (ix r))</span>
<span id="cb13-11"><a href="#cb13-11" aria-hidden="true" tabindex="-1"></a>                <span class="kw">let</span> loadNext <span class="ot">=</span> _1 <span class="op">&lt;&lt;+=</span> <span class="dv">1</span> <span class="op">&gt;&gt;=</span> loadRegister</span>
<span id="cb13-12"><a href="#cb13-12" aria-hidden="true" tabindex="-1"></a>                <span class="kw">let</span> getArg <span class="ot">=</span> loadNext <span class="op">&gt;&gt;=</span> loadRegister</span>
<span id="cb13-13"><a href="#cb13-13" aria-hidden="true" tabindex="-1"></a>                out <span class="ot">&lt;-</span> getOp <span class="op">&lt;$&gt;</span> loadNext <span class="op">&lt;*&gt;</span> getArg <span class="op">&lt;*&gt;</span> getArg</span>
<span id="cb13-14"><a href="#cb13-14" aria-hidden="true" tabindex="-1"></a>                outputReg <span class="ot">&lt;-</span> loadNext</span>
<span id="cb13-15"><a href="#cb13-15" aria-hidden="true" tabindex="-1"></a>                _2 <span class="op">.</span> ix outputReg <span class="op">.=</span> out</span>
<span id="cb13-16"><a href="#cb13-16" aria-hidden="true" tabindex="-1"></a>                use _1 <span class="op">&gt;&gt;=</span> loadRegister <span class="op">&gt;&gt;=</span> \<span class="kw">case</span></span>
<span id="cb13-17"><a href="#cb13-17" aria-hidden="true" tabindex="-1"></a>                  <span class="dv">99</span> <span class="ot">-&gt;</span> <span class="fu">return</span> ()</span>
<span id="cb13-18"><a href="#cb13-18" aria-hidden="true" tabindex="-1"></a>                  _ <span class="ot">-&gt;</span> continue</span>
<span id="cb13-19"><a href="#cb13-19" aria-hidden="true" tabindex="-1"></a>                )</span>
<span id="cb13-20"><a href="#cb13-20" aria-hidden="true" tabindex="-1"></a>            <span class="op">&amp;</span> view (_2 <span class="op">.</span> singular (ix <span class="dv">0</span>))</span>
<span id="cb13-21"><a href="#cb13-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-22"><a href="#cb13-22" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> solve1</span>
<span id="cb13-23"><a href="#cb13-23" aria-hidden="true" tabindex="-1"></a><span class="op">&lt;</span>my answer<span class="op">&gt;</span></span></code></pre></div>
<p>Honestly, aside from the intentional obfuscation it turned out
okay!</p>
<h2 id="part-2">Part 2</h2>
<p>Just in case you haven't solved the first part on your own, the
second part says we now need to find a specific <strong>memory
initialization</strong> which <strong>results</strong> in a specific
answer after running the computer. We need to find the exact values to
put into slots 1 and 2 which result in this number, in my case:
<code>19690720</code>.</p>
<p>Let's see what we can do! First I'll refactor the code from step 1 so
it accepts some parameters</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">solveSingle ::</span> <span class="dt">M.Map</span> <span class="dt">Int</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Int</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a>solveSingle registers noun verb <span class="ot">=</span></span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a>    registers</span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">&amp;</span> ix <span class="dv">1</span> <span class="op">.~</span> noun</span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">&amp;</span> ix <span class="dv">2</span> <span class="op">.~</span> verb</span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">&amp;</span> (,) <span class="dv">0</span></span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">&amp;~</span> fix (\continue <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a>        <span class="kw">let</span> loadRegister r <span class="ot">=</span> use (_2 <span class="op">.</span> singular (ix r))</span>
<span id="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a>        <span class="kw">let</span> loadNext <span class="ot">=</span> _1 <span class="op">&lt;&lt;+=</span> <span class="dv">1</span> <span class="op">&gt;&gt;=</span> loadRegister</span>
<span id="cb14-10"><a href="#cb14-10" aria-hidden="true" tabindex="-1"></a>        <span class="kw">let</span> getArg <span class="ot">=</span> loadNext <span class="op">&gt;&gt;=</span> loadRegister</span>
<span id="cb14-11"><a href="#cb14-11" aria-hidden="true" tabindex="-1"></a>        out <span class="ot">&lt;-</span> getOp <span class="op">&lt;$&gt;</span> loadNext <span class="op">&lt;*&gt;</span> getArg <span class="op">&lt;*&gt;</span> getArg</span>
<span id="cb14-12"><a href="#cb14-12" aria-hidden="true" tabindex="-1"></a>        outputReg <span class="ot">&lt;-</span> loadNext</span>
<span id="cb14-13"><a href="#cb14-13" aria-hidden="true" tabindex="-1"></a>        _2 <span class="op">.</span> ix outputReg <span class="op">.=</span> out</span>
<span id="cb14-14"><a href="#cb14-14" aria-hidden="true" tabindex="-1"></a>        use _1 <span class="op">&gt;&gt;=</span> loadRegister <span class="op">&gt;&gt;=</span> \<span class="kw">case</span></span>
<span id="cb14-15"><a href="#cb14-15" aria-hidden="true" tabindex="-1"></a>          <span class="dv">99</span> <span class="ot">-&gt;</span> <span class="fu">return</span> ()</span>
<span id="cb14-16"><a href="#cb14-16" aria-hidden="true" tabindex="-1"></a>          _ <span class="ot">-&gt;</span> continue</span>
<span id="cb14-17"><a href="#cb14-17" aria-hidden="true" tabindex="-1"></a>        )</span>
<span id="cb14-18"><a href="#cb14-18" aria-hidden="true" tabindex="-1"></a>    <span class="op">&amp;</span> view (_2 <span class="op">.</span> singular (ix <span class="dv">0</span>))</span></code></pre></div>
<p>That was pretty painless. Now we need to construct some thingamabob
which runs this with different 'noun' and 'verb' numbers (that's what
the puzzle calls them) until it gets the answer we need. Unless we want
to do some sort of crazy analysis of how this computer works at a
theoretical level, we'll have to just brute force it. There're only
10,000 combinations, so it should be fine. We can collect all
possibilities using a simple list comprehension:</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>[(noun, verb) <span class="op">|</span> noun <span class="ot">&lt;-</span> [<span class="dv">0</span><span class="op">..</span><span class="dv">99</span>], verb <span class="ot">&lt;-</span> [<span class="dv">0</span><span class="op">..</span><span class="dv">99</span>]]</span></code></pre></div>
<p>We need to run the computer on each possible set of inputs, which
amounts to simply calling <code>solveSingle</code> on them:</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">solve2 ::</span> <span class="dt">IO</span> ()</span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a>solve2 <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a>    registers <span class="ot">&lt;-</span> TIO.readFile <span class="st">&quot;./src/Y2019/day02.txt&quot;</span></span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a>               <span class="op">&lt;&amp;&gt;</span> toMapOf (indexing ([regex|\d+|] <span class="op">.</span> match <span class="op">.</span> unpacked <span class="op">.</span> _Show <span class="op">@</span><span class="dt">Int</span>))</span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a>    <span class="fu">print</span> <span class="op">$</span> [(noun, verb) <span class="op">|</span> noun <span class="ot">&lt;-</span> [<span class="dv">0</span><span class="op">..</span><span class="dv">99</span>], verb <span class="ot">&lt;-</span> [<span class="dv">0</span><span class="op">..</span><span class="dv">99</span>]]</span>
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a>              <span class="op">^..</span> traversed <span class="op">.</span> to (<span class="fu">uncurry</span> (solveSingle registers))</span>
<span id="cb16-7"><a href="#cb16-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-8"><a href="#cb16-8" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> solve2</span>
<span id="cb16-9"><a href="#cb16-9" aria-hidden="true" tabindex="-1"></a>[<span class="dv">29891</span>,<span class="dv">29892</span>,<span class="dv">29893</span>,<span class="dv">29894</span>,<span class="dv">29895</span>,<span class="dv">29896</span>,<span class="dv">29897</span>,<span class="dv">29898</span>,<span class="dv">29899</span>,<span class="dv">29900</span><span class="op">...</span>]</span></code></pre></div>
<p>This prints out the answers to every possible combination, but we
need to <strong>find</strong> a <strong>specific</strong> combination!
We can easily <strong>find</strong> the answer by using
<code>filtered</code>, or <code>only</code> or even <code>findOf</code>,
these are all valid:</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="op">&gt;&gt;&gt;</span> [(noun, verb) <span class="op">|</span> noun <span class="ot">&lt;-</span> [<span class="dv">0</span><span class="op">..</span><span class="dv">99</span>], verb <span class="ot">&lt;-</span> [<span class="dv">0</span><span class="op">..</span><span class="dv">99</span>]] </span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a>      <span class="op">^?</span> traversed <span class="op">.</span> to (<span class="fu">uncurry</span> (solveSingle registers)) <span class="op">.</span> filtered (<span class="op">==</span> <span class="dv">19690720</span>)</span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> <span class="dv">19690720</span></span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a><span class="co">-- `only` is like `filtered` but searches for a specific value</span></span>
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> [(noun, verb) <span class="op">|</span> noun <span class="ot">&lt;-</span> [<span class="dv">0</span><span class="op">..</span><span class="dv">99</span>], verb <span class="ot">&lt;-</span> [<span class="dv">0</span><span class="op">..</span><span class="dv">99</span>]] </span>
<span id="cb17-7"><a href="#cb17-7" aria-hidden="true" tabindex="-1"></a>      <span class="op">^?</span> traversed <span class="op">.</span> to (<span class="fu">uncurry</span> (solveSingle registers)) <span class="op">.</span> only <span class="dv">19690720</span></span>
<span id="cb17-8"><a href="#cb17-8" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> <span class="dv">19690720</span></span>
<span id="cb17-9"><a href="#cb17-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-10"><a href="#cb17-10" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> findOf </span>
<span id="cb17-11"><a href="#cb17-11" aria-hidden="true" tabindex="-1"></a>      (traversed <span class="op">.</span> to (<span class="fu">uncurry</span> (solveSingle registers)) <span class="op">.</span> only <span class="dv">19690720</span>)</span>
<span id="cb17-12"><a href="#cb17-12" aria-hidden="true" tabindex="-1"></a>      [(noun, verb) <span class="op">|</span> noun <span class="ot">&lt;-</span> [<span class="dv">0</span><span class="op">..</span><span class="dv">99</span>], verb <span class="ot">&lt;-</span> [<span class="dv">0</span><span class="op">..</span><span class="dv">99</span>]]</span>
<span id="cb17-13"><a href="#cb17-13" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> <span class="dv">19690720</span></span></code></pre></div>
<p>These all work, but the tricky part is that we don't actually care
about the answer, we already know that! What we need is the arguments we
passed in to <strong>get</strong> that answer. There are many ways to do
this, but my first thought is to just <strong>stash</strong> the
arguments away where we can get them later. Indexes are great for this
sort of thing (I cover tricks using indexed optics <a
href="https://leanpub.com/optics-by-example">in my book</a>). We can
<em>stash</em> a value into the index using <code>selfIndex</code>, and
it'll be carried alongside the rest of your computation for you! There's
the handy <code>findIndexOf</code> combinator which will find the index
of the first value which matches your predicate (in this case, the
answer is equal to our required output).</p>
<p>Here's the magic incantation:</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>findIndexOf (traversed <span class="op">.</span> selfIndex <span class="op">.</span> to (<span class="fu">uncurry</span> (solveSingle registers)))</span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a>            (<span class="op">==</span> <span class="dv">19690720</span>)</span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a>            [(noun, verb) <span class="op">|</span> noun <span class="ot">&lt;-</span> [<span class="dv">0</span><span class="op">..</span><span class="dv">99</span>], verb <span class="ot">&lt;-</span> [<span class="dv">0</span><span class="op">..</span><span class="dv">99</span>]]</span></code></pre></div>
<p>This gets us super-duper close, but the problem says we actually need
to run the following transformation over our arguments to get the real
answer: <code>(100 * noun) + verb</code>. We could easily do it
<em>after</em> running <code>findIndexOf</code>, but just to be
ridiculous, we'll do it inline! We're stashing our "answer" in the
index, so that's where we need to run the transformation. We can use
<code>reindexed</code> to run a transformation over the index of an
optic, so if we alter <code>selfIndex</code> (which stashes the value
into the index) then we can map the index through the
transformation:</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>reindexed (\(noun, verb) <span class="ot">-&gt;</span> (<span class="dv">100</span> <span class="op">*</span> noun) <span class="op">+</span> verb) selfIndex</span></code></pre></div>
<p>That does it!</p>
<p>Altogether now, here's the entire solution for the second part:</p>
<div class="sourceCode" id="cb20"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="ot">getOp ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> (<span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Int</span>)</span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a>getOp <span class="dv">1</span> <span class="ot">=</span> (<span class="op">+</span>)</span>
<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a>getOp <span class="dv">2</span> <span class="ot">=</span> (<span class="op">*</span>)</span>
<span id="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a>getOp n <span class="ot">=</span> <span class="fu">error</span> <span class="op">$</span> <span class="st">&quot;unknown op-code: &quot;</span> <span class="op">&lt;&gt;</span> <span class="fu">show</span> n</span>
<span id="cb20-5"><a href="#cb20-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-6"><a href="#cb20-6" aria-hidden="true" tabindex="-1"></a><span class="ot">solveSingle ::</span> <span class="dt">M.Map</span> <span class="dt">Int</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Int</span></span>
<span id="cb20-7"><a href="#cb20-7" aria-hidden="true" tabindex="-1"></a>solveSingle registers noun verb <span class="ot">=</span></span>
<span id="cb20-8"><a href="#cb20-8" aria-hidden="true" tabindex="-1"></a>    registers</span>
<span id="cb20-9"><a href="#cb20-9" aria-hidden="true" tabindex="-1"></a>    <span class="op">&amp;</span> ix <span class="dv">1</span> <span class="op">.~</span> noun</span>
<span id="cb20-10"><a href="#cb20-10" aria-hidden="true" tabindex="-1"></a>    <span class="op">&amp;</span> ix <span class="dv">2</span> <span class="op">.~</span> verb</span>
<span id="cb20-11"><a href="#cb20-11" aria-hidden="true" tabindex="-1"></a>    <span class="op">&amp;</span> (,) <span class="dv">0</span></span>
<span id="cb20-12"><a href="#cb20-12" aria-hidden="true" tabindex="-1"></a>    <span class="op">&amp;~</span> fix (\continue <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb20-13"><a href="#cb20-13" aria-hidden="true" tabindex="-1"></a>        <span class="kw">let</span> loadRegister r <span class="ot">=</span> use (_2 <span class="op">.</span> singular (ix r))</span>
<span id="cb20-14"><a href="#cb20-14" aria-hidden="true" tabindex="-1"></a>        <span class="kw">let</span> loadNext <span class="ot">=</span> _1 <span class="op">&lt;&lt;+=</span> <span class="dv">1</span> <span class="op">&gt;&gt;=</span> loadRegister</span>
<span id="cb20-15"><a href="#cb20-15" aria-hidden="true" tabindex="-1"></a>        <span class="kw">let</span> getArg <span class="ot">=</span> loadNext <span class="op">&gt;&gt;=</span> loadRegister</span>
<span id="cb20-16"><a href="#cb20-16" aria-hidden="true" tabindex="-1"></a>        out <span class="ot">&lt;-</span> getOp <span class="op">&lt;$&gt;</span> loadNext <span class="op">&lt;*&gt;</span> getArg <span class="op">&lt;*&gt;</span> getArg</span>
<span id="cb20-17"><a href="#cb20-17" aria-hidden="true" tabindex="-1"></a>        outputReg <span class="ot">&lt;-</span> loadNext</span>
<span id="cb20-18"><a href="#cb20-18" aria-hidden="true" tabindex="-1"></a>        _2 <span class="op">.</span> ix outputReg <span class="op">.=</span> out</span>
<span id="cb20-19"><a href="#cb20-19" aria-hidden="true" tabindex="-1"></a>        use _1 <span class="op">&gt;&gt;=</span> loadRegister <span class="op">&gt;&gt;=</span> \<span class="kw">case</span></span>
<span id="cb20-20"><a href="#cb20-20" aria-hidden="true" tabindex="-1"></a>          <span class="dv">99</span> <span class="ot">-&gt;</span> <span class="fu">return</span> ()</span>
<span id="cb20-21"><a href="#cb20-21" aria-hidden="true" tabindex="-1"></a>          _ <span class="ot">-&gt;</span> continue</span>
<span id="cb20-22"><a href="#cb20-22" aria-hidden="true" tabindex="-1"></a>        )</span>
<span id="cb20-23"><a href="#cb20-23" aria-hidden="true" tabindex="-1"></a>    <span class="op">&amp;</span> view (_2 <span class="op">.</span> singular (ix <span class="dv">0</span>))</span>
<span id="cb20-24"><a href="#cb20-24" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-25"><a href="#cb20-25" aria-hidden="true" tabindex="-1"></a><span class="ot">solvePart2 ::</span> <span class="dt">IO</span> ()</span>
<span id="cb20-26"><a href="#cb20-26" aria-hidden="true" tabindex="-1"></a>solvePart2 <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb20-27"><a href="#cb20-27" aria-hidden="true" tabindex="-1"></a>    registers <span class="ot">&lt;-</span> TIO.readFile <span class="st">&quot;./src/Y2019/day02.txt&quot;</span></span>
<span id="cb20-28"><a href="#cb20-28" aria-hidden="true" tabindex="-1"></a>               <span class="op">&lt;&amp;&gt;</span> toMapOf (indexing ([regex|\d+|] <span class="op">.</span> match <span class="op">.</span> unpacked <span class="op">.</span> _Show <span class="op">@</span><span class="dt">Int</span>))</span>
<span id="cb20-29"><a href="#cb20-29" aria-hidden="true" tabindex="-1"></a>    <span class="fu">print</span> <span class="op">$</span> findIndexOf  ( traversed</span>
<span id="cb20-30"><a href="#cb20-30" aria-hidden="true" tabindex="-1"></a>                         <span class="op">.</span> reindexed (\(noun, verb) <span class="ot">-&gt;</span> (<span class="dv">100</span> <span class="op">*</span> noun) <span class="op">+</span> verb) selfIndex</span>
<span id="cb20-31"><a href="#cb20-31" aria-hidden="true" tabindex="-1"></a>                         <span class="op">.</span> to (<span class="fu">uncurry</span> (solveSingle registers)))</span>
<span id="cb20-32"><a href="#cb20-32" aria-hidden="true" tabindex="-1"></a>            (<span class="op">==</span> <span class="dv">19690720</span>)</span>
<span id="cb20-33"><a href="#cb20-33" aria-hidden="true" tabindex="-1"></a>            [(noun, verb) <span class="op">|</span> noun <span class="ot">&lt;-</span> [<span class="dv">0</span><span class="op">..</span><span class="dv">99</span>], verb <span class="ot">&lt;-</span> [<span class="dv">0</span><span class="op">..</span><span class="dv">99</span>]]</span></code></pre></div>
<p>This was a surprisingly tricky problem for only day 2, but we've
gotten through it okay! Today we learned about:</p>
<ul>
<li><code>regex</code>: for precisely extracting text</li>
<li><code>toMapOf</code>: for building maps from an indexed fold</li>
<li><code>&amp;~</code>: for running state monads as part of a
pipeline</li>
<li><code>&lt;&amp;&gt;</code>: for pipelining data within a
context,</li>
<li><code>&lt;&lt;+=</code>: for simultaneous modification AND access
using lenses in MonadState</li>
<li><code>fix</code>: using fix for anonymous recursion (just for
fun)</li>
<li><code>selfIndex</code>: for stashing values till later</li>
<li><code>reindexed</code>: for editing indices</li>
<li><code>findIndexOf</code>: for getting the index of a value matching
a predicate</li>
</ul>
<p>Hopefully at least one of those was new for you! Maybe tomorrows will
be easier :)</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Advent of Optics: Day 1</title>
      <link href="https://chrispenner.ca/posts/advent-of-optics-01"/>
      <id>https://chrispenner.ca/posts/advent-of-optics-01</id>
      <updated>2019-12-01T00:00:00Z</updated>
      <summary>Day one of Advent of Code solved using optics</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/pinecones.jpg" alt="Advent of Optics: Day 1">
              <p>Since I'm releasing <a href="https://leanpub.com/optics-by-example">a
book on practical lenses and optics</a> later this month I thought it
would be fun to do a few of this year's Advent of Code puzzles using
optics as much as possible!</p>
<p>I'm not sure how many I'll do, or even if any problems will yield
interesting solutions with optics, but there's no harm trying! The goal
is to use optics for as much of the solution as possible, even if it's
awkward, silly, or just plain overkill. Maybe we'll both learn something
along the way. Let's have some fun!</p>
<p>You can find the first puzzle <a
href="https://adventofcode.com/2019/day/1">here</a>.</p>
<h2 id="part-one">Part One</h2>
<p>So the gist of this one is that we have a series of input numbers
(mass of ship modules) which each need to pass through a pipeline of
mathematic operations (fuel calculations) before being summed together
to get our puzzle solution (total fuel required).</p>
<p>This immediately makes me think of a <strong>reducing</strong>
operation, we want to <strong>fold</strong> many inputs down into a
single solution. We also need to <strong>map</strong> each input through
the pipeline of transformations before adding them. Were I to use
"normal" Haskell I could just <code>foldMap</code> to do both the
<strong>fold</strong> and <strong>map</strong> at once! With optics
however, the ideas of <strong>folds</strong> <em>already</em> encompass
both the folding and mapping pieces. The optic we use provides the
selection of elements as well as the mapping, and the action we run on
it provides the reductions step (the fold).</p>
<p>Let's see if we can build up a fold in pieces to do what we need.</p>
<p>Assuming we have a <code>String</code> representing our problem input
we need to break it into tokens to get each number from the file.
Writing a parser is overkill for such a simple task; we can just use the
<code>worded</code> fold which splits a String on whitespace and folds
over each word individually!</p>
<p>Here's what we've got so far:</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">import</span> <span class="dt">Control.Lens</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="ot">solve ::</span> <span class="dt">IO</span> ()</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>solve <span class="ot">=</span>  <span class="kw">do</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>  input <span class="ot">&lt;-</span> <span class="fu">readFile</span> <span class="st">&quot;./src/Y2019/day01.txt&quot;</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>  <span class="fu">print</span> <span class="op">$</span> input <span class="op">^..</span> worded</span></code></pre></div>
<p>Running this yields something 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="op">&gt;&gt;&gt;</span> solve</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>[<span class="st">&quot;76542&quot;</span>,<span class="st">&quot;97993&quot;</span>,<span class="st">&quot;79222&quot;</span><span class="op">...</span>] <span class="co">-- You get the idea</span></span></code></pre></div>
<p>Now we need to parse the strings into a numeric type like
<code>Double</code>. There's a handy prism in <code>lens</code> called
<code>_Show</code> which will use <code>Read</code> instances to parse
strings, simply skipping elements which fail to parse. Our input is
valid, so we don't need to worry about errors, meaning we can use this
prism confidently.</p>
<p>Here's the type of <code>_Show</code> by the way:</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">_Show ::</span> (<span class="dt">Read</span> a, <span class="dt">Show</span> a) <span class="ot">=&gt;</span> <span class="dt">Prism&#39;</span> <span class="dt">String</span> a</span></code></pre></div>
<p>I'll add a type-application to tell it what the output type should be
so it knows what type to parse into (i.e. which <code>Read</code>
instance to use for the parsing):</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 TypeApplications #-}</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="ot">solve ::</span> <span class="dt">IO</span> ()</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>solve <span class="ot">=</span>  <span class="kw">do</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>  input <span class="ot">&lt;-</span> <span class="fu">readFile</span> <span class="st">&quot;./src/Y2019/day01.txt&quot;</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>  <span class="fu">print</span> <span class="op">$</span> input <span class="op">^..</span> worded</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>                  <span class="op">.</span> _Show <span class="op">@</span><span class="dt">Double</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="op">&gt;&gt;&gt;</span> solve</span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a>[<span class="fl">76542.0</span>,<span class="fl">97993.0</span>,<span class="fl">79222.0</span><span class="op">...</span>]</span></code></pre></div>
<p>Looks like that's working!</p>
<p>Next we need to pipe it through several numeric operations. I like to
read my optics pipelines sequentially, so I'll use <code>to</code> to
string each transformation together. If you prefer you can simply
compose all the arithmetic into a single function and use only one
<code>to</code> instead, but this is how I like to do it.</p>
<p>The steps are:</p>
<ol>
<li>Divide by 3</li>
<li>Round down</li>
<li>Subtract 2</li>
</ol>
<p>No problem:</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">solve ::</span> <span class="dt">IO</span> ()</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>solve <span class="ot">=</span>  <span class="kw">do</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>  input <span class="ot">&lt;-</span> <span class="fu">readFile</span> <span class="st">&quot;./src/Y2019/day01.txt&quot;</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>  <span class="fu">print</span> <span class="op">$</span> input <span class="op">^..</span> worded</span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>                  <span class="op">.</span> _Show</span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a>                  <span class="op">.</span> to (<span class="op">/</span> <span class="dv">3</span>)</span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>                  <span class="op">.</span> to (<span class="fu">floor</span> <span class="op">@</span><span class="dt">Double</span> <span class="op">@</span><span class="dt">Int</span>)</span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>                  <span class="op">.</span> to (<span class="fu">subtract</span> <span class="dv">2</span>)</span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> solve</span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a>[<span class="dv">25512</span>,<span class="dv">32662</span>,<span class="dv">26405</span><span class="op">...</span>]</span></code></pre></div>
<p>I moved the type application to <code>floor</code> so it knows what
its converting between, but other than that it's pretty straight
forward.</p>
<p>Almost done! Lastly we need to sum all these adapted numbers
together. We can simply change our aggregation action from
<code>^..</code> (a.k.a. <code>toListOf</code>) into <code>sumOf</code>
and we'll now collect results by summing!</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">solve ::</span> <span class="dt">IO</span> ()</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>solve <span class="ot">=</span>  <span class="kw">do</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>  input <span class="ot">&lt;-</span> <span class="fu">readFile</span> <span class="st">&quot;./src/Y2019/day01.txt&quot;</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>  <span class="fu">print</span> <span class="op">$</span> input <span class="op">&amp;</span> sumOf ( worded</span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>                        <span class="op">.</span> _Show</span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>                        <span class="op">.</span> to (<span class="op">/</span> <span class="dv">3</span>)</span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a>                        <span class="op">.</span> to (<span class="fu">floor</span> <span class="op">@</span><span class="dt">Double</span> <span class="op">@</span><span class="dt">Int</span>)</span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a>                        <span class="op">.</span> to (<span class="fu">subtract</span> <span class="dv">2</span>)</span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a>                        )</span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> solve</span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a><span class="dv">3154112</span></span></code></pre></div>
<p>First part's all done! That's the correct answer.</p>
<p>As a fun side-note, we could have computed the ENTIRE thing in a fold
by using <code>lens-action</code> to thread the <code>readFile</code>
into IO as well. Here's that version:</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="kw">import</span> <span class="dt">Control.Lens</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Lens.Action</span> ((^!), act)</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="ot">solve&#39; ::</span> <span class="dt">IO</span> (<span class="dt">Sum</span> <span class="dt">Int</span>)</span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>solve&#39; <span class="ot">=</span>  <span class="st">&quot;./src/Y2019/day01.txt&quot;</span></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>          <span class="op">^!</span> act <span class="fu">readFile</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a>          <span class="op">.</span> worded</span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a>          <span class="op">.</span> _Show</span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a>          <span class="op">.</span> to (<span class="op">/</span><span class="dv">3</span>)</span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a>          <span class="op">.</span> to <span class="fu">floor</span> <span class="op">@</span><span class="dt">Double</span> <span class="op">@</span><span class="dt">Int</span></span>
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a>          <span class="op">.</span> to (<span class="fu">subtract</span> <span class="dv">2</span>)</span>
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true" tabindex="-1"></a>          <span class="op">.</span> to <span class="dt">Sum</span></span>
<span id="cb7-13"><a href="#cb7-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-14"><a href="#cb7-14" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> solve&#39;</span>
<span id="cb7-15"><a href="#cb7-15" aria-hidden="true" tabindex="-1"></a><span class="dt">Sum</span> {getSum <span class="ot">=</span> <span class="dv">3154112</span>}</span></code></pre></div>
<p>The <code>^!</code> is an action from <code>lens-action</code> which
lets us 'view' a result from a Fold which requires IO. <code>act</code>
allows us to lift a monadic action into a fold. By <code>viewing</code>
we implicitly fold down the output using it's Monoid (in this case
<code>Sum</code>).</p>
<p>I think the first version is cleaner though.</p>
<p>On to part 2!</p>
<h2 id="part-2">Part 2</h2>
<p>Okay, so the gist of part two is that we need to ALSO account for the
fuel required to transport all the fuel we add! Rather than using
calculus for this we're told to fudge the numbers and simply iterate on
our calculations until we hit a negative fuel value.</p>
<p>So to adapt our code for this twist we should split it up a bit!
First we've got a few optics for <strong>parsing</strong> the input,
those are boring and don't need any iteration. Next we've got the
pipeline part, we need to run this on <strong>each input
number</strong>, but will also need to run it on <strong>each
iteration</strong> of each input number. We'll need to somehow loop our
input through this pipeline.</p>
<p>As it turns out, an iteration like we need to do here is technically
an <strong>unfold</strong> (or <strong>anamorphism</strong> if you're
feeling eccentric). In optics-land unfolds can be represented as a
normal <code>Fold</code> which <strong>adds</strong> more elements when
it runs. Lensy folds can focus an arbitrary (possibly infinite) number
of focuses! Even better, there's already a fold in <code>lens</code>
which does basically what we need!</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">iterated ::</span> (a <span class="ot">-&gt;</span> a) <span class="ot">-&gt;</span> <span class="dt">Fold</span> a a</span></code></pre></div>
<p><code>iterated</code> takes an iteration function and, well,
iterates! Let's try it out on it's own first to see how it does its
thing:</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="dv">1</span> <span class="op">^..</span> taking <span class="dv">10</span> (iterated (<span class="op">+</span><span class="dv">1</span>))</span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>[<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>,<span class="dv">5</span>,<span class="dv">6</span>,<span class="dv">7</span>,<span class="dv">8</span>,<span class="dv">9</span>,<span class="dv">10</span>]</span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span></span></code></pre></div>
<p>Notice that I have to limit it with <code>taking 10</code> or it'd go
on forever. So it definitely does what we expect! Notice also that it
also emits its first input without any iteration; so we see the
<code>1</code> appear unaffected in the output. This tripped me up at
first.</p>
<p>Okay, so we've got all our pieces, let's try patching them
together!</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">solve2 ::</span> <span class="dt">IO</span> ()</span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>solve2 <span class="ot">=</span>  <span class="kw">do</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>  input <span class="ot">&lt;-</span> <span class="fu">readFile</span> <span class="st">&quot;./src/Y2019/day01.txt&quot;</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>  <span class="fu">print</span></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">$</span> input</span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">&amp;</span> toListOf ( worded</span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a>               <span class="op">.</span> _Show</span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a>               <span class="op">.</span> taking <span class="dv">20</span> (iterated calculateRequiredFuel)</span>
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a>               )</span>
<span id="cb10-10"><a href="#cb10-10" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb10-11"><a href="#cb10-11" aria-hidden="true" tabindex="-1"></a><span class="ot">    calculateRequiredFuel ::</span> <span class="dt">Double</span> <span class="ot">-&gt;</span> <span class="dt">Double</span></span>
<span id="cb10-12"><a href="#cb10-12" aria-hidden="true" tabindex="-1"></a>    calculateRequiredFuel <span class="ot">=</span> (<span class="fu">fromIntegral</span> <span class="op">.</span> <span class="fu">subtract</span> <span class="dv">2</span> <span class="op">.</span> <span class="fu">floor</span> <span class="op">@</span><span class="dt">Double</span> <span class="op">@</span><span class="dt">Int</span> <span class="op">.</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>
<span id="cb10-14"><a href="#cb10-14" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> solve2</span>
<span id="cb10-15"><a href="#cb10-15" aria-hidden="true" tabindex="-1"></a>[<span class="fl">76542.0</span>,<span class="fl">25512.0</span>,<span class="fl">8502.0</span>,<span class="fl">2832.0</span>,<span class="fl">942.0</span>,<span class="fl">312.0</span>,<span class="fl">102.0</span>,<span class="fl">32.0</span>,<span class="fl">8.0</span>,<span class="fl">0.0</span>,<span class="op">-</span><span class="fl">2.0</span>,<span class="op">-</span><span class="fl">3.0</span>,<span class="op">-</span><span class="fl">3.0</span></span>
<span id="cb10-16"><a href="#cb10-16" aria-hidden="true" tabindex="-1"></a><span class="op">...</span><span class="fl">79222.0</span>,<span class="fl">26405.0</span>,<span class="fl">8799.0</span>,<span class="fl">2931.0</span><span class="op">...</span>]</span></code></pre></div>
<p>I've limited our iteration again here while we're still figuring
things out, I also switched back to <code>toListOf</code> so we can see
what's happening clearly. I also moved the fuel calculations into a
single pure function, and added a <code>fromIntegral</code> so we can go
from <code>Double -&gt; Double</code> as is required by
<code>iterated</code>.</p>
<p>In the output we can see the fuel numbers getting smaller on each
iteration, until they eventually go negative (just like the puzzle
predicted). Eventually we finish our 20 iterations and the fold moves
onto the next input so we can see the numbers jump back up again as a
new iteration starts.</p>
<p>The puzzle states we can ignore everything past the point where
numbers go negative, so we can stop iterating at that point. That's
pretty easy to do using the higher-order optic <code>takingWhile</code>;
it accepts a predicate and <strong>another optic</strong> and will
consume elements from the other optic until the predicate fails, at
which point it will yield no more elements. In our case we can use it to
consume from each iteration until it hits a negative number, then move
on to the next iteration.</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">solve2 ::</span> <span class="dt">IO</span> ()</span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>solve2 <span class="ot">=</span>  <span class="kw">do</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>  input <span class="ot">&lt;-</span> <span class="fu">readFile</span> <span class="st">&quot;./src/Y2019/day01.txt&quot;</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>  <span class="fu">print</span> <span class="op">$</span> </span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>    input <span class="op">&amp;</span> toListOf </span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>            ( worded</span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a>            <span class="op">.</span> _Show</span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a>            <span class="op">.</span> takingWhile (<span class="op">&gt;</span><span class="dv">0</span>) (iterated calculateRequiredFuel)</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>
<span id="cb11-11"><a href="#cb11-11" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> solve2</span>
<span id="cb11-12"><a href="#cb11-12" aria-hidden="true" tabindex="-1"></a>[<span class="fl">76542.0</span>,<span class="fl">25512.0</span>,<span class="fl">8502.0</span>,<span class="fl">2832.0</span>,<span class="fl">942.0</span>,<span class="fl">312.0</span>,<span class="fl">102.0</span>,<span class="fl">32.0</span>,<span class="fl">8.0</span></span>
<span id="cb11-13"><a href="#cb11-13" aria-hidden="true" tabindex="-1"></a>,<span class="fl">97993.0</span>,<span class="fl">32662.0</span>,<span class="fl">10885.0</span>,<span class="fl">3626.0</span>,<span class="fl">1206.0</span>,<span class="fl">400.0</span>,<span class="fl">131.0</span>,<span class="fl">41.0</span>,<span class="fl">11.0</span><span class="op">...</span>]</span></code></pre></div>
<p>We don't need the <code>taking 20</code> limiter anymore since now we
stop when we hit <code>0</code> or below. In this case we technically
filter out an actual <code>0</code>; but since <code>0</code> has no
effect on a <code>sum</code> it's totally fine.</p>
<p>Okay, we're really close! On my first try I summed up all these
numbers and got the wrong answer! As I drew attention to earlier, when
we use <code>iterated</code> it passes through the original value as
well. We don't want the weight of our module in our final sum, so we
need to remove the <strong>first</strong> element from each set of
iterations. I'll use ANOTHER higher-order optic to wrap our iteration
optic, dropping the first output from each iteration:</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">solve2 ::</span> <span class="dt">IO</span> ()</span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>solve2 <span class="ot">=</span>  <span class="kw">do</span></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>  input <span class="ot">&lt;-</span> <span class="fu">readFile</span> <span class="st">&quot;./src/Y2019/day01.txt&quot;</span></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>  <span class="fu">print</span> <span class="op">$</span> </span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a>    input <span class="op">&amp;</span> sumOf </span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a>            ( worded</span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a>            <span class="op">.</span> _Show</span>
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a>            <span class="op">.</span> takingWhile (<span class="op">&gt;</span><span class="dv">0</span>) (dropping <span class="dv">1</span> (iterated calculateRequiredFuel))</span>
<span id="cb12-9"><a href="#cb12-9" aria-hidden="true" tabindex="-1"></a>            )</span>
<span id="cb12-10"><a href="#cb12-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-11"><a href="#cb12-11" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> solve2</span>
<span id="cb12-12"><a href="#cb12-12" aria-hidden="true" tabindex="-1"></a><span class="fl">4728317.0</span></span></code></pre></div>
<p>Great! That's the right answer!</p>
<p>It depends on how you like to read your optics, but I think the
multiple nested higher-order-optics is a bit messy, we can re-arrange it
to use fewer brackets like this; but it really depends on which you find
more readable:</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">solve2 ::</span> <span class="dt">IO</span> ()</span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>solve2 <span class="ot">=</span>  <span class="kw">do</span></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a>  input <span class="ot">&lt;-</span> <span class="fu">readFile</span> <span class="st">&quot;./src/Y2019/day01.txt&quot;</span></span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>  <span class="fu">print</span></span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">$</span> input</span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">&amp;</span> sumOf (worded</span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a>             <span class="op">.</span> _Show</span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a>             <span class="op">.</span> (takingWhile (<span class="op">&gt;</span> <span class="dv">0</span>) <span class="op">.</span> dropping <span class="dv">1</span> <span class="op">.</span> iterated) calculateRequiredFuel</span>
<span id="cb13-9"><a href="#cb13-9" aria-hidden="true" tabindex="-1"></a>            )</span></code></pre></div>
<p>That'll do it!</p>
<p>Once you get comfortable with how folds nest inside paths of optics,
and how to use higher-order folds (spoilers: there's a whole chapter on
this in my book launching later this month: <a
href="https://leanpub.com/optics-by-example/">Optics By Example</a>),
then we can solve this problem very naturally with optics! I hope some
of the other problems work out just as well.</p>
<p>See you again soon!</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Beating C with 80 lines of Haskell: wc</title>
      <link href="https://chrispenner.ca/posts/wc"/>
      <id>https://chrispenner.ca/posts/wc</id>
      <updated>2019-10-15T00:00:00Z</updated>
      <summary>An exploration into high-performance Haskell by cloning the wc utility</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/words.jpg" alt="Beating C with 80 lines of Haskell: wc">
              <p>Despite the click-bait title I hope you'll find this post generally
illuminating, or at the very least a bit of fun! This article makes no
claims that Haskell is "better" than C, nor does it make claims about
the respective value of either language, or either implementation. It's
simply an exploration into high-performance Haskell, with a few fun
tricks and hacks along the way.</p>
<p>You can find source code for this post <a
href="https://github.com/ChrisPenner/wc">here</a>.</p>
<p>For reference, I'm using the Mac's version of <code>wc</code>; you
can find <a
href="https://opensource.apple.com/source/text_cmds/text_cmds-68/wc/wc.c.auto.html">reference
source code here</a>. Yes, there are faster <code>wc</code>
implementations out there.</p>
<p>The challenge is to build a <em>faster</em> clone of the
hand-optimized C implementation of the <code>wc</code> utility in our
favourite high-level garbage-collected runtime-based language: Haskell!
Sounds simple enough right?</p>
<p>Here's the criteria we'll be considering as we go along:</p>
<ul>
<li>Correctness: Should return identical character, word, and line
counts as <code>wc</code> on the test files.</li>
<li>Speed (wall-clock-time): How do we compare to the execution time of
<code>wc</code>?</li>
<li>Max Resident Memory: What's the peak of our memory usage? Is our
memory usage constant, linear, or otherwise?</li>
</ul>
<p>Those are the main things we need to worry about.</p>
<p>Let's dive in.</p>
<h2 id="the-dumbest-thing-that-could-possibly-work">The dumbest thing
that could possibly work</h2>
<p>As always, we should start by just trying the dumbest possible thing
and see how it goes. We can build up from there. What's the dumbest way
to count characters, lines, and words in Haskell? Well, we could read
the file, then run the functions
<code>length</code>,<code>length . words</code>, and
<code>length . lines</code> to get our counts!</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">stupid ::</span> <span class="dt">FilePath</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> (<span class="dt">Int</span>, <span class="dt">Int</span>, <span class="dt">Int</span>)</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>stupid fp <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>    contents <span class="ot">&lt;-</span> <span class="fu">readFile</span> fp</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>    <span class="fu">return</span> (<span class="fu">length</span> s, <span class="fu">length</span> (<span class="fu">words</span> s), <span class="fu">length</span> (<span class="fu">lines</span> s))</span></code></pre></div>
<p>Amazingly enough, this actually DOES work, and gets us the same
answers as <code>wc</code>, IF you're willing to wait for it... I got
sick of waiting for it to finish on my large test file (it was taking
more than a few minutes), but on a smaller test file (90 MB) got the
following results:</p>
<p>90 MB test file:</p>
<table>
<thead>
<tr class="header">
<th></th>
<th>wc</th>
<th>stupid-wc</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>time</td>
<td>0.37s</td>
<td>17.07s</td>
</tr>
<tr class="even">
<td>max mem.</td>
<td>1.86 MB</td>
<td>2403 MB</td>
</tr>
</tbody>
</table>
<p>Yikes... Needless to say there's some room for improvement...</p>
<h2 id="being-slightly-less-dumb">Being slightly less dumb</h2>
<p>Let's think about why this is doing so poorly; the first thing that
comes to mind is that we're iterating through the contents of the file 3
separate times! This also means GHC can't garbage collect our list as we
iterate through it since we're still using it in other places. The fact
that we're keeping every character of the file in a linked list helps
explain the 2.4 GB of memory on a file that's only 90 MB! Ouch!</p>
<p>Okay, so that's REALLY not great. Let's see if we can get this down
to a SINGLE pass over the structure. We're accumulating 3 simple things,
so maybe we can process all three parts at once? When iterating through
a structure to get one final result I reach for folds!</p>
<p>It's pretty easy to use a fold to count characters or lines; the
character count always adds one to the total, the line count adds one
when the current character is a newline; but what about the word count?
We can't add one on every space character because consecutive spaces
doesn't count as a new word! We'll need to keep track of whether the
previous character was a space, and only add one to the counter whenever
we start a completely <strong>new</strong> word. That's not too tough to
do; we'll use <code>foldl'</code> from <code>Data.List</code> for our
implementation.</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">import</span> <span class="dt">Data.List</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Char</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="ot">simpleFold ::</span> <span class="dt">FilePath</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> (<span class="dt">Int</span>, <span class="dt">Int</span>, <span class="dt">Int</span>)</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>simpleFold fp <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>    countFile <span class="op">&lt;$&gt;</span> <span class="fu">readFile</span> fp</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a><span class="ot">countFile ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> (<span class="dt">Int</span>, <span class="dt">Int</span>, <span class="dt">Int</span>)</span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>countFile s <span class="ot">=</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> (cs, ws, ls, _) <span class="ot">=</span> foldl&#39; go (<span class="dv">0</span>, <span class="dv">0</span>, <span class="dv">0</span>, <span class="dt">False</span>) s</span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a>     <span class="kw">in</span> (cs, ws, ls)</span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a><span class="ot">    go ::</span> (<span class="dt">Int</span>, <span class="dt">Int</span>, <span class="dt">Int</span>, <span class="dt">Bool</span>) <span class="ot">-&gt;</span> <span class="dt">Char</span> <span class="ot">-&gt;</span> (<span class="dt">Int</span>, <span class="dt">Int</span>, <span class="dt">Int</span>, <span class="dt">Bool</span>)</span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a>    go (cs, ws, ls, wasSpace) c <span class="ot">=</span></span>
<span id="cb2-15"><a href="#cb2-15" aria-hidden="true" tabindex="-1"></a>        <span class="kw">let</span> addLine <span class="op">|</span> c <span class="op">==</span> <span class="ch">&#39;\n&#39;</span> <span class="ot">=</span> <span class="dv">1</span></span>
<span id="cb2-16"><a href="#cb2-16" aria-hidden="true" tabindex="-1"></a>                    <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="dv">0</span></span>
<span id="cb2-17"><a href="#cb2-17" aria-hidden="true" tabindex="-1"></a>            addWord <span class="op">|</span> wasSpace <span class="ot">=</span> <span class="dv">0</span></span>
<span id="cb2-18"><a href="#cb2-18" aria-hidden="true" tabindex="-1"></a>                    <span class="op">|</span> <span class="fu">isSpace</span> c <span class="ot">=</span> <span class="dv">1</span></span>
<span id="cb2-19"><a href="#cb2-19" aria-hidden="true" tabindex="-1"></a>                    <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="dv">0</span></span>
<span id="cb2-20"><a href="#cb2-20" aria-hidden="true" tabindex="-1"></a>         <span class="kw">in</span> (cs <span class="op">+</span> <span class="dv">1</span>, ws <span class="op">+</span> addWord, ls <span class="op">+</span> addLine, <span class="fu">isSpace</span> c)</span></code></pre></div>
<p>Running this version we run into an even worse problem! The program
takes more than a few minutes and quickly spikes up to more than 3 GB of
memory! What's gone wrong? Well, we used the strict version of
<code>foldl</code> (indicated by the trailing tick <code>'</code>); BUT
it's only strict up to "Weak Head Normal Form" (WHNF), which means it'll
be strict in the <strong>structure</strong> of the tuple accumulator,
but not the actual values! That's annoying, because it means we're
building up a HUGE thunk of additions that we never fully evaluate until
we've finished iterating through the whole file! Sometimes laziness
sneaks in and bites us like this. This is the sort of memory leak that
can easily take down web-servers if you aren't careful!</p>
<p>90 MB test file:</p>
<table>
<thead>
<tr class="header">
<th></th>
<th>wc</th>
<th>simple-fold-wc</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>time</td>
<td>0.37s</td>
<td>longer than I want to wait</td>
</tr>
<tr class="even">
<td>max mem.</td>
<td>1.86 MB</td>
<td>&gt; 3 GB</td>
</tr>
</tbody>
</table>
<p>We can fix it by telling GHC to strictly evaluate the contents of the
tuple on ever iteration. An easy way to do that is with the
<code>BangPatterns</code> extension; it lets us use <code>!</code> in
our argument list to force evaluation on each run of the function.
Here's the new version of <code>go</code>:</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">{-# LANGUAGE BangPatterns #-}</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="op">...</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="ot">    go ::</span> (<span class="dt">Int</span>, <span class="dt">Int</span>, <span class="dt">Int</span>, <span class="dt">Bool</span>) <span class="ot">-&gt;</span> <span class="dt">Char</span> <span class="ot">-&gt;</span> (<span class="dt">Int</span>, <span class="dt">Int</span>, <span class="dt">Int</span>, <span class="dt">Bool</span>)</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>    go (<span class="op">!</span>cs, <span class="op">!</span>ws, <span class="op">!</span>ls, <span class="op">!</span>wasSpace) c <span class="ot">=</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>        <span class="kw">let</span> addLine <span class="op">|</span> c <span class="op">==</span> <span class="ch">&#39;\n&#39;</span> <span class="ot">=</span> <span class="dv">1</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>                    <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="dv">0</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>            addWord <span class="op">|</span> wasSpace <span class="ot">=</span> <span class="dv">0</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a>                    <span class="op">|</span> <span class="fu">isSpace</span> c <span class="ot">=</span> <span class="dv">1</span></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a>                    <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="dv">0</span></span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a>         <span class="kw">in</span> (cs <span class="op">+</span> <span class="dv">1</span>, ws <span class="op">+</span> addWord, ls <span class="op">+</span> addLine, <span class="fu">isSpace</span> c)</span></code></pre></div>
<p>That simple change speeds things up like <strong>CRAZY</strong>;
here's our new performance breakdown:</p>
<p>90 MB test file:</p>
<table>
<thead>
<tr class="header">
<th></th>
<th>wc</th>
<th>strict-fold-wc</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>time</td>
<td>0.37s</td>
<td>8.12s</td>
</tr>
<tr class="even">
<td>max mem.</td>
<td>1.86 MB</td>
<td>3.7 MB</td>
</tr>
</tbody>
</table>
<p>Okay; so we're doing WAY better on memory now, a few MBs of memory on
a 90 MB file means we must finally be streaming the file contents
properly! Even though laziness has already bitten us on this problem,
now that we've localized the laziness into the right places it provides
us with streaming for free! The streaming happens naturally because
<code>readFile</code> actually does <strong>lazy IO</strong>; which can
be a real nuisance sometimes for things like web servers since you're
never quite sure when the IO is happening, but in our case it gives us
much better memory residency.</p>
<h2 id="better-with-bytestrings">Better with ByteStrings</h2>
<p>We can probably stop worrying about memory for now, so we're back to
crunching for performance! One thing I can think to try there to switch
to using a ByteString rather than a String. Using a String means we're
implicitly decoding the file as we read it, which takes time, AND we
have the overhead of using a linked list for the whole thing, we can't
easily take advantage of batching or buffering our data as we read
it.</p>
<p>This change is actually laughably easy, the <code>bytestring</code>
package provides the module: <code>Data.ByteString.Lazy.Char8</code>,
which provides operations for working with Lazy ByteStrings as though
they were strings of characters, but with all the performance benefits
of ByteStrings. Note that it DOESN'T actually verify that each byte is a
valid Character, or do any decoding, so it's on us to make sure we're
passing it valid data. By default <code>wc</code> assumes its input is
ASCII, so I think we're safe to do the same. If our input is ASCII then
the functions in this module will behave sensibly.</p>
<p>Literally the only changes I need to make are to switch the
<code>Data.List</code> import to <code>Data.ByteString.Lazy.Char8</code>
and then switch the <code>readFile</code> and <code>foldl'</code>
functions to their ByteString versions:</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">import</span> <span class="dt">Data.Char</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Data.ByteString.Lazy.Char8</span> <span class="kw">as</span> <span class="dt">BS</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 class="ot">simpleFold ::</span> <span class="dt">FilePath</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> (<span class="dt">Int</span>, <span class="dt">Int</span>, <span class="dt">Int</span>)</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>simpleFold fp <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>    simpleFoldCountFile <span class="op">&lt;$&gt;</span> BS.readFile fp</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a><span class="ot">simpleFoldCountFile ::</span> <span class="dt">BS.ByteString</span> <span class="ot">-&gt;</span> (<span class="dt">Int</span>, <span class="dt">Int</span>, <span class="dt">Int</span>)</span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>simpleFoldCountFile s <span class="ot">=</span></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> (cs, ws, ls, _) <span class="ot">=</span> BS.foldl&#39; go (<span class="dv">0</span>, <span class="dv">0</span>, <span class="dv">0</span>, <span class="dt">False</span>) s</span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a>     <span class="kw">in</span> (cs, ws, ls)</span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a><span class="ot">    go ::</span> (<span class="dt">Int</span>, <span class="dt">Int</span>, <span class="dt">Int</span>, <span class="dt">Bool</span>) <span class="ot">-&gt;</span> <span class="dt">Char</span> <span class="ot">-&gt;</span> (<span class="dt">Int</span>, <span class="dt">Int</span>, <span class="dt">Int</span>, <span class="dt">Bool</span>)</span>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a>    go (<span class="op">!</span>cs, <span class="op">!</span>ws, <span class="op">!</span>ls, <span class="op">!</span>wasSpace) c <span class="ot">=</span></span>
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a>        <span class="kw">let</span> addLine <span class="op">|</span> c <span class="op">==</span> <span class="ch">&#39;\n&#39;</span> <span class="ot">=</span> <span class="dv">1</span></span>
<span id="cb4-16"><a href="#cb4-16" aria-hidden="true" tabindex="-1"></a>                    <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="dv">0</span></span>
<span id="cb4-17"><a href="#cb4-17" aria-hidden="true" tabindex="-1"></a>            addWord <span class="op">|</span> wasSpace <span class="ot">=</span> <span class="dv">0</span></span>
<span id="cb4-18"><a href="#cb4-18" aria-hidden="true" tabindex="-1"></a>                    <span class="op">|</span> <span class="fu">isSpace</span> c <span class="ot">=</span> <span class="dv">1</span></span>
<span id="cb4-19"><a href="#cb4-19" aria-hidden="true" tabindex="-1"></a>                    <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="dv">0</span></span>
<span id="cb4-20"><a href="#cb4-20" aria-hidden="true" tabindex="-1"></a>         <span class="kw">in</span> (cs <span class="op">+</span> <span class="dv">1</span>, ws <span class="op">+</span> addWord, ls <span class="op">+</span> addLine, <span class="fu">isSpace</span> c)</span></code></pre></div>
<p>This little change chops our time down by nearly half!</p>
<p>90 MB test file:</p>
<table>
<thead>
<tr class="header">
<th></th>
<th>wc</th>
<th>strict-fold-wc</th>
<th>bs-fold-wc</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>time</td>
<td>0.37s</td>
<td>8.12s</td>
<td>3.41s</td>
</tr>
<tr class="even">
<td>max mem.</td>
<td>1.86 MB</td>
<td>3.7 MB</td>
<td>5.48 MB</td>
</tr>
</tbody>
</table>
<p>So we're clearly still making some progress. Our memory usage has
increased slightly, but it still seems to be a constant overhead. We're
still orders of magnitude away from <code>wc</code> unfortunately; let's
see if there's anything else we could do.</p>
<h2 id="moving-to-monoids">Moving to Monoids</h2>
<p>At this point I feel like experimenting a little. Modern PC's tend to
have multiple cores, and it seems as though newer machines scale up the
number of cores moreso than their processor speed, so it would be
beneficial to take advantage of that.</p>
<p>Splitting up a computation like this isn't exactly trivial. In order
to use multiple cores we'll need to split up the job into pieces. In
theory this is easy, just split the file into chunks and give one chunk
to each core! As you think a bit deeper about it the problems start to
appear; combining character counts is pretty easy, we can just sum the
totals from each chunk. The same with line-counts, but word counts pose
a problem! What happens if we split in the middle of a word, or in the
middle of several consecutive spaces? In order to combine the word
counts we'd need to keep track of the starting and end state of each
chunk and be intelligent when we combine them together. That sounds like
a lot of book-keeping that I don't really want to do.</p>
<p>Monoids to the rescue! The associative laws of a Monoid mean that so
long as we can develop a lawful monoid it WILL work properly in spite of
this type of parallelism. That really just passes the buck down the line
though, is it possible to write a Monoid that can handle the
complexities of word-counting like this?</p>
<p>It sure is! It may not be immediately apparent how a monoid like this
works, but there's a class of counting problems that all fall into the
same category like this, and luckily for me I've worked on these before.
Basically we need to count the number of times a given invariant has
<strong>changed</strong> from the start to the end of a sequence. I've
generalized this class of monoid before, naming them <a
href="http://hackage.haskell.org/package/flux-monoid"><code>flux</code>
monoids</a>. What we need to do is count the number of times we change
from characters which ARE spaces to those which AREN'T spaces. We could
probably express this using the <code>Flux</code> monoid itself, but
since we need to be so careful about strictness and performance I'm
going to define a bespoke version of the Flux monoid for our purposes.
Check this out:</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="kw">data</span> <span class="dt">CharType</span> <span class="ot">=</span> <span class="dt">IsSpace</span> <span class="op">|</span> <span class="dt">NotSpace</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">deriving</span> <span class="dt">Show</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Flux</span> <span class="ot">=</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Flux</span> <span class="op">!</span><span class="dt">CharType</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a>         <span class="ot">{-# UNPACK #-}</span> <span class="op">!</span><span class="dt">Int</span></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>         <span class="op">!</span><span class="dt">CharType</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>    <span class="op">|</span> <span class="dt">Unknown</span></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a>    <span class="kw">deriving</span> <span class="dt">Show</span></span></code></pre></div>
<p>We need these types only for the word-counting part of our
solution.</p>
<p>The <code>CharType</code> says whether a given character is
considered a space or not; then the <code>Flux</code> type represents a
chunk of text, storing fields for whether the left-most character is a
space, how many words are in the full block of text, and whether the
right-most character is a space. We don't actually keep the text in the
structure since we don't need it for this problem. I've
<code>UNPACK</code>ed the <code>Int</code> and made all the fields
strict to ensure we won't run into the same problems we did with lazy
tuples earlier. Using a strict data type means I don't need to use
BangPatterns in my computations.</p>
<p>Next we need a semigroup and Monoid instance for this type!</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="kw">instance</span> <span class="dt">Semigroup</span> <span class="dt">Flux</span> <span class="kw">where</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Unknown</span> <span class="op">&lt;&gt;</span> x <span class="ot">=</span> x</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>  x <span class="op">&lt;&gt;</span> <span class="dt">Unknown</span> <span class="ot">=</span> x</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Flux</span> l n <span class="dt">NotSpace</span> <span class="op">&lt;&gt;</span> <span class="dt">Flux</span> <span class="dt">NotSpace</span> n&#39; r <span class="ot">=</span> <span class="dt">Flux</span> l (n <span class="op">+</span> n&#39; <span class="op">-</span> <span class="dv">1</span>) r</span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Flux</span> l n _ <span class="op">&lt;&gt;</span> <span class="dt">Flux</span> _ n&#39; r <span class="ot">=</span> <span class="dt">Flux</span> l (n <span class="op">+</span> n&#39;) r</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="kw">instance</span> <span class="dt">Monoid</span> <span class="dt">Flux</span> <span class="kw">where</span></span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a>  <span class="fu">mempty</span> <span class="ot">=</span> <span class="dt">Unknown</span></span></code></pre></div>
<p>The <code>Unknown</code> constructor is there to represent a Monoidal
identity, we could actually leave it out and use <code>Maybe</code> to
promote our Semigroup into a Monoid, but <code>Maybe</code> introduces
unwanted laziness into our semigroup append! I just define it as part of
the type for simplicity.</p>
<p>The <code>(&lt;&gt;)</code> operation we define checks whether the
join-point of our two text blocks happens in the middle of a word, if it
does then we must have counted the start and end of the same word
separately, so we subtract one when we add the word totals to make it
all balance out.</p>
<p>Lastly we need a way to build a <code>Flux</code> object from
individual characters.</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">flux ::</span> <span class="dt">Char</span> <span class="ot">-&gt;</span> <span class="dt">Flux</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>flux c <span class="op">|</span> <span class="fu">isSpace</span> c <span class="ot">=</span> <span class="dt">Flux</span> <span class="dt">IsSpace</span> <span class="dv">0</span> <span class="dt">IsSpace</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>       <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="dt">Flux</span> <span class="dt">NotSpace</span> <span class="dv">1</span> <span class="dt">NotSpace</span></span></code></pre></div>
<p>This is simple enough, we count non-space characters as 'words' which
start and end with non-space charactes and for spaces have an empty word
count surrounded on both sides with space chars.</p>
<p>It may not be immediately clear, but that's all we need to count
words monoidally!</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="fu">foldMap</span> flux <span class="st">&quot;testing one two three&quot;</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Flux</span> <span class="dt">NotSpace</span> <span class="dv">4</span> <span class="dt">NotSpace</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="fu">foldMap</span> flux <span class="st">&quot;testing on&quot;</span> <span class="op">&lt;&gt;</span> <span class="fu">foldMap</span> flux <span class="st">&quot;e two three&quot;</span></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Flux</span> <span class="dt">NotSpace</span> <span class="dv">4</span> <span class="dt">NotSpace</span></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="op">&gt;&gt;&gt;</span> <span class="fu">foldMap</span> flux <span class="st">&quot;testing one &quot;</span> <span class="op">&lt;&gt;</span> <span class="fu">foldMap</span> flux <span class="st">&quot; two three&quot;</span></span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a><span class="dt">Flux</span> <span class="dt">NotSpace</span> <span class="dv">4</span> <span class="dt">NotSpace</span></span></code></pre></div>
<p>Looks like it's working fine!</p>
<p>We've got the word count part covered, now we need the Monoidal
version of the char count and line count. This is a snap to build:</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">data</span> <span class="dt">Counts</span> <span class="ot">=</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Counts</span> {<span class="ot"> charCount ::</span> <span class="ot">{-# UNPACK #-}</span> <span class="op">!</span><span class="dt">Int</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="ot"> wordCount ::</span>  <span class="op">!</span><span class="dt">Flux</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>           ,<span class="ot"> lineCount ::</span> <span class="ot">{-# UNPACK #-}</span> <span class="op">!</span><span class="dt">Int</span></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a>           }</span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">deriving</span> (<span class="dt">Show</span>)</span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Semigroup</span> <span class="dt">Counts</span> <span class="kw">where</span></span>
<span id="cb9-10"><a href="#cb9-10" aria-hidden="true" tabindex="-1"></a>  (<span class="dt">Counts</span> a b c) <span class="op">&lt;&gt;</span> (<span class="dt">Counts</span> a&#39; b&#39; c&#39;) <span class="ot">=</span> <span class="dt">Counts</span> (a <span class="op">+</span> a&#39;) (b <span class="op">&lt;&gt;</span> b&#39;) (c <span class="op">+</span> c&#39;)</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 class="kw">instance</span> <span class="dt">Monoid</span> <span class="dt">Counts</span> <span class="kw">where</span></span>
<span id="cb9-13"><a href="#cb9-13" aria-hidden="true" tabindex="-1"></a>  <span class="fu">mempty</span> <span class="ot">=</span> <span class="dt">Counts</span> <span class="dv">0</span> <span class="fu">mempty</span> <span class="dv">0</span></span></code></pre></div>
<p>No problem! Similarly we'll need a way to turn a single char into a
<code>Counts</code> object:</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">countChar ::</span> <span class="dt">Char</span> <span class="ot">-&gt;</span> <span class="dt">Counts</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>countChar c <span class="ot">=</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Counts</span> { charCount <span class="ot">=</span> <span class="dv">1</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>           , wordCount <span class="ot">=</span> flux c</span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>           , lineCount <span class="ot">=</span> <span class="kw">if</span> (c <span class="op">==</span> <span class="ch">&#39;\n&#39;</span>) <span class="kw">then</span> <span class="dv">1</span> <span class="kw">else</span> <span class="dv">0</span></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a>           }</span></code></pre></div>
<p>Let's try that out too:</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="op">&gt;&gt;&gt;</span> <span class="fu">foldMap</span> countChar <span class="st">&quot;one two\nthree&quot;</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Counts</span> {charCount <span class="ot">=</span> <span class="dv">13</span>, wordCount <span class="ot">=</span> <span class="dt">Flux</span> <span class="dt">NotSpace</span> <span class="dv">3</span> <span class="dt">NotSpace</span>, lineCount <span class="ot">=</span> <span class="dv">1</span>}</span></code></pre></div>
<p>Looks good to me! Experiment to your heart's content to convince
yourself it's a lawful Monoid.</p>
<p>With a lawful Monoid we no longer need to worry about how we split
our file up!</p>
<p>Before going any further, let's try using our monoid with our
existing code and make sure it gets the same answers.</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">module</span> <span class="dt">MonoidBSFold</span> <span class="kw">where</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="kw">import</span> <span class="dt">Data.Char</span></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Data.ByteString.Lazy.Char8</span> <span class="kw">as</span> <span class="dt">BS</span></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="ot">monoidBSFold ::</span> <span class="dt">FilePath</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> <span class="dt">Counts</span></span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a>monoidBSFold paths <span class="ot">=</span> monoidFoldFile <span class="op">&lt;$&gt;</span> BS.readFile fp</span>
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-9"><a href="#cb12-9" aria-hidden="true" tabindex="-1"></a><span class="ot">monoidFoldFile ::</span> <span class="dt">BS.ByteString</span> <span class="ot">-&gt;</span> <span class="dt">Counts</span></span>
<span id="cb12-10"><a href="#cb12-10" aria-hidden="true" tabindex="-1"></a>monoidFoldFile <span class="ot">=</span> BS.foldl&#39; (\a b <span class="ot">-&gt;</span> a <span class="op">&lt;&gt;</span> countChar b) <span class="fu">mempty</span></span></code></pre></div>
<p>We've moved some complexity into our <code>Counts</code> type, which
allows us to really simplify our implementation here. This is nice in
general because it's much easier to test a single data-type rather than
testing EVERYWHERE that we do this fold.</p>
<p>As a side benefit, this change has <em>somehow</em> sped things up
even more!</p>
<p>We're in the ballpark now!</p>
<p>90 MB test file:</p>
<table>
<thead>
<tr class="header">
<th></th>
<th>wc</th>
<th>strict-bs-fold-wc</th>
<th>monoid-bs-fold-wc</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>time</td>
<td>0.37s</td>
<td>3.41s</td>
<td>1.94s</td>
</tr>
<tr class="even">
<td>max mem.</td>
<td>1.86 MB</td>
<td>5.48 MB</td>
<td>3.83 MB</td>
</tr>
</tbody>
</table>
<p>We've knocked off a good chunk of time AND memory with this change...
I'll admit I have no idea WHY, but I won't look a gift-horse in the
mouth. It's possible that by using a fully strict data structure we've
strictified some laziness that snuck in somewhere; but I'm really not
sure. If you can see what happened please let me know!</p>
<p><strong>UPDATE</strong>: <strong>guibou</strong> pointed out to me
that our <code>Flux</code> and <code>Counts</code> type use
<code>UNPACK</code> pragmas, whereas beforehand we used a regular ol'
tuple. Apparently GHC is sometimes smart enough to UNPACK tuples, but
it's likely that wasn't happening in this case. By
<code>UNPACK</code>ing we can save a few pointer indirections and use
less memory!</p>
<h2 id="inlining-away">Inlining away!</h2>
<p>Next in our quest, I think I'll inline some definitions! Why? Because
that's just what you do when you want performance! We can use the
<code>INLINE</code> pragma to tell GHC that our function is performance
critical and it'll inline it for us; possibly triggering further
optimizations down the line.</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">monoidBSFold ::</span> <span class="dt">FilePath</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> <span class="dt">Counts</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>monoidBSFold paths <span class="ot">=</span> monoidBSFoldFile <span class="op">&lt;$&gt;</span> BS.readFile fp</span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# INLINE monoidBSFold #-}</span></span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a><span class="ot">monoidBSFoldFile ::</span> <span class="dt">BS.ByteString</span> <span class="ot">-&gt;</span> <span class="dt">Counts</span></span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a>monoidBSFoldFile <span class="ot">=</span> BS.foldl&#39; (\a b <span class="ot">-&gt;</span> a <span class="op">&lt;&gt;</span> countChar b) <span class="fu">mempty</span></span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# INLINE monoidBSFoldFile #-}</span></span></code></pre></div>
<p>I also went ahead and added INLINE's to our <code>countChar</code>
and <code>flux</code> functions. Let's see if it made any
difference:</p>
<p>90 MB test file:</p>
<table>
<thead>
<tr class="header">
<th></th>
<th>original</th>
<th>inlined</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>time</td>
<td>1.94s</td>
<td>0.47s</td>
</tr>
<tr class="even">
<td>max mem.</td>
<td>3.83 MB</td>
<td>4.35 MB</td>
</tr>
</tbody>
</table>
<p>Interestingly it seems to have slashed our time down by 75%! I'm
really not sure if this is a fluke, or if we stumbled upon something
lucky here; but I'll take it! It's bumped up our memory usage by a
smidge; but not enough for me to worry.</p>
<p>Here's how we compare to the C version now:</p>
<p>90 MB test file:</p>
<table>
<thead>
<tr class="header">
<th></th>
<th>wc</th>
<th>inlined-monoid-bs-wc</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>time</td>
<td>0.37s</td>
<td>0.47s</td>
</tr>
<tr class="even">
<td>max mem.</td>
<td>1.86 MB</td>
<td>4.35 MB</td>
</tr>
</tbody>
</table>
<p>At this point we're pretty close to parity with <code>wc</code>; but
we're looking at sub-second times, so I'm going to bump up the size of
our test file and run a few times to see if we can learn anything
new.</p>
<p>I bumped up to a 543 MB plaintext file and ran it a few times in a
row to get the caches warmed up. This is clearly important because my
times dropped a full 33% after a few runs. I understand my testing
method isn't exactly "scientific", but it gives us a good estimate of
how we're doing. Anyways, on the much larger file here's how we
perform:</p>
<p>543 MB test file:</p>
<table>
<thead>
<tr class="header">
<th></th>
<th>wc</th>
<th>inlined-monoid-bs-wc</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>time</td>
<td>2.06s</td>
<td>2.73s</td>
</tr>
<tr class="even">
<td>max mem.</td>
<td>1.85 MB</td>
<td>3.97 MB</td>
</tr>
</tbody>
</table>
<p>From here we can see that we're actually getting pretty close!
Considering we've cloned <code>wc</code> in a high-level garbage
collected language in around 80 lines of code I'd say we're doing
alright!</p>
<h2 id="using-our-cores">Using our Cores</h2>
<p>One may not expect parallelizing to multiple cores to do a whole lot
since presumably this whole operation is IO bounded, but I'm going to do
it anyways because I'm stubborn and bored.</p>
<p>We've already expressed our problem as a Monoid, which means it
should be pretty trivial to split up the computation! The trick here is
actually in reading in our data. If we try to read in all the data and
THEN split it into chunks we'll have to load the whole file into memory
at once, which is going to be REALLY bad for our memory residency, and
will probably hurt our performance too! We could try
<strong>streaming</strong> it in and splitting it that way, but then we
have to <strong>process</strong> the first chunk before we get to the
second split; and hopefully you can see the problem there. Instead I'm
going to spin up a separate thread for each core we have then open a
separate file handle in each of those threads. Then I'll seek each
Handle to disjoint offsets and perform our operation on each
non-overlapping piece of the file that way before combining the counts
together.</p>
<p>Here's the whole thing, did I mention how much I
<strong>love</strong> writing concurrent code in Haskell?</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="kw">import</span> <span class="dt">Types</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Monad</span></span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Traversable</span></span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Bits</span></span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">GHC.Conc</span> (numCapabilities)</span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Concurrent.Async</span></span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Foldable</span></span>
<span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">System.IO</span></span>
<span id="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">System.Posix.Files</span></span>
<span id="cb14-10"><a href="#cb14-10" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Data.ByteString.Lazy.Char8</span> <span class="kw">as</span> <span class="dt">BL</span></span>
<span id="cb14-11"><a href="#cb14-11" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.ByteString.Internal</span> (c2w)</span>
<span id="cb14-12"><a href="#cb14-12" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">GHC.IO.Handle</span></span>
<span id="cb14-13"><a href="#cb14-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-14"><a href="#cb14-14" aria-hidden="true" tabindex="-1"></a><span class="ot">multiCoreCount ::</span> <span class="dt">FilePath</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> <span class="dt">Counts</span></span>
<span id="cb14-15"><a href="#cb14-15" aria-hidden="true" tabindex="-1"></a>multiCoreCount fp <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb14-16"><a href="#cb14-16" aria-hidden="true" tabindex="-1"></a>    <span class="fu">putStrLn</span> (<span class="st">&quot;Using available cores: &quot;</span> <span class="op">&lt;&gt;</span> <span class="fu">show</span> numCapabilities)</span>
<span id="cb14-17"><a href="#cb14-17" aria-hidden="true" tabindex="-1"></a>    size <span class="ot">&lt;-</span> <span class="fu">fromIntegral</span> <span class="op">.</span> fileSize <span class="op">&lt;$&gt;</span> getFileStatus fp</span>
<span id="cb14-18"><a href="#cb14-18" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> chunkSize <span class="ot">=</span> <span class="fu">fromIntegral</span> (size <span class="ot">`div`</span> numCapabilities)</span>
<span id="cb14-19"><a href="#cb14-19" aria-hidden="true" tabindex="-1"></a>    fold <span class="op">&lt;$!&gt;</span> (forConcurrently [<span class="dv">0</span><span class="op">..</span>numCapabilities<span class="op">-</span><span class="dv">1</span>] <span class="op">$</span> \n <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb14-20"><a href="#cb14-20" aria-hidden="true" tabindex="-1"></a>        <span class="co">-- Take all remaining bytes on the last capability due to integer division anomolies</span></span>
<span id="cb14-21"><a href="#cb14-21" aria-hidden="true" tabindex="-1"></a>        <span class="kw">let</span> limiter <span class="ot">=</span> <span class="kw">if</span> n <span class="op">==</span> numCapabilities <span class="op">-</span> <span class="dv">1</span></span>
<span id="cb14-22"><a href="#cb14-22" aria-hidden="true" tabindex="-1"></a>                         <span class="kw">then</span> <span class="fu">id</span></span>
<span id="cb14-23"><a href="#cb14-23" aria-hidden="true" tabindex="-1"></a>                         <span class="kw">else</span> BL.take (<span class="fu">fromIntegral</span> chunkSize)</span>
<span id="cb14-24"><a href="#cb14-24" aria-hidden="true" tabindex="-1"></a>        <span class="kw">let</span> offset <span class="ot">=</span> <span class="fu">fromIntegral</span> (n <span class="op">*</span> chunkSize)</span>
<span id="cb14-25"><a href="#cb14-25" aria-hidden="true" tabindex="-1"></a>        fileHandle <span class="ot">&lt;-</span> openBinaryFile fp <span class="dt">ReadMode</span></span>
<span id="cb14-26"><a href="#cb14-26" aria-hidden="true" tabindex="-1"></a>        hSeek fileHandle <span class="dt">AbsoluteSeek</span> offset</span>
<span id="cb14-27"><a href="#cb14-27" aria-hidden="true" tabindex="-1"></a>        countBytes <span class="op">.</span> limiter <span class="op">&lt;$!&gt;</span> BL.hGetContents fileHandle)</span>
<span id="cb14-28"><a href="#cb14-28" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# INLINE multiCoreCount #-}</span></span>
<span id="cb14-29"><a href="#cb14-29" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-30"><a href="#cb14-30" aria-hidden="true" tabindex="-1"></a><span class="ot">countBytes ::</span> <span class="dt">BL.ByteString</span> <span class="ot">-&gt;</span> <span class="dt">Counts</span></span>
<span id="cb14-31"><a href="#cb14-31" aria-hidden="true" tabindex="-1"></a>countBytes <span class="ot">=</span> BL.foldl&#39; (\a b <span class="ot">-&gt;</span> a <span class="op">&lt;&gt;</span> countChar b) <span class="fu">mempty</span></span>
<span id="cb14-32"><a href="#cb14-32" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# INLINE countBytes #-}</span></span></code></pre></div>
<p>There's a lot going on here, so I'll break it down as best I can.</p>
<p>We can import the number of "capabilities" available to our program
(i.e. the number of cores we have access to) from <code>GHC.Conc</code>.
From there, we run a fileStat on the file we want to count to get the
number of bytes in the file. From there, we use integer division to
determine how many bytes should be handled by each individual core. The
integer division rounds the result down, so we'll have to be careful to
pick up the bytes that were possibly left out later on. We then use
<code>forConcurrently</code> from <code>Control.Concurrent.Async</code>
to run a separate thread for each of our capabilities.</p>
<p>Inside each thread we check whether we're inside the thread which
handls the LAST chunk of the file, if we are we should read until the
EOF to pick up the leftover bytes from the earlier rounding error,
otherwise we want to limit ourselves to processing only
<code>chunkSize</code> bytes. Then we can calculate our offset into the
file by multiplying the chunk size by our thread number. We open a
binary file handle and use <code>hSeek</code> to move our handle to the
starting offset for our thread. From this point we can simply read our
allocated number of bytes and fold them down using the same logic as
before. After we've handled each of the threads, we'll use a simple
<code>fold</code> to combine the counts of each chunk into a total
count.</p>
<p>We use <code>&lt;$!&gt;</code> in a few spots to add additional
strictness since we want to ensure that the folding operations happen
within each thread, instead of after the threads have been joined. I
might go a little overboard on strictness annotations, but it's easier
to add too many than it is to track down the places we've accidentally
missed them.</p>
<p>Let's take this puppy out for a spin!</p>
<p>After warming up the caches I ran each of them a few times on my 4
core 2013 Macbook Pro with an SSD, and averaged the results
together:</p>
<p>543 MB test file:</p>
<table>
<thead>
<tr class="header">
<th></th>
<th>wc</th>
<th>multicore-wc</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>time</td>
<td>2.07s</td>
<td>1.23s</td>
</tr>
<tr class="even">
<td>max mem.</td>
<td>1.87 MB</td>
<td>7.06 MB</td>
</tr>
</tbody>
</table>
<p>It seems to make a pretty big difference! We're actually going FASTER
than some C code that's been hand optimized for a few decades. These
results are best taken with a hefty grain of salt; it's really hard to
tell what sort of caching is going on here. There are probably mutliple
layers of disk caching happening. Maybe the multithreading only helps
when reading files from a cache?</p>
<p>I did a bit of skimming and it seems that SOME storage devices might
experience a speed-up from doing file reads in parallel, some may
actually slow down. Your mileage may vary. If anyone's an expert on SSDs
I'd love to hear from you on this one. Regardless I'm still pretty happy
with the results.</p>
<p><strong>UPDATE</strong>: Turns out some folks out there ARE experts
on SSDs! Paul Tanner wrote me an email explaining that modern NVME
drives can typically benefit from this sort of parallelism, so long as
we're not accessing the same block (and here we're not). Unfortunately,
my ancient macbook doesn't have one, but on the plus side that means
this code might actually run even FASTER on a modern drive. Thanks
Paul!</p>
<p>In case you're wondering, the actual <code>User</code> time for our
program comes in at <code>4.22s</code> (which is split across the 4
cores), meaning our parallel program is less efficient than the simple
version in terms of actual processor cycles, but the ability to use
multiple cores gets the "real" wall-clock time down.</p>
<h2 id="handling-unicode">Handling Unicode</h2>
<p>There's something we've been avoiding so far, we've assumed every
file is simple ASCII! That's really not the way the world works. A lot
of documents are encoded in UTF-8 these days; which turns out to be
identical to an ASCII file IFF the file only contains valid ASCII
characters, however if those crazy pre-teens put some Emoji in there
then it's going to screw everything up.</p>
<p>The problem is two-fold; firstly we currently count BYTES not
CHARACTERS, because in ASCII-land they're semantically the same. With
our current code, if we come across a UTF-8 encoded frowny face we're
going to count it as at least 2 characters when it should only count as
one. Okay, so maybe we should actually be decoding these things, but
that's much easier said than done because we're splitting the file up
into chunks at arbitrary byte-counts; meaning we might end up splitting
that frowny face into two different chunks, leading to an invalid
decoding! What a nightmare.</p>
<p>This is another reason why doing a multi-threaded <code>wc</code> is
probably a bad idea, but I'm not so easily deterred. In order to proceed
I'm going to make a few assumptions:</p>
<ul>
<li>Our input will be encoded using either ASCII or UTF-8 family of
encodings. There are of course other popular encodings out there; but in
my limited experience most modern text files prefer one of these
encodings. In fact there are <a href="http://utf8everywhere.org/">entire
sites</a> dedicated to making <code>UTF-8</code> the one format to rule
them all.</li>
<li>We count only ASCII spaces and newlines as spaces and newlines;
sorry <code>MONGOLIAN VOWEL SEPARATOR</code>, but you're cut from the
team.</li>
</ul>
<p>By making these two assumptions we can exploit a few details of the
UTF-8 encoding scheme to solve our problem. Firstly, we know from the
UTF-8 spec that it's completely back-compatible with ASCII. What this
means is that every ASCII byte is encoded in UTF-8 as exactly that same
byte. Secondly, we know that NO other bytes in the file will conflict in
encoding with a valid ASCII byte; you can see why in a chart on the <a
href="https://en.wikipedia.org/wiki/UTF-8">UTF-8 wikipedia page</a>.
Continuation bytes start with a leading '1', and no ASCII bytes start
with a '1'.</p>
<p>These two facts mean we can safely leave our current 'space'
detection logic the same! It's impossible for us to 'split' a space or
newline because they're all encoded in a single byte, and we know we
won't accidentally count some byte that's part of a different codepoint
because there's no overlap in encoding for the ASCII bytes. We do
however need to change our character-counting logic.</p>
<p>One last fact about UTF-8 is that every UTF-8 encoded codepoint
contains exactly one byte from the set:
<code>0xxxxxxx, 110xxxxx, 1110xxxx, 11110xxx</code>. Continuation bytes
ALL start with <code>10</code>, so if we count all bytes OTHER than
those starting with <code>10</code> then we'll count each code-point
exactly once, even if we split a codepoint across different chunks!</p>
<p>All of these facts combined means we can write a per-byte monoid for
counting UTF-8 codepoints OR ASCII characters all in one!</p>
<p>Note that technically Unicode <strong>codepoints</strong> are not the
same as "characters", there are many codepoints like diacritics which
will "fuse" themselves to be displayed as a single character, but so far
as I know <code>wc</code> doesn't handle these separately either.</p>
<p>Actually, our current <code>Counts</code> monoid is fine, we'll just
need to adapt our <code>countChar</code> function:</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="kw">import</span> <span class="dt">Data.Bits</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.ByteString.Internal</span> (c2w)</span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a><span class="ot">countByte ::</span> <span class="dt">Char</span> <span class="ot">-&gt;</span> <span class="dt">Counts</span></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a>countByte c <span class="ot">=</span></span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Counts</span> {</span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a>            <span class="co">-- Only count bytes at the START of a codepoint, not continuation bytes</span></span>
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a>            charCount <span class="ot">=</span> <span class="kw">if</span> (bitAt <span class="dv">7</span> <span class="op">&amp;&amp;</span> <span class="fu">not</span> (bitAt <span class="dv">6</span>)) <span class="kw">then</span> <span class="dv">0</span> <span class="kw">else</span> <span class="dv">1</span></span>
<span id="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a>            , wordCount <span class="ot">=</span> flux c</span>
<span id="cb15-9"><a href="#cb15-9" aria-hidden="true" tabindex="-1"></a>            , lineCount <span class="ot">=</span> <span class="kw">if</span> (c <span class="op">==</span> <span class="ch">&#39;\n&#39;</span>) <span class="kw">then</span> <span class="dv">1</span> <span class="kw">else</span> <span class="dv">0</span></span>
<span id="cb15-10"><a href="#cb15-10" aria-hidden="true" tabindex="-1"></a>            }</span>
<span id="cb15-11"><a href="#cb15-11" aria-hidden="true" tabindex="-1"></a>    <span class="kw">where</span></span>
<span id="cb15-12"><a href="#cb15-12" aria-hidden="true" tabindex="-1"></a>      bitAt <span class="ot">=</span> testBit (c2w c)</span>
<span id="cb15-13"><a href="#cb15-13" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# INLINE countByte #-}</span></span></code></pre></div>
<p>And that's it! Now we can handle UTF-8 or ASCII; we don't even need
to know which encoding we're handling, we'll always give the right
answer.</p>
<p><code>wc</code>, at least the version on my Macbook, has a
<code>-m</code> flag for handling multi-byte characters when counting. A
few quick experiments shows that telling <code>wc</code> to handle
multi-byte chars slows down the process pretty significantly (it now
decodes every byte); let's see how our version does in comparison. (I've
confirmed they get the same results when running on a large UTF-8
encoded document with many non-ASCII characters)</p>
<p>543 MB test file:</p>
<table>
<thead>
<tr class="header">
<th></th>
<th>wc -mwl</th>
<th>multicore-utf8-wc</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>time</td>
<td>5.56s</td>
<td>3.07s</td>
</tr>
<tr class="even">
<td>max mem.</td>
<td>1.86 MB</td>
<td>7.52 MB</td>
</tr>
</tbody>
</table>
<p>Just as we suspect, we come out pretty far ahead! Our new version is
a bit slower than when we just counted every byte (we're now doing a few
extra bit-checks), so it's probably a good idea to add a
<code>utf</code> flag to our program so we can always run as fast as
possible for a given input.</p>
<h1 id="interjection">Interjection!</h1>
<p>Since posting the article, the wonderful <a
href="https://github.com/harendra-kumar">Harendra Kumar</a> has provided
me with a new performance tweak to try, which (spoiler alert) gives us
even better performance while also allowing us to STREAM input from
stdin! Wow! The code is pretty too!</p>
<p>The secret lies in the <a
href="https://github.com/composewell/streamly"><code>streamly</code>
library</a>, a wonderful high-level high-performance streaming library.
I'd seen it in passing, but these result will definitely have me
reaching for it in the future! Enough talk, let's see some code! Thanks
again to Harendra Kumar for this implementation:</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="kw">module</span> <span class="dt">Streaming</span> <span class="kw">where</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Types</span></span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Traversable</span></span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">GHC.Conc</span> (numCapabilities)</span>
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">System.IO</span> (openFile, <span class="dt">IOMode</span>(..))</span>
<span id="cb16-7"><a href="#cb16-7" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Streamly</span> <span class="kw">as</span> <span class="dt">S</span></span>
<span id="cb16-8"><a href="#cb16-8" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Streamly.Data.String</span> <span class="kw">as</span> <span class="dt">S</span></span>
<span id="cb16-9"><a href="#cb16-9" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Streamly.Prelude</span> <span class="kw">as</span> <span class="dt">S</span></span>
<span id="cb16-10"><a href="#cb16-10" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Streamly.Internal.Memory.Array</span> <span class="kw">as</span> <span class="dt">A</span></span>
<span id="cb16-11"><a href="#cb16-11" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Streamly.Internal.FileSystem.Handle</span> <span class="kw">as</span> <span class="dt">FH</span></span>
<span id="cb16-12"><a href="#cb16-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-13"><a href="#cb16-13" aria-hidden="true" tabindex="-1"></a><span class="ot">streamingBytestream ::</span> <span class="dt">FilePath</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> <span class="dt">Counts</span></span>
<span id="cb16-14"><a href="#cb16-14" aria-hidden="true" tabindex="-1"></a>streamingBytestream fp <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb16-15"><a href="#cb16-15" aria-hidden="true" tabindex="-1"></a>    src <span class="ot">&lt;-</span> openFile fp <span class="dt">ReadMode</span></span>
<span id="cb16-16"><a href="#cb16-16" aria-hidden="true" tabindex="-1"></a>    S.foldl&#39; <span class="fu">mappend</span> <span class="fu">mempty</span></span>
<span id="cb16-17"><a href="#cb16-17" aria-hidden="true" tabindex="-1"></a>        <span class="op">$</span> S.aheadly</span>
<span id="cb16-18"><a href="#cb16-18" aria-hidden="true" tabindex="-1"></a>        <span class="op">$</span> S.maxThreads numCapabilities</span>
<span id="cb16-19"><a href="#cb16-19" aria-hidden="true" tabindex="-1"></a>        <span class="op">$</span> S.mapM countBytes</span>
<span id="cb16-20"><a href="#cb16-20" aria-hidden="true" tabindex="-1"></a>        <span class="op">$</span> FH.toStreamArraysOf <span class="dv">1024000</span> src</span>
<span id="cb16-21"><a href="#cb16-21" aria-hidden="true" tabindex="-1"></a>    <span class="kw">where</span></span>
<span id="cb16-22"><a href="#cb16-22" aria-hidden="true" tabindex="-1"></a>    countBytes <span class="ot">=</span></span>
<span id="cb16-23"><a href="#cb16-23" aria-hidden="true" tabindex="-1"></a>          S.foldl&#39; (\acc c <span class="ot">-&gt;</span> acc <span class="op">&lt;&gt;</span> countByte c) <span class="fu">mempty</span></span>
<span id="cb16-24"><a href="#cb16-24" aria-hidden="true" tabindex="-1"></a>        <span class="op">.</span> S.decodeChar8</span>
<span id="cb16-25"><a href="#cb16-25" aria-hidden="true" tabindex="-1"></a>        <span class="op">.</span> A.toStream</span>
<span id="cb16-26"><a href="#cb16-26" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-27"><a href="#cb16-27" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# INLINE streamingBytestream #-}</span></span></code></pre></div>
<p>Note; this uses streamly version <code>7.10</code> straight from
their Github repo, it'll likely be published to hackage soon. It also
uses a few internal modules, but hopefully use-cases like this will
prove that these combinators have enough valid uses to expose them.</p>
<p>First things first we simply open the file, nothing fancy there.</p>
<p>Next is the streaming code, we'll read it from the bottom to the top
to follow the flow of information.</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>FH.toStreamArraysOf <span class="dv">1024000</span> src</span></code></pre></div>
<p>This chunks the bytes from the file handle into streams of Byte
arrays. Using Byte arrays ends up being even faster than using something
like a Lazy ByteString! We'll use a separate array for approximately
each MB of the file, you can tweak this to your heart's content.</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>S.mapM countBytes</span></code></pre></div>
<p>This uses <code>mapM</code> to run the <code>countBytes</code>
function over the array; <code>countBytes</code> itself creates a stream
from the array and runs a streaming fold over it with our Monoidal byte
counter:</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>countBytes <span class="ot">=</span></span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a>      S.foldl&#39; (\acc c <span class="ot">-&gt;</span> acc <span class="op">&lt;&gt;</span> countByte c) <span class="fu">mempty</span></span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a>    <span class="op">.</span> S.decodeChar8</span>
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">.</span> A.toStream</span></code></pre></div>
<p>Next we tell streamly to run the map over arrays in parallel,
allowing separate threads to handle each 1MB chunk. We limit the number
of threads to our number of capabilities. Once we've read in the data we
can process it immediately, and our counting code doesn't have any
reasons to block, so adding more threads than capabilities would likely
just add more work for the scheduler.</p>
<div class="sourceCode" id="cb20"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a>S.maxThreads numCapabilities</span></code></pre></div>
<p>Streamly provides many different stream evaluation strategies, We use
<code>aheadly</code> as our strategy which allows stream elements to be
processed in parallel, but still guarantees output will be emitted in
the order corresponding to the input. Since we're using a Monoid, so
long as everything ends up in the appropriate order we can chunk up the
computations any way we like:</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>S.aheadly</span></code></pre></div>
<p>At this point we've counted 1 MB chunks of our input, but we still
need to aggregate all the chunks together, we can do this by
<code>mappending</code> them all in another streaming fold:</p>
<div class="sourceCode" id="cb22"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a>S.foldl&#39; <span class="fu">mappend</span> <span class="fu">mempty</span></span></code></pre></div>
<p>That's the gist! Let's take it for a spin!</p>
<p>Here's the non-utf version on our 543 MB test file:</p>
<table>
<thead>
<tr class="header">
<th></th>
<th>wc</th>
<th>multicore-wc</th>
<th>streaming-wc</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>time</td>
<td>2.07s</td>
<td>1.23s</td>
<td>1.07s</td>
</tr>
<tr class="even">
<td>max mem.</td>
<td>1.87 MB</td>
<td>7.06 MB</td>
<td>17.81 MB</td>
</tr>
</tbody>
</table>
<p>We can see it gets even faster, at the expense of a significant
amount of memory, which I suspect could be mitigated by tuning our input
chunking, let's try it out. Here's a comparison of the 100 KB chunks vs
1 MB chunks:</p>
<table>
<thead>
<tr class="header">
<th></th>
<th>streaming-wc (100 KB chunks)</th>
<th>streaming-wc (1 MB chunks)</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>time</td>
<td>1.20s</td>
<td>1.07s</td>
</tr>
<tr class="even">
<td>max mem.</td>
<td>8.02 MB</td>
<td>17.81 MB</td>
</tr>
</tbody>
</table>
<p>That's about what I suspected, we can trade a bit of performance for
a decent hunk of memory. I'm already pretty happy with our results, but
feel free to test other tuning strategies.</p>
<p>Lastly let's try the UTF8 version on our 543 MB test file, here's
everything side by side:</p>
<table>
<colgroup>
<col style="width: 11%" />
<col style="width: 13%" />
<col style="width: 31%" />
<col style="width: 43%" />
</colgroup>
<thead>
<tr class="header">
<th></th>
<th>wc -mwl</th>
<th>multicore-utf8-wc</th>
<th>streaming-utf-wc (1 MB chunks)</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>time</td>
<td>5.56s</td>
<td>3.07s</td>
<td>2.67s</td>
</tr>
<tr class="even">
<td>max mem.</td>
<td>1.86 MB</td>
<td>7.52 MB</td>
<td>17.92 MB</td>
</tr>
</tbody>
</table>
<p>We're still getting faster! For the final version we may want to cut
the memory usage down a bit though!</p>
<p>Overall I think the streaming version is my favourite, it's very
high-level, very readable, and reads from an arbitrary file handle,
including <code>stdin</code>, which is a very common use-case for
<code>wc</code>. Streamly is pretty cool.</p>
<h2 id="conclusions">Conclusions</h2>
<p>So; how does our high-level garbage-collected runtime-based language
Haskell stack up? Pretty dang well I'd say! We ended up really quite
close with our single-core lazy-bytestring <code>wc</code>. Switching to
a multi-core approach ultimately allowed us to pull ahead! Whether our
<code>wc</code> clone is faster in practice without a warmed up
disk-cache is something that should be considered, but in terms of raw
performance we managed to build something faster! The streaming version
shouldn't have the same dependencies on disk caching to be optimal.</p>
<p>Haskell as a language isn't perfect, but if I can get ball-park
comparable performance to a C program while writing high-level fully
type-checked code then I'll call that a win any day.</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Optics + Regex: Greater than the sum of their parts</title>
      <link href="https://chrispenner.ca/posts/lens-regex-pcre"/>
      <id>https://chrispenner.ca/posts/lens-regex-pcre</id>
      <updated>2019-09-20T00:00:00Z</updated>
      <summary>Optics + Regex: greater than the sum of their parts.</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/magnifier.jpg" alt="Optics + Regex: Greater than the sum of their parts">
              <p>The library presented in this post is one of many steps towards
getting everyone interested in the amazing world of Optics! If you're at
all interested in learning their ins &amp; outs; check out the
comprehensive book I'm writing on the topic: <a
href="https://opticsbyexample.com">Optics By Example</a></p>
<hr />
<p>Regardless of the programming language, regular expressions have
always been a core tool in the programmer's toolbox. Though some have a
distaste for their difficult to maintain nature, they're an adaptable
quick'n'dirty way to get things done.</p>
<p>As much love as I have for Regular Expressions, they've become an
incredibly hacky thing; they support a lot of options and a lot of
different behaviours, so the interfaces to regular expressions in all
languages tends to leave a bit to be desired.</p>
<h2 id="the-status-quo">The Status Quo</h2>
<p>I don't know about you, but I've found almost every regular
expression interface I've ever used in any language to be a bit clunky
and inelegant; that's not meant to insult or demean any of those
libraries, I think it's because regular expressions have a complex set
of possible operations and the combination of them makes it tough to
design a clean interface. Here are just a few reasons why it's hard to
design a regex interface:</p>
<ul>
<li>Regular expressions can be used to either get <strong>or</strong>
set</li>
<li>Sometimes you want only <strong>one</strong> match, sometimes a few,
sometimes you want <strong>all</strong> of them!</li>
<li>Sometimes you want <strong>just</strong> the match groups; sometimes
you want the <strong>whole</strong> match, sometimes you want
<strong>BOTH</strong>!</li>
<li>Regular Expression searching is <strong>expensive</strong>; we want
to be <strong>lazy</strong> to avoid work!</li>
<li>Regular expressions patterns are usually written as text; what if
it's not valid?</li>
</ul>
<p>Luckily Haskell has a few tricks that help make some of these
inherently difficult things a bit easier. Inherently lazy data
structures and computations allows us to punt off laziness to the
language rather than worrying about how to do the minimal amount of work
possible. TemplateHaskell allows us to statically check Regular
Expressions to ensure they're valid at compile time, and could even
possibly allow us to statically analyze the existence of match groups.
But that still leaves a lot of surface area to cover! It's easy to see
how come these interfaces are complicated!</p>
<p>Think about designing a single interface which can support ALL of the
following operations performantly and elegantly:</p>
<ul>
<li>Get me the second match group from the first three matches</li>
<li>Replace only the first match with this text</li>
<li>Get me all groups AND match text from ALL matches</li>
<li>Replace the first match with this value, the next with this one, and
so on...</li>
<li>Lazily get me the full match text of the first 2 matches where
match-group 1 has a certain property.</li>
</ul>
<p>Yikes... That's going to take either a lot of methods or a lot of
options!</p>
<p>In a language like Haskell which doesn't have keyword or optional
arguments it means we have to either overload operators with a lot of
different meanings based on context; or provide a LOT of functions that
the user has to learn, increasing our API's surface area. You may be
familiar with the laughably overloaded "do everything" regex operator in
many Haskell regex libs:</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">(=~) ::</span> ( <span class="dt">RegexMaker</span> <span class="dt">Regex</span> <span class="dt">CompOption</span> <span class="dt">ExecOption</span> source2</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>        , <span class="dt">RegexContext</span> <span class="dt">Regex</span> source1 target</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>        ) <span class="ot">=&gt;</span> source1 <span class="ot">-&gt;</span> source2 <span class="ot">-&gt;</span> target</span></code></pre></div>
<p>And even that doesn't handle replacement!</p>
<p>Overloading is one approach, but as it turns out, it requires a lot
of spelunking through types and documentation to even find out what the
valid possible uses are! I'm going to rule out this approach as unwieldy
and tough to reason about. That leaves us with the other option; add a
whole bunch of methods or options, which doesn't sound great either,
mainly because I don't want someone to need to learn a dozen
<strong>specialized</strong> functions just to use <strong>my</strong>
library. If only there was some existing vocabulary of operations which
could be composed in different permutations to express complex
ideas!</p>
<h2 id="something-different">Something Different</h2>
<p>Introducing <a
href="https://github.com/ChrisPenner/lens-regex-pcre"><code>lens-regex-pcre</code></a>;
a Haskell regular expression library which uses optics as its primary
interface.</p>
<p>Think about what regular expressions are meant to do; they're an
interface which allows you to <strong>get</strong> or
<strong>set</strong> zero or more small pieces of text in a larger
whole. This is practically the <strong>dictionary definition</strong> of
a Traversal in optics! Interop with optics means you
<strong>instantly</strong> benefit from the plethora of existing optics
combinators! In fact, optics fit this problem <strong>so nicely</strong>
that the lensy wrapper I built supports <strong>more features</strong>,
with <strong>less code</strong>, and runs
<em><strong>faster</strong></em> (for replacements) than the regex
library it wraps! Stay tuned for more on how that's even possible near
the end!</p>
<p>Using optics as an interface has the benefit that the user is either
<strong>already familiar</strong> with most of the combinators and tools
they'll need from using optics previously, or that everything they learn
here is transferable into work with optics in the future! As more optics
are discovered, added, and optimized, the regex library passively
benefits without any extra work from anyone!</p>
<p>I don't want to discount the fact that optics can be tough to work
with; I'm aware that they have a reputation of being too hard to learn
and sometimes have poor type-inference and tricky error messages. I'm <a
href="https://opticsbyexample.com/">doing my best to address those
problems through education</a>, and there are new optics libraries
coming out every year that improve error messages and usability! Despite
current inconveniences, optics are fundamental constructions which model
problems well; I believe <strong>optics are inevitable</strong>! So
rather than shying away from an incredibly elegant solution because of a
few temporary issues with the domain I'd rather push through them, use
all the power the domain provides me, and continue to do all I can to
chip away at the usability problems over time.</p>
<blockquote>
<p>Optics are inevitable.</p>
</blockquote>
<p>Okay! I'll put my soapbox away, now it's time to see how this all
actually works. Notice how most of the following examples actually read
roughly like a sentence!</p>
<h2 id="examples">Examples</h2>
<p><code>lens-regex-pcre</code> provides <code>regex</code>,
<code>match</code>, <code>group</code> and <code>groups</code> in the
following examples, everything else is regular ol' optics from the
<code>lens</code> library!</p>
<p>We'll search through this text in the following examples:</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">txt ::</span> <span class="dt">Text</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>txt <span class="ot">=</span> <span class="st">&quot;raindrops on roses and whiskers on kittens&quot;</span></span></code></pre></div>
<p>First off, let's check if a pattern exists in the text:</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="op">&gt;&gt;&gt;</span> has [regex|wh.skers|] txt</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span></span></code></pre></div>
<p>Looks like we found it!</p>
<p><code>regex</code> is a QuasiQuoter which constructs a traversal over
all the text that matches the pattern you pass to it; behind the scenes
it compiles the regex with <code>pcre-heavy</code> and will check your
regex for you at compile time! Look; if we give it a bad pattern we find
out right away!</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="co">-- Search</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> has [regex|?|] txt</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 class="op">&lt;</span>interactive<span class="op">&gt;:</span><span class="dv">1</span><span class="op">:</span><span class="dv">12</span><span class="op">:</span> <span class="fu">error</span><span class="op">:</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>    • <span class="dt">Exception</span> when trying to run compile<span class="op">-</span>time code<span class="op">:</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Text.Regex.PCRE.Light</span><span class="op">:</span> <span class="dt">Error</span> <span class="kw">in</span> regex<span class="op">:</span> nothing to <span class="fu">repeat</span></span></code></pre></div>
<p>Handy!</p>
<p>Okay! Moving on, what if we just want to find the first match? We can
use <code>firstOf</code> from <code>lens</code> to get <code>Just</code>
the first focus or <code>Nothing</code>.</p>
<p>Here we use a fun regex to return the first word with doubles of a
letter inside; it turns out <code>kittens</code> has a double
<code>t</code>!</p>
<p>We use <code>match</code> to say we want to extract the text that was
matched.</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> firstOf ([regex|\w*(\w)\1\w*|] <span class="op">.</span> match) txt</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> <span class="st">&quot;kittens&quot;</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="co">-- Alias: ^?</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> txt <span class="op">^?</span> [regex|\w*(\w)\1\w*|] <span class="op">.</span> match</span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> <span class="st">&quot;kittens&quot;</span></span></code></pre></div>
<p>Next we want to get <strong>ALL</strong> the matches for a pattern,
this one is probably the most common task we want to perform, luckily
it's common when working with optics too!</p>
<p>Let's find all the words starting with <code>r</code> using
<code>toListOf</code></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="op">&gt;&gt;&gt;</span> toListOf ([regex|\br\w*|] <span class="op">.</span> match) txt</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>[<span class="st">&quot;raindrops&quot;</span>,<span class="st">&quot;roses&quot;</span>]</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="co">-- ALIAS: ^..</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> txt <span class="op">^..</span> [regex|\br\w*|] <span class="op">.</span> match</span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>[<span class="st">&quot;raindrops&quot;</span>,<span class="st">&quot;roses&quot;</span>]</span></code></pre></div>
<p>What if we want to count the number of matches instead?</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> lengthOf [regex|\br\w*|] txt</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="dv">2</span></span></code></pre></div>
<p>Basically anything you can think to ask is already provided by
<code>lens</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="co">-- Do any matches contain &quot;drop&quot;?</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> anyOf ([regex|\br\w*|] <span class="op">.</span> match) (T.isInfixOf <span class="st">&quot;drop&quot;</span>) txt</span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a><span class="co">-- Are all of our matches greater than 3 chars?</span></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> allOf ([regex|\br\w*|] <span class="op">.</span> match) ((<span class="op">&gt;</span><span class="dv">3</span>) <span class="op">.</span> T.length) txt</span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span></span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a><span class="co">-- &quot;Is &#39;roses&#39; one of our matches&quot;</span></span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> elemOf ([regex|\br\w*|] <span class="op">.</span> match) <span class="st">&quot;roses&quot;</span> txt</span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span></span></code></pre></div>
<h2 id="substitutions-and-replacements">Substitutions and
replacements</h2>
<p>But that's not all! We can edit and mutate our matches in-place! This
is something that the lensy interface does much better than any regex
library I've ever seen. Hold my beer.</p>
<p>We can do the boring basic regex replace without even breaking a
sweat:</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> set ([regex|\br\w*|] <span class="op">.</span> match) <span class="st">&quot;brillig&quot;</span> txt</span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;brillig on brillig and whiskers on kittens&quot;</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="co">-- Alias .~</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> txt <span class="op">&amp;</span> [regex|\br\w*|] <span class="op">.</span> match <span class="op">.~</span> <span class="st">&quot;brillig&quot;</span></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;brillig on brillig and whiskers on kittens&quot;</span></span></code></pre></div>
<p>Now for the fun stuff; we can <strong>mutate</strong> a match
in-place!</p>
<p>Let's reverse all of our matches:</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="op">&gt;&gt;&gt;</span> over ([regex|\br\w*|] <span class="op">.</span> match) T.reverse txt</span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;spordniar on sesor and whiskers on kittens&quot;</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">-- Alias %~</span></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> txt <span class="op">&amp;</span> [regex|\br\w*|] <span class="op">.</span> match <span class="op">%~</span> T.reverse</span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;spordniar on sesor and whiskers on kittens&quot;</span></span></code></pre></div>
<p>Want to replace matches using a list of substitutions? No problem! We
can use <code>partsOf</code> to edit our matches as a list!</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="op">&gt;&gt;&gt;</span> txt <span class="op">&amp;</span> partsOf ([regex|\br\w*|] <span class="op">.</span> match) <span class="op">.~</span> [<span class="st">&quot;one&quot;</span>, <span class="st">&quot;two&quot;</span>]</span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;one on two and whiskers on kittens&quot;</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">-- Providing too few simply leaves extras alone</span></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> txt <span class="op">&amp;</span> partsOf ([regex|\br\w*|] <span class="op">.</span> match) <span class="op">.~</span> [<span class="st">&quot;one&quot;</span>]</span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;one on roses and whiskers on kittens&quot;</span></span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a><span class="co">-- Providing too many performs as many substitutions as it can</span></span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> txt <span class="op">&amp;</span> partsOf ([regex|\br\w*|] <span class="op">.</span> match) <span class="op">.~</span> [<span class="st">&quot;one&quot;</span>, <span class="st">&quot;two&quot;</span>, <span class="st">&quot;three&quot;</span>]</span>
<span id="cb11-10"><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;one on two and whiskers on kittens&quot;</span></span></code></pre></div>
<p>We can even do updates which require effects!</p>
<p>Let's find and replace variables in a block of text with values from
environment variables using <code>IO</code>!</p>
<p>Note that <code>%%~</code> is the combinator for running a
<code>traverse</code> over the targets. We could also use
<code>traverseOf</code>.</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">import</span> <span class="kw">qualified</span> <span class="dt">Data.Text</span> <span class="kw">as</span> <span class="dt">T</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Lens</span></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Lens.Regex</span></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">System.Environment</span></span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Text.Lens</span></span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a><span class="ot">src ::</span> <span class="dt">T.Text</span></span>
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a>src <span class="ot">=</span> <span class="st">&quot;Hello $NAME, how&#39;s your $THING?&quot;</span></span>
<span id="cb12-9"><a href="#cb12-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-10"><a href="#cb12-10" aria-hidden="true" tabindex="-1"></a><span class="ot">replaceEnv ::</span> <span class="dt">T.Text</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> <span class="dt">T.Text</span></span>
<span id="cb12-11"><a href="#cb12-11" aria-hidden="true" tabindex="-1"></a>replaceEnv <span class="ot">=</span> [regex|\$\w+|] <span class="op">.</span> match <span class="op">.</span> unpacked <span class="op">%%~</span> getEnv <span class="op">.</span> <span class="fu">tail</span></span></code></pre></div>
<p>Let's run it:</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> setEnv <span class="st">&quot;NAME&quot;</span> <span class="st">&quot;Joey&quot;</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> setEnv <span class="st">&quot;THING&quot;</span> <span class="st">&quot;dog&quot;</span></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> replaceWithEnv src</span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;Hello Joey, how&#39;s your dog?&quot;</span></span></code></pre></div>
<p>When you think about what we've managed to do with
<code>replaceWithEnv</code> in a single line of code I think it's pretty
impressive.</p>
<p>And we haven't even looked at groups yet!</p>
<h2 id="using-groups">Using Groups</h2>
<p>Any sufficiently tricky regex problem will need groups eventually!
<code>lens-regex-pcre</code> supports that!</p>
<p>Instead of using <code>match</code> after <code>regex</code> we just
use <code>groups</code> instead! It's that easy.</p>
<p>Let's say we want to collect only the names of every variable in a
template string:</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">template ::</span> <span class="dt">T.Text</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a>template <span class="ot">=</span> <span class="st">&quot;Hello $NAME, glad you came to $PLACE&quot;</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="op">&gt;&gt;&gt;</span> toListOf ([regex|\$(\w+)|] <span class="op">.</span> <span class="fu">group</span> <span class="dv">0</span>) template</span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a>[<span class="st">&quot;NAME&quot;</span>,<span class="st">&quot;PLACE&quot;</span>]</span></code></pre></div>
<p>You can substitute/edit groups too!</p>
<p>What if we got all our our area codes and local numbers messed up in
our phone numbers? We can fix that in one fell swoop:</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">phoneNumbers ::</span> <span class="dt">T.Text</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>phoneNumbers <span class="ot">=</span> <span class="st">&quot;555-123-4567, 999-876-54321&quot;</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="co">-- &#39;reverse&#39; will switch the first and second groups in the list of groups matches!</span></span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> phoneNumbers <span class="op">&amp;</span> [regex|(\d{3})-(\d{3})|] <span class="op">.</span> groups <span class="op">%~</span> Prelude.reverse</span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;123-555-4567, 876-999-54321&quot;</span></span></code></pre></div>
<h2 id="bringing-it-in">Bringing it in</h2>
<p>So with this new vocabulary how do we solve all the problems we posed
earlier?</p>
<ul>
<li>Get me the second match group from the first three matches</li>
</ul>
<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="op">&gt;&gt;&gt;</span> <span class="st">&quot;a:b, c:d, e:f, g:h&quot;</span> <span class="op">^..</span> taking <span class="dv">3</span> ([regex|(\w):(\w)|] <span class="op">.</span> <span class="fu">group</span> <span class="dv">1</span>)</span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a>[<span class="st">&quot;b&quot;</span>,<span class="st">&quot;d&quot;</span>,<span class="st">&quot;f&quot;</span>]</span></code></pre></div>
<p>You can replace the call to <code>taking</code> with a simple
<code>Prelude.take 3</code> on the whole list of matches if you prefer,
it'll lazily do the minimum amount of work!</p>
<ul>
<li>Replace only the first match with this text</li>
</ul>
<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="op">&gt;&gt;&gt;</span> <span class="st">&quot;one two three&quot;</span> <span class="op">&amp;</span> [regex|\w+|] <span class="op">.</span> <span class="fu">index</span> <span class="dv">0</span> <span class="op">.</span> match <span class="op">.~</span> <span class="st">&quot;new&quot;</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;new two three&quot;</span></span></code></pre></div>
<ul>
<li>Get me all groups AND match text from ALL matches</li>
</ul>
<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="op">&gt;&gt;&gt;</span> <span class="st">&quot;a:b, c:d, e:f&quot;</span> <span class="op">^..</span> [regex|(\w):(\w)|] <span class="op">.</span> matchAndGroups</span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a>[(<span class="st">&quot;a:b&quot;</span>,[<span class="st">&quot;a&quot;</span>,<span class="st">&quot;b&quot;</span>]),(<span class="st">&quot;c:d&quot;</span>,[<span class="st">&quot;c&quot;</span>,<span class="st">&quot;d&quot;</span>]),(<span class="st">&quot;e:f&quot;</span>,[<span class="st">&quot;e&quot;</span>,<span class="st">&quot;f&quot;</span>])]</span></code></pre></div>
<ul>
<li>Replace the first match with this value, the next with this one, and
so on...</li>
</ul>
<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="co">-- If we get more matches than replacements it just leaves the extras alone</span></span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="st">&quot;one two three four&quot;</span> <span class="op">&amp;</span> partsOf ([regex|\w+|] <span class="op">.</span> match) <span class="op">.~</span> [<span class="st">&quot;1&quot;</span>, <span class="st">&quot;2&quot;</span>, <span class="st">&quot;3&quot;</span>]</span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;1 2 3 four&quot;</span></span></code></pre></div>
<ul>
<li>Lazily get me the full match text of the first 2 matches where
match-group 1 has a certain property.</li>
</ul>
<div class="sourceCode" id="cb20"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- The resulting list will be lazily evaluated!</span></span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="st">&quot;a:b, c:d, e:f, g:h&quot;</span> </span>
<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a>      <span class="op">^..</span> [regex|(\w):(\w)|] </span>
<span id="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a>      <span class="op">.</span> filtered (has (<span class="fu">group</span> <span class="dv">0</span> <span class="op">.</span> filtered (<span class="op">&gt;</span> <span class="st">&quot;c&quot;</span>))) </span>
<span id="cb20-5"><a href="#cb20-5" aria-hidden="true" tabindex="-1"></a>      <span class="op">.</span> match</span>
<span id="cb20-6"><a href="#cb20-6" aria-hidden="true" tabindex="-1"></a>[<span class="st">&quot;e:f&quot;</span>,<span class="st">&quot;g:h&quot;</span>]</span></code></pre></div>
<p>Anyways, at this point I'm rambling, but I hope you see that this is
too useful of an abstraction for us to give up!</p>
<p>Huge thanks to everyone who has done work on <code>pcre-light</code>
and <code>pcre-heavy</code>; and of course everyone who helped to build
<code>lens</code> too! This wouldn't be possible without both of
them!</p>
<p>The library has a Text interface which supports Unicode, and a
<code>ByteString</code> interface for when you've gotta go
<strong>fast</strong>!</p>
<h1 id="performance">Performance</h1>
<p>Typically one would expect that the more expressive an interface, the
worse it would perform, in this case the opposite is true!
<code>lens-regex-pcre</code> utilizes <code>pcre-heavy</code> ONLY for
regex compilation and finding match positions with
<code>scanRanges</code>, that's it! In fact, I don't use
<code>pcre-heavy</code>'s built-in support for replacements <strong>at
all</strong>! After finding the match positions it lazily walks over the
full <code>ByteString</code> splitting it into chunks. Chunks are tagged
with whether they're a match or not, then the "match" chunks are split
further to represent whether the text is in a group or not. This allows
us to implement all of our regex operations as a simple traversal over a
nested list of <code>Either</code>s. These traversals are the ONLY
things we actually need to implement, all other functionality including
listing matches, filtering matches, and even setting or updating matches
already exists in <code>lens</code> as generic optics combinators!</p>
<p>This means I didn't need to optimize for replacements or for viewing
separately, because I didn't optimize for specific actions <strong>at
all</strong>! I just built a single Traversal, and everything else
follows from that.</p>
<p>You heard that right! I didn't write ANY special logic for viewing,
updating, setting, or anything else! I just provided the appropriate
traversals, optics combinators do the rest, and it's still
performant!</p>
<p>There was a little bit of fiddly logic involved with splitting the
text up into chunks, but after that it all gets pretty easy to reason
about. To optimize the Traversal itself I was easily able to refactor
things to use <code>ByteString</code> 'Builder's rather than full
<code>ByteString</code>s, which have much better concatenation
performance.</p>
<p>With the caveat that I don't claim to be an expert at benchmarks;
(please <a
href="https://github.com/ChrisPenner/lens-regex-pcre/blob/master/bench/Bench.hs">take
a look</a> and tell me if I'm making any critical mistakes!) this single
change took <code>lens-regex-pcre</code> from being about <strong>half
the speed</strong> of <code>pcre-heavy</code> to being within 0.6% of
<strong>equal</strong> for search, and <strong>~10% faster</strong> for
replacements. It's just as fast for arbitrary pure or effectful
<strong>modifications</strong>, which is something other regex libraries
simply don't support. If there's a need for it, it can also trivially
support things like inverting the match to operate over all
<strong>unmatched</strong> text, or things like splitting up a text on
matches, etc.</p>
<p>I suspect that these performance improvements are simple enough they
could also be back-ported to <code>pcre-heavy</code> if anyone has the
desire to do so, I'd be curious if it works just as well for
<code>pcre-heavy</code> as it did for <code>lens-regex-pcre</code>.</p>
<p>You can try out the library <a
href="https://github.com/ChrisPenner/lens-regex-pcre">here!</a>; make
sure you're using <code>v1.0.0.0</code>.</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Slick 1.0 Release - Now with a quick and easy template!</title>
      <link href="https://chrispenner.ca/posts/slick-template"/>
      <id>https://chrispenner.ca/posts/slick-template</id>
      <updated>2019-09-18T00:00:00Z</updated>
      <summary>Build a static site using Haskell, Shake and Pandoc!</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/slick.jpg" alt="Slick 1.0 Release - Now with a quick and easy template!">
              <p>TLDR; Build a site with <a
href="https://github.com/ChrisPenner/slick">slick 1.0</a>: <a
href="https://github.com/ChrisPenner/slick-template">fork the
slick-template</a>.</p>
<p>Hey folks! Slick has been around for a while already, it's a light
wrapper over Shake which allows for blazing fast static site builds! It
provides Pandoc helpers to load in pages or posts as markdown, or
ANYTHING that Pandoc can read (which is pretty much EVERYTHING
nowadays). It offers support for Mustache templates as well!</p>
<p>Shake was always great as a build tool, but its Makefile-style of
dependency targets was always a little backwards for building a site.
Slick 1.0 switches to recommending using Shake's FORWARD discoverable
build style. This means you can basically write normal Haskell code in
the Action monad to build and render your site, and Shake will
<strong>automagically</strong> cache everything for you with proper and
efficient cache-busting! A dream come true.</p>
<p>Slick lets you build and deploy a static website using Github Pages
(or literally any static file host) very easily while still maintaining
completely open for extensibility. You can use any shake compatible lib,
or even just IO if you want; Shake's forward build tools can even detect
caching rules when running arbitrary external processes (caveat
emptor).</p>
<p>Hope you like it! In case you're curious what a site might be like;
this very blog is built with slick!</p>
<p>Here's a full snippet of code for building a simple blog (with
awesome caching) from markdown files; check it out:</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">{-# LANGUAGE DeriveGeneric #-}</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE DeriveAnyClass #-}</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE OverloadedStrings #-}</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="kw">module</span> <span class="dt">Main</span> <span class="kw">where</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span>           <span class="dt">Control.Lens</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span>           <span class="dt">Control.Monad</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span>           <span class="dt">Data.Aeson</span>                 <span class="kw">as</span> <span class="dt">A</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span>           <span class="dt">Data.Aeson.Lens</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span>           <span class="dt">Development.Shake</span></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span>           <span class="dt">Development.Shake.Classes</span></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span>           <span class="dt">Development.Shake.Forward</span></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span>           <span class="dt">Development.Shake.FilePath</span></span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span>           <span class="dt">GHC.Generics</span>               (<span class="dt">Generic</span>)</span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span>           <span class="dt">Slick</span></span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Data.Text</span>                  <span class="kw">as</span> <span class="dt">T</span></span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a><span class="ot">outputFolder ::</span> <span class="dt">FilePath</span></span>
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a>outputFolder <span class="ot">=</span> <span class="st">&quot;docs/&quot;</span></span>
<span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-22"><a href="#cb1-22" aria-hidden="true" tabindex="-1"></a><span class="co">-- | Data for the index page</span></span>
<span id="cb1-23"><a href="#cb1-23" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">IndexInfo</span> <span class="ot">=</span></span>
<span id="cb1-24"><a href="#cb1-24" aria-hidden="true" tabindex="-1"></a>  <span class="dt">IndexInfo</span></span>
<span id="cb1-25"><a href="#cb1-25" aria-hidden="true" tabindex="-1"></a>    {<span class="ot"> posts ::</span> [<span class="dt">Post</span>]</span>
<span id="cb1-26"><a href="#cb1-26" aria-hidden="true" tabindex="-1"></a>    } <span class="kw">deriving</span> (<span class="dt">Generic</span>, <span class="dt">Show</span>, <span class="dt">FromJSON</span>, <span class="dt">ToJSON</span>)</span>
<span id="cb1-27"><a href="#cb1-27" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-28"><a href="#cb1-28" aria-hidden="true" tabindex="-1"></a><span class="co">-- | Data for a blog post</span></span>
<span id="cb1-29"><a href="#cb1-29" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Post</span> <span class="ot">=</span></span>
<span id="cb1-30"><a href="#cb1-30" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Post</span> {<span class="ot"> title   ::</span> <span class="dt">String</span></span>
<span id="cb1-31"><a href="#cb1-31" aria-hidden="true" tabindex="-1"></a>         ,<span class="ot"> author  ::</span> <span class="dt">String</span></span>
<span id="cb1-32"><a href="#cb1-32" aria-hidden="true" tabindex="-1"></a>         ,<span class="ot"> content ::</span> <span class="dt">String</span></span>
<span id="cb1-33"><a href="#cb1-33" aria-hidden="true" tabindex="-1"></a>         ,<span class="ot"> url     ::</span> <span class="dt">String</span></span>
<span id="cb1-34"><a href="#cb1-34" aria-hidden="true" tabindex="-1"></a>         ,<span class="ot"> date    ::</span> <span class="dt">String</span></span>
<span id="cb1-35"><a href="#cb1-35" aria-hidden="true" tabindex="-1"></a>         ,<span class="ot"> image   ::</span> <span class="dt">Maybe</span> <span class="dt">String</span></span>
<span id="cb1-36"><a href="#cb1-36" aria-hidden="true" tabindex="-1"></a>         }</span>
<span id="cb1-37"><a href="#cb1-37" aria-hidden="true" tabindex="-1"></a>    <span class="kw">deriving</span> (<span class="dt">Generic</span>, <span class="dt">Eq</span>, <span class="dt">Ord</span>, <span class="dt">Show</span>, <span class="dt">FromJSON</span>, <span class="dt">ToJSON</span>, <span class="dt">Binary</span>)</span>
<span id="cb1-38"><a href="#cb1-38" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-39"><a href="#cb1-39" aria-hidden="true" tabindex="-1"></a><span class="co">-- | given a list of posts this will build a table of contents</span></span>
<span id="cb1-40"><a href="#cb1-40" aria-hidden="true" tabindex="-1"></a><span class="ot">buildIndex ::</span> [<span class="dt">Post</span>] <span class="ot">-&gt;</span> <span class="dt">Action</span> ()</span>
<span id="cb1-41"><a href="#cb1-41" aria-hidden="true" tabindex="-1"></a>buildIndex posts&#39; <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb1-42"><a href="#cb1-42" aria-hidden="true" tabindex="-1"></a>  indexT <span class="ot">&lt;-</span> compileTemplate&#39; <span class="st">&quot;site/templates/index.html&quot;</span></span>
<span id="cb1-43"><a href="#cb1-43" aria-hidden="true" tabindex="-1"></a>  <span class="kw">let</span> indexInfo <span class="ot">=</span> <span class="dt">IndexInfo</span> {posts <span class="ot">=</span> posts&#39;}</span>
<span id="cb1-44"><a href="#cb1-44" aria-hidden="true" tabindex="-1"></a>      indexHTML <span class="ot">=</span> T.unpack <span class="op">$</span> substitute indexT (toJSON indexInfo)</span>
<span id="cb1-45"><a href="#cb1-45" aria-hidden="true" tabindex="-1"></a>  writeFile&#39; (outputFolder <span class="op">&lt;/&gt;</span> <span class="st">&quot;index.html&quot;</span>) indexHTML</span>
<span id="cb1-46"><a href="#cb1-46" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-47"><a href="#cb1-47" aria-hidden="true" tabindex="-1"></a><span class="co">-- | Find and build all posts</span></span>
<span id="cb1-48"><a href="#cb1-48" aria-hidden="true" tabindex="-1"></a><span class="ot">buildPosts ::</span> <span class="dt">Action</span> [<span class="dt">Post</span>]</span>
<span id="cb1-49"><a href="#cb1-49" aria-hidden="true" tabindex="-1"></a>buildPosts <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb1-50"><a href="#cb1-50" aria-hidden="true" tabindex="-1"></a>  pPaths <span class="ot">&lt;-</span> getDirectoryFiles <span class="st">&quot;.&quot;</span> [<span class="st">&quot;site/posts//*.md&quot;</span>]</span>
<span id="cb1-51"><a href="#cb1-51" aria-hidden="true" tabindex="-1"></a>  forP pPaths buildPost</span>
<span id="cb1-52"><a href="#cb1-52" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-53"><a href="#cb1-53" aria-hidden="true" tabindex="-1"></a><span class="co">-- | Load a post, process metadata, write it to output, then return the post object</span></span>
<span id="cb1-54"><a href="#cb1-54" aria-hidden="true" tabindex="-1"></a><span class="co">-- Detects changes to either post content or template</span></span>
<span id="cb1-55"><a href="#cb1-55" aria-hidden="true" tabindex="-1"></a><span class="ot">buildPost ::</span> <span class="dt">FilePath</span> <span class="ot">-&gt;</span> <span class="dt">Action</span> <span class="dt">Post</span></span>
<span id="cb1-56"><a href="#cb1-56" aria-hidden="true" tabindex="-1"></a>buildPost srcPath <span class="ot">=</span> cacheAction (<span class="st">&quot;build&quot;</span><span class="ot"> ::</span> <span class="dt">T.Text</span>, srcPath) <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb1-57"><a href="#cb1-57" aria-hidden="true" tabindex="-1"></a>  liftIO <span class="op">.</span> <span class="fu">putStrLn</span> <span class="op">$</span> <span class="st">&quot;Rebuilding post: &quot;</span> <span class="op">&lt;&gt;</span> srcPath</span>
<span id="cb1-58"><a href="#cb1-58" aria-hidden="true" tabindex="-1"></a>  postContent <span class="ot">&lt;-</span> readFile&#39; srcPath</span>
<span id="cb1-59"><a href="#cb1-59" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- load post content and metadata as JSON blob</span></span>
<span id="cb1-60"><a href="#cb1-60" aria-hidden="true" tabindex="-1"></a>  postData <span class="ot">&lt;-</span> markdownToHTML <span class="op">.</span> T.pack <span class="op">$</span> postContent</span>
<span id="cb1-61"><a href="#cb1-61" aria-hidden="true" tabindex="-1"></a>  <span class="kw">let</span> postUrl <span class="ot">=</span> T.pack <span class="op">.</span> dropDirectory1 <span class="op">$</span> srcPath <span class="op">-&lt;.&gt;</span> <span class="st">&quot;html&quot;</span></span>
<span id="cb1-62"><a href="#cb1-62" aria-hidden="true" tabindex="-1"></a>      withPostUrl <span class="ot">=</span> _Object <span class="op">.</span> at <span class="st">&quot;url&quot;</span> <span class="op">?~</span> <span class="dt">String</span> postUrl</span>
<span id="cb1-63"><a href="#cb1-63" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- Add additional metadata we&#39;ve been able to compute</span></span>
<span id="cb1-64"><a href="#cb1-64" aria-hidden="true" tabindex="-1"></a>  <span class="kw">let</span> fullPostData <span class="ot">=</span> withPostUrl <span class="op">$</span> postData</span>
<span id="cb1-65"><a href="#cb1-65" aria-hidden="true" tabindex="-1"></a>  template <span class="ot">&lt;-</span> compileTemplate&#39; <span class="st">&quot;site/templates/post.html&quot;</span></span>
<span id="cb1-66"><a href="#cb1-66" aria-hidden="true" tabindex="-1"></a>  writeFile&#39; (outputFolder <span class="op">&lt;/&gt;</span> T.unpack postUrl) <span class="op">.</span> T.unpack <span class="op">$</span> substitute template fullPostData</span>
<span id="cb1-67"><a href="#cb1-67" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- Convert the metadata into a Post object</span></span>
<span id="cb1-68"><a href="#cb1-68" aria-hidden="true" tabindex="-1"></a>  convert fullPostData</span>
<span id="cb1-69"><a href="#cb1-69" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-70"><a href="#cb1-70" aria-hidden="true" tabindex="-1"></a><span class="co">-- | Copy all static files from the listed folders to their destination</span></span>
<span id="cb1-71"><a href="#cb1-71" aria-hidden="true" tabindex="-1"></a><span class="ot">copyStaticFiles ::</span> <span class="dt">Action</span> ()</span>
<span id="cb1-72"><a href="#cb1-72" aria-hidden="true" tabindex="-1"></a>copyStaticFiles <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb1-73"><a href="#cb1-73" aria-hidden="true" tabindex="-1"></a>    filepaths <span class="ot">&lt;-</span> getDirectoryFiles <span class="st">&quot;./site/&quot;</span> [<span class="st">&quot;images//*&quot;</span>, <span class="st">&quot;css//*&quot;</span>, <span class="st">&quot;js//*&quot;</span>]</span>
<span id="cb1-74"><a href="#cb1-74" aria-hidden="true" tabindex="-1"></a>    void <span class="op">$</span> forP filepaths <span class="op">$</span> \filepath <span class="ot">-&gt;</span></span>
<span id="cb1-75"><a href="#cb1-75" aria-hidden="true" tabindex="-1"></a>        copyFileChanged (<span class="st">&quot;site&quot;</span> <span class="op">&lt;/&gt;</span> filepath) (outputFolder <span class="op">&lt;/&gt;</span> filepath)</span>
<span id="cb1-76"><a href="#cb1-76" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-77"><a href="#cb1-77" aria-hidden="true" tabindex="-1"></a><span class="co">-- | Specific build rules for the Shake system</span></span>
<span id="cb1-78"><a href="#cb1-78" aria-hidden="true" tabindex="-1"></a><span class="co">--   defines workflow to build the website</span></span>
<span id="cb1-79"><a href="#cb1-79" aria-hidden="true" tabindex="-1"></a><span class="ot">buildRules ::</span> <span class="dt">Action</span> ()</span>
<span id="cb1-80"><a href="#cb1-80" aria-hidden="true" tabindex="-1"></a>buildRules <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb1-81"><a href="#cb1-81" aria-hidden="true" tabindex="-1"></a>  allPosts <span class="ot">&lt;-</span> buildPosts</span>
<span id="cb1-82"><a href="#cb1-82" aria-hidden="true" tabindex="-1"></a>  buildIndex allPosts</span>
<span id="cb1-83"><a href="#cb1-83" aria-hidden="true" tabindex="-1"></a>  copyStaticFiles</span>
<span id="cb1-84"><a href="#cb1-84" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-85"><a href="#cb1-85" aria-hidden="true" tabindex="-1"></a><span class="co">-- | Kick it all off</span></span>
<span id="cb1-86"><a href="#cb1-86" aria-hidden="true" tabindex="-1"></a><span class="ot">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb1-87"><a href="#cb1-87" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb1-88"><a href="#cb1-88" aria-hidden="true" tabindex="-1"></a>  <span class="kw">let</span> shOpts <span class="ot">=</span> forwardOptions <span class="op">$</span> shakeOptions { shakeVerbosity <span class="ot">=</span> <span class="dt">Chatty</span>}</span>
<span id="cb1-89"><a href="#cb1-89" aria-hidden="true" tabindex="-1"></a>  shakeArgsForward shOpts buildRules</span></code></pre></div>
<p>See you next time!</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Haskell IDE Support (hie-core lsp Sept. 2019)</title>
      <link href="https://chrispenner.ca/posts/hie-core"/>
      <id>https://chrispenner.ca/posts/hie-core</id>
      <updated>2019-09-07T00:00:00Z</updated>
      <summary>Configuring editor support for Haskell (hie-core 2019)</summary>
      <content type="html"><![CDATA[
              <p><strong>EDIT</strong>: This project has been renamed to
<code>ghcide</code> now; you can find it <a
href="https://github.com/digital-asset/ghcide">here</a>!</p>
<p>Here's a super quick guide on adding hie-core to your workflow!</p>
<p>Disclaimer; this post depends on the state of the world as of
Saturday Morning, Sept. 7th 2019; it's likely changed since then. I'm
not a maintainer of any of these libraries, and this is a complicated
and confusing process. There's a good chance this won't work for you,
but I'm afraid I can't support every possible set up. Use it as a
guide-post, but you'll probably need to fix a few problems yourself.
Feel free to let me know if things are broken, but I make no guarantees
that I can help, sorry! Good luck!</p>
<p>This is a guide for using it with stack projects, or at least using
the stack tool. If your project isn't a stack project, you can probably
just run <code>stack init</code> first.</p>
<p><code>hie-core</code> currently requires a whole suite of tools to
run, including <code>hie-bios</code>, <code>hie-core</code>, and
<code>haskell-lsp</code>. Each of these need to be installed against the
proper GHC version and LTS that you'll be using in your project. This is
a bit annoying of course, but the end result is worth it.</p>
<p>We need separate binaries for every GHC version, so to avoid getting
them all confused, we'll install everything in LTS specific
sandboxes!</p>
<ul>
<li>First navigate to the project you want to run <code>hie-core</code>
with</li>
<li>Now <code>stack update</code>; sometimes stack doesn't keep your
hackage index up-to-date and most of the packages we'll be using are
pretty new.</li>
<li><code>stack build hie-bios hie-core haskell-lsp --copy-compiler-tool</code>
<ul>
<li>We need these three executables installed, using
<code>stack build</code> doesn't install them globally (which is what we
want to avoid conflicts), but <code>--copy-compiler-tool</code> allows
us to share binaries with other projects of the same LTS.</li>
<li>This will probably FAIL the first time you run it, stack will
suggest that you add extra-deps to your <code>stack.yaml</code>; go
ahead and do that and try again. Repeat this process until success!</li>
</ul></li>
</ul>
<p>If you've got all those running, time to go for a walk, or make a cup
of tea. It'll take a while.</p>
<p>If you're using an LTS OLDER than <code>14.1</code> then
<code>haskell-lsp</code> will probably be too old to work with
<code>hie-core</code>; you can <strong>try</strong> to fix it by adding
the following to your extra-deps:</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode yaml"><code class="sourceCode yaml"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="fu">extra-deps</span><span class="kw">:</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="kw">-</span><span class="at"> haskell-lsp-0.15.0.0</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="kw">-</span><span class="at"> haskell-lsp-types-0.15.0.0</span></span></code></pre></div>
<p>If that doesn't work, sorry, I really have no idea :'(</p>
<p>Okay, so now we've got all the tools installed we can start
configuring the editor. I can't tell you how to install it for every
possible editor, but the key parts to know is that it's a
<strong>language server</strong>, so search for integrations for your
editor that handle that protocol. Usually "$MyEditorName lsp" is a good
google search. Once you find a plugin you need to configure it.
Typically there's a spot in the settings to associate file-types with
the language server binary. Punch in the Haskell filetype or extensions
accordingly, the lsp binary is
<code>stack exec hie-core -- --lsp</code>; this'll use the
<code>hie-core</code> you install specifically for this LTS, and will
add the other dependencies to the path properly. You'll likely need to
specify the binary and arguments separately, see the following vim setup
for an example.</p>
<h2 id="vim-setup">Vim Setup</h2>
<p>Here's my setup for using <code>hie-core</code> with <a
href="https://neovim.io/">Neovim</a> using the amazing <a
href="https://github.com/neoclide/coc.nvim">Coc plugin</a>. Note that
you'll need to install Neovim from latest HEAD to get proper pop-up
support, if you're on a Mac you can do that with
<code>brew unlink neovim; brew install --HEAD neovim</code>.</p>
<p>Follow the instructions in the Coc README for installing that however
you like; then run <code>:CocConfig</code> inside neovim to open up the
config file.</p>
<p>Here's my current config:</p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode json"><code class="sourceCode json"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="dt">&quot;languageserver&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>  <span class="dt">&quot;haskell&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>    <span class="dt">&quot;command&quot;</span><span class="fu">:</span> <span class="st">&quot;stack&quot;</span><span class="fu">,</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>    <span class="dt">&quot;args&quot;</span><span class="fu">:</span> <span class="ot">[</span><span class="st">&quot;exec&quot;</span><span class="ot">,</span> <span class="st">&quot;hie-core&quot;</span><span class="ot">,</span> <span class="st">&quot;--&quot;</span><span class="ot">,</span> <span class="st">&quot;--lsp&quot;</span><span class="ot">]</span><span class="fu">,</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>    <span class="dt">&quot;rootPatterns&quot;</span><span class="fu">:</span> <span class="ot">[</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>      <span class="st">&quot;.stack.yaml&quot;</span><span class="ot">,</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>      <span class="st">&quot;cabal.config&quot;</span><span class="ot">,</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>      <span class="st">&quot;package.yaml&quot;</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>    <span class="ot">]</span><span class="fu">,</span></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a>    <span class="dt">&quot;filetypes&quot;</span><span class="fu">:</span> <span class="ot">[</span></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a>      <span class="st">&quot;hs&quot;</span><span class="ot">,</span></span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a>      <span class="st">&quot;lhs&quot;</span><span class="ot">,</span></span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a>      <span class="st">&quot;haskell&quot;</span></span>
<span id="cb2-15"><a href="#cb2-15" aria-hidden="true" tabindex="-1"></a>    <span class="ot">]</span><span class="fu">,</span></span>
<span id="cb2-16"><a href="#cb2-16" aria-hidden="true" tabindex="-1"></a>    <span class="dt">&quot;initializationOptions&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb2-17"><a href="#cb2-17" aria-hidden="true" tabindex="-1"></a>      <span class="dt">&quot;languageServerHaskell&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb2-18"><a href="#cb2-18" aria-hidden="true" tabindex="-1"></a>      <span class="fu">}</span></span>
<span id="cb2-19"><a href="#cb2-19" aria-hidden="true" tabindex="-1"></a>    <span class="fu">}</span></span>
<span id="cb2-20"><a href="#cb2-20" aria-hidden="true" tabindex="-1"></a>  <span class="fu">}</span></span>
<span id="cb2-21"><a href="#cb2-21" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span>
<span id="cb2-22"><a href="#cb2-22" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
<p>Also make sure to read the <a
href="https://github.com/neoclide/coc.nvim#example-vim-configuration">Sample
Vim Configuration</a> for Coc to set up bindings and such.</p>
<p>After you've done all that, I <strong>hope</strong> it's working for
you, if not, something crazy has probably changed and you're probably on
your own. Good luck!</p>
<p>PS; I have a little bash script I use for installing this in every
new project in case you want to see how terrible I am at writing BASH.
It includes a helper which auto-adds all the necessary extra-deps for
you: <a
href="https://github.com/ChrisPenner/dotfiles/blob/master/bin/hie-init">My
crappy bash script</a></p>
<p>You'll probably need to run the script more than once as it attempts
to add all the needed extra-deps. Hopefully this'll get better as these
tools get added to stackage.</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Higher Kinded Option Parsing</title>
      <link href="https://chrispenner.ca/posts/hkd-options"/>
      <id>https://chrispenner.ca/posts/hkd-options</id>
      <updated>2019-05-04T00:00:00Z</updated>
      <summary>Collecting options for your application from multiple sources using
Higher Kinded Data</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/hkd-option-parsing/tools.jpg" alt="Higher Kinded Option Parsing">
              <p>Higher Kinded Data Types (HKDTs) have piqued my interest lately. They
seem to have a lot of potential applications, however the ergonomics
still aren't so great in most of these cases. Today we'll look at one
case where I think the end result ends up quite nice! Let's parse some
options!</p>
<p>First the problem; if you've worked on a non-trivial production app
you've probably come across what I'll call the <strong>Configuration
Conundrum</strong>. Specifically, this is when an app collects
configuration values from <em>many sources</em>. Maybe it parses some
options from CLI flags, some from Environment Variables, yet more come
from a configuration file in JSON or YAML or TOML or or even worse it
may pull from SEVERAL files. Working with these is a mess, option
priority gets tricky, providing useful error messages gets even harder,
and the code for managing all these sources is confusing, complicated,
and spread out. Though we may not solve ALL these problems today, we'll
build an approach that's modular and extensible enough that you can mix
and match bits and pieces to get whatever you need.</p>
<p>Here's an example of some messy code which pulls options from the
environment or from a JSON value file:</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">getOptions ::</span> <span class="dt">IO</span> <span class="dt">Options</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>getOptions <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>    configJson <span class="ot">&lt;-</span> readConfigFile</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>    mServerHostEnv <span class="ot">&lt;-</span> readServerHostEnv</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>    mNumThreadsEnv <span class="ot">&lt;-</span> readNumThreadsEnv</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> mServerHostJson <span class="ot">=</span> configJson <span class="op">^?</span> key <span class="st">&quot;server_host&quot;</span> <span class="op">.</span> _String <span class="op">.</span> unpacked</span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> mNumThreadsJson <span class="ot">=</span> configJson <span class="op">^?</span> key <span class="st">&quot;num_threads&quot;</span> <span class="op">.</span> _Number <span class="op">.</span> to <span class="fu">round</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>    <span class="fu">return</span> <span class="op">$</span> <span class="dt">Options</span> <span class="op">&lt;$&gt;</span> fromMaybe serverHostDef (mServerHostEnv <span class="op">&lt;|&gt;</span> mServerHostJson)</span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>                     <span class="op">&lt;*&gt;</span> fromMaybe numThreadsDef (mNumThreadsEnv <span class="op">&lt;|&gt;</span> mNumThreadsJson)</span></code></pre></div>
<p>Here's a peek at how our configuration parsing code will end up:</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">getOptions ::</span> <span class="dt">IO</span> <span class="dt">Options</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>getOptions <span class="ot">=</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>  withDefaults defaultOpts <span class="op">&lt;$&gt;</span> fold [envOpts, jsonOptsCustom <span class="op">&lt;$&gt;</span> readConfigFile]</span></code></pre></div>
<p>This is slightly disingenuous as some of the logic is abstracted away
behind the scenes in the second example; but the point here is that the
logic CAN be abstracted, whereas it's very difficult to abstract over
the steps in the first example without creating a bunch of intermediate
types.</p>
<h2 id="kinds-of-options">Kinds of Options</h2>
<p>If you're unfamiliar with HKDTs (higher kinded data types); it's a
very simple idea with some mind bending implications. Many data types
are parameterized by a value type (e.g. <code>[a]</code> is a list is
parameterized by the types of values it contains); however HKDTs are
parameterized by some <strong>wrapper</strong> type (typically a
functor, but not always) around the data of the record. Easiest to just
show an example and see it in practice. Let's define a very simple type
to contain all the options our app needs:</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">Options_</span> f <span class="ot">=</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Options_</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>    {<span class="ot"> serverHost ::</span> f <span class="dt">String</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>    ,<span class="ot"> numThreads ::</span> f <span class="dt">Int</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>    ,<span class="ot"> verbosity  ::</span> f <span class="dt">Int</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>    }</span></code></pre></div>
<p>Notice that each field is <em>wrapped</em> in <code>f</code>. I use a
<code>_</code> suffix as a convention to denote that it's a HKDT.
<code>f</code> could be anything at all of the kind
<code>Type -&gt; Type</code>; e.g. <code>Maybe</code>, <code>IO</code>,
<code>Either String</code>, or even strange constructions like
<code>Compose Maybe (Join (Biff (,) IO Reader))</code> ! You'll discover
the implications as we go along, so don't worry if you don't get it yet.
For our first example we'll describe how to get options from Environment
Variables!</p>
<h2 id="getting-environment-variables">Getting Environment
Variables</h2>
<p>Applications will often set configuration values using Environment
Variables; it's an easy way to implicitly pass information into programs
and is nice for sensitive data like secrets. We can describe the options
in our HKDT in terms of Environment Variables which may or may not
exist. First we'll need a way to lookup an option for a given key, and a
way to convert it into the type we expect. You may want to use something
more sophisticated in your app; but for the blog post I'll just lean on
the <code>Read</code> typeclass to make a small helper.</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">import</span> <span class="dt">System.Environment</span> (lookupEnv, setEnv)</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Text.Read</span> (readMaybe)</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 class="ot">readEnv ::</span> <span class="dt">Read</span> a <span class="ot">=&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> (<span class="dt">Maybe</span> a)</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>readEnv envKey <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>    lookupEnv envKey <span class="op">&gt;&gt;=</span> <span class="fu">pure</span> <span class="op">.</span> \<span class="kw">case</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Just</span> x <span class="ot">-&gt;</span> readMaybe x</span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Nothing</span> <span class="ot">-&gt;</span> <span class="dt">Nothing</span></span></code></pre></div>
<p>This function looks up the given key in the environment, returning a
<code>Nothing</code> if it doesn't exist or fails to parse. We'll talk
about more civilized error handling later on, don't worry ;)</p>
<p>Now we can describe how to get each option in our type using this
construct:</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="co">-- This doesn&#39;t work!</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="ot">envOpts ::</span> <span class="dt">Options_</span> <span class="op">??</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>envOpts <span class="ot">=</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>    <span class="dt">OptionsF</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>    { serverHost <span class="ot">=</span> readEnv <span class="st">&quot;SERVER_HOST&quot;</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a>    , numThreads <span class="ot">=</span> readEnv <span class="st">&quot;NUM_THREADS&quot;</span></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>    , verbosity  <span class="ot">=</span> <span class="fu">pure</span> <span class="dt">Nothing</span> <span class="co">-- Don&#39;t read verbosity from environment</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>    }</span></code></pre></div>
<p>Close; but if you'll note earlier, each field should contain field's
underlying type wrapped in some <code>f</code>. Here we've got
<code>IO (Maybe a)</code>, we can't assign <code>f</code> to
<code>IO (Maybe _)</code> so we need to compose the two Functors
somehow. We can employ <code>Compose</code> here to collect both
<code>IO</code> and <code>Maybe</code> into a single Higher Kinded Type
to serve as our <code>f</code>. Try the following instead:</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="kw">import</span> <span class="dt">Data.Functor.Compose</span> (<span class="dt">Compose</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="co">-- Add a Compose to our helper</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="ot">readEnv ::</span> <span class="dt">Read</span> a <span class="ot">=&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> (<span class="dt">IO</span> <span class="ot">`Compose`</span> <span class="dt">Maybe</span>) a</span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>readEnv envKey <span class="ot">=</span> <span class="dt">Compose</span> <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">...</span></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a><span class="ot">envOpts ::</span> <span class="dt">Options_</span> (<span class="dt">IO</span> <span class="ot">`Compose`</span> <span class="dt">Maybe</span>)</span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a>envOpts <span class="ot">=</span></span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a>    <span class="dt">OptionsF</span></span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a>    { serverHost <span class="ot">=</span> readEnv <span class="st">&quot;SERVER_HOST&quot;</span></span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a>    , numThreads <span class="ot">=</span> readEnv <span class="st">&quot;NUM_THREADS&quot;</span></span>
<span id="cb6-13"><a href="#cb6-13" aria-hidden="true" tabindex="-1"></a>    , verbosity  <span class="ot">=</span> <span class="dt">Compose</span> <span class="op">$</span> <span class="fu">pure</span> <span class="dt">Nothing</span> <span class="co">-- Don&#39;t read verbosity from environment</span></span>
<span id="cb6-14"><a href="#cb6-14" aria-hidden="true" tabindex="-1"></a>    }</span></code></pre></div>
<p>I personally find it more readable to write <code>Compose</code> as
infix like this, but some disagree. Very cool; we've got a version of
our record where each field contains an action which gets and parses the
right value from the environment! It's clear at a glance that we haven't
forgotten to check any fields (if you have <code>-Wall</code> enabled
you'd get a warning about missing fields)! We've effectively turned the
traditional <code>Options &lt;$&gt; ... &lt;*&gt; ...</code> design
<strong>inside out</strong>. It's much more declarative this way, and
now that it's all collected as structured data it'll be easier for us to
work with from now on too!</p>
<p>Let's build another one!</p>
<h2 id="parsing-jsonyaml-configs">Parsing JSON/YAML Configs</h2>
<p>JSON and YAML configuration files are pretty common these days. I
won't bother to dive into where to store them or how we'll parse them,
let's assume you've done that already and just pretend we've got
ourselves an Aeson <code>Value</code> object from some config file and
we want to dump the values into our options object.</p>
<p>We have two options here and I'll show both! The simplest is just to
derive <code>FromJSON</code> and cast the value directly into our
type!</p>
<p>Unfortunately it's not quite so easy as just tacking on a
<code>deriving FromJSON</code>; Since GHC doesn't know what type
<code>f</code> is it has a tough time figuring out what you want it to
do. If you try you'll get an error like:</p>
<pre><code>• No instance for (FromJSON (f String))</code></pre>
<p>We need to help out GHC a bit. No worries though; someone thought of
that! Time to pull in the <a
href="http://hackage.haskell.org/package/barbies"><code>barbies</code></a>
library. An incredibly useful tool for working with HKDT in general. Add
the <code>barbies</code> library to your project, then we'll derive a
few handy instances:</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">{-# LANGUAGE DeriveGeneric #-}</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE DeriveAnyClass #-}</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE StandaloneDeriving #-}</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="co">-- ...</span></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">GHC.Generics</span> (<span class="dt">Generic</span>)</span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Data.Aeson</span> <span class="kw">as</span> <span class="dt">A</span></span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Barbie</span></span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a><span class="co">-- ...</span></span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a><span class="co">-- Go back and add the deriving clause:</span></span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Options_</span> f <span class="ot">=</span></span>
<span id="cb8-12"><a href="#cb8-12" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Options_</span> {<span class="op">...</span>}</span>
<span id="cb8-13"><a href="#cb8-13" aria-hidden="true" tabindex="-1"></a>    <span class="kw">deriving</span> (<span class="dt">Generic</span>, <span class="dt">FunctorB</span>, <span class="dt">TraversableB</span>, <span class="dt">ProductB</span>, <span class="dt">ConstraintsB</span>, <span class="dt">ProductBC</span>)</span>
<span id="cb8-14"><a href="#cb8-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-15"><a href="#cb8-15" aria-hidden="true" tabindex="-1"></a><span class="kw">deriving</span> <span class="kw">instance</span> (<span class="dt">AllBF</span> <span class="dt">Show</span> f <span class="dt">Options_</span>) <span class="ot">=&gt;</span> <span class="dt">Show</span> (<span class="dt">Options_</span> f)</span>
<span id="cb8-16"><a href="#cb8-16" aria-hidden="true" tabindex="-1"></a><span class="kw">deriving</span> <span class="kw">instance</span> (<span class="dt">AllBF</span> <span class="dt">Eq</span> f <span class="dt">Options_</span>) <span class="ot">=&gt;</span> <span class="dt">Eq</span> (<span class="dt">Options_</span> f)</span>
<span id="cb8-17"><a href="#cb8-17" aria-hidden="true" tabindex="-1"></a><span class="kw">deriving</span> <span class="kw">instance</span> (<span class="dt">AllBF</span> <span class="dt">A.FromJSON</span> f <span class="dt">Options_</span>) <span class="ot">=&gt;</span> <span class="dt">A.FromJSON</span> (<span class="dt">Options_</span> f)</span></code></pre></div>
<p>Okay! Let's step through some of that. First we derive
<code>Generic</code>, it's used by both <code>aeson</code> and
<code>barbies</code> for most of their type classes. We derive a bunch
of handy <code>*B</code> helpers (B for Barbies) which also come from
the <code>barbies</code> lib, we'll explain them as we use them. The
important part right now is the <code>deriving instance</code> clauses.
<code>AllBF</code> from <code>barbies</code> asserts that
<strong>all</strong> the wrapped fields of the typeclass adhere to some
type class. For example, <code>AllBF Show f Options_</code> says that
<code>f a</code> is Showable for every field in our product. More
concretely, in our case <code>AllBF Show f Options</code> expands into
something equivalent to <code>(Show (f String), Show (f Int))</code>
since we have fields of type <code>String</code> and <code>Int</code>.
Nifty! So we can now derive type classes with behaviour dependent on the
wrapping type. In most cases this works as expected, and can sometimes
be really handy!</p>
<p>One example where this ends up being useful is <code>FromJSON</code>.
The behaviour of our <code>FromJSON</code> instance will depend on the
wrapper type; if we choose <code>f ~ Maybe</code> then all of our fields
become optional! Let's use this behaviour to say that we want to parse
our JSON file into an <code>Options</code> object, but it's okay if
fields are missing.</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">import</span> <span class="dt">Control.Lens</span></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="ot">jsonOptsDerived ::</span> <span class="dt">A.Value</span> <span class="ot">-&gt;</span> <span class="dt">Options_</span> <span class="dt">Maybe</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>jsonOptsDerived <span class="ot">=</span> fromResult <span class="op">.</span> A.fromJSON</span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a><span class="ot">    fromResult ::</span> <span class="dt">A.Result</span> (<span class="dt">Options_</span> <span class="dt">Maybe</span>) <span class="ot">-&gt;</span> <span class="dt">Options_</span> <span class="dt">Maybe</span></span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a>    fromResult (<span class="dt">A.Success</span> a) <span class="ot">=</span> a</span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a>    fromResult (<span class="dt">A.Error</span> _) <span class="ot">=</span> buniq <span class="dt">Nothing</span></span></code></pre></div>
<p>A few things to point out here; we call
<code>fromJson :: FromJSON a =&gt; Value -&gt; Result a</code> here, but
we don't really need the outer <code>Result</code> type; we'd prefer if
the failure was localized at the individual field level; simply using
<code>Nothing</code> for fields which are missing. So we use
<code>fromResult</code> to unpack the result if successful, or to
construct an <code>Options_ Maybe</code> filled completely with
<code>Nothing</code> if the parsing fails for some reason (you'll
probably want to come back an improve this error handling behaviour
later). You'll notice that nothing we do really has much to do with
<code>Options_</code>; so let's generalize this into a combinator we can
re-use in the future:</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">jsonOptsDerived ::</span> (<span class="dt">A.FromJSON</span> (b <span class="dt">Maybe</span>), <span class="dt">ProductB</span> b) <span class="ot">=&gt;</span> <span class="dt">A.Value</span> <span class="ot">-&gt;</span> b <span class="dt">Maybe</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>jsonOptsDerived <span class="ot">=</span> fromResult <span class="op">.</span> A.fromJSON</span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a><span class="ot">    fromResult ::</span> <span class="dt">ProductB</span> b <span class="ot">=&gt;</span> <span class="dt">A.Result</span> (b <span class="dt">Maybe</span>) <span class="ot">-&gt;</span> b <span class="dt">Maybe</span></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>    fromResult (<span class="dt">A.Success</span> a) <span class="ot">=</span> a</span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a>    fromResult (<span class="dt">A.Error</span> _) <span class="ot">=</span> buniq <span class="dt">Nothing</span></span></code></pre></div>
<p><code>buniq</code> requires a <code>ProductB</code> constraint which
asserts that the type we're constructing is a Record type or some other
Product. This is required because <code>buniq</code> wouldn't know which
constructor to instantiate if it were a Sum-type.</p>
<p>Okay, we've seen the generic version; here's a different approach
where we can choose HOW to deserialize each option from the provided
<code>Value</code>.</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">import</span> <span class="dt">Data.Text.Lens</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Aeson.Lens</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Lens</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a><span class="ot">jsonOptsCustom ::</span> <span class="dt">A.Value</span> <span class="ot">-&gt;</span> <span class="dt">Options_</span> <span class="dt">Maybe</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>jsonOptsCustom <span class="ot">=</span> bsequence</span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Options_</span></span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a>    { serverHost <span class="ot">=</span> findField <span class="op">$</span> key <span class="st">&quot;host&quot;</span>        <span class="op">.</span> _String <span class="op">.</span> unpacked</span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a>    , numThreads <span class="ot">=</span> findField <span class="op">$</span> key <span class="st">&quot;num_threads&quot;</span> <span class="op">.</span> _Number <span class="op">.</span> to <span class="fu">round</span></span>
<span id="cb11-10"><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a>    , verbosity  <span class="ot">=</span> findField <span class="op">$</span> key <span class="st">&quot;verbosity&quot;</span>   <span class="op">.</span> _Number <span class="op">.</span> to <span class="fu">round</span></span>
<span id="cb11-11"><a href="#cb11-11" aria-hidden="true" tabindex="-1"></a>    }</span>
<span id="cb11-12"><a href="#cb11-12" aria-hidden="true" tabindex="-1"></a>      <span class="kw">where</span></span>
<span id="cb11-13"><a href="#cb11-13" aria-hidden="true" tabindex="-1"></a><span class="ot">        findField ::</span> <span class="dt">Fold</span> <span class="dt">A.Value</span> a <span class="ot">-&gt;</span> <span class="dt">Compose</span> ((<span class="ot">-&gt;</span>) <span class="dt">A.Value</span>) <span class="dt">Maybe</span> a</span>
<span id="cb11-14"><a href="#cb11-14" aria-hidden="true" tabindex="-1"></a>        findField p <span class="ot">=</span> <span class="dt">Compose</span> (preview p)</span></code></pre></div>
<p>Some of these types get a bit funky; but IMHO they wouldn't be too
terrible if this were all bundled up in some lib for readability. As I
said earlier, some of the ergonomics still have room for
improvement.</p>
<p>Let's talk about what this thing does! First we import a bunch of
lensy stuff; then in each field of our options type we build a getter
function from <code>Value -&gt; Maybe a</code> which tries to extract
the field from the JSON Value. <code>preview</code> mixed with
<code>Data.Aeson.Lens</code> happens to be a handy way to do this. I
pulled out the <code>findField</code> helper mainly to draw attention to
the rather cryptic <code>Compose ((-&gt;) A.Value) Maybe a</code> type
signature. This is just <code>Compose</code> wrapped around a function
<code>A.Value -&gt; Maybe a</code>; why do we need the
<code>Compose</code> here? What we REALLY want is
<code>A.Value -&gt; Option_ Maybe</code>; but remember that every field
MUST contain something that matches <code>f a</code> for some
<code>f</code>. A function signature like
<code>A.Value -&gt; Maybe a</code> doesn't match this form, but
<code>Compose ((-&gt;) A.Value) Maybe a</code> does (where
<code>f ~ Compose ((-&gt;) A.Value) Maybe</code>)! Ideally we'd then
like to pull the function bits to the outside since we'll be calling
each field with the same argument. Conveniently; <code>barbies</code>
provides us with <code>bsequence</code>; whose type looks like this:</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">bsequence ::</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>  (<span class="dt">Applicative</span> f, <span class="dt">TraversableB</span> b) <span class="ot">=&gt;</span></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>  b (<span class="dt">Compose</span> f g) <span class="ot">-&gt;</span> f (b g)</span></code></pre></div>
<p>Or if we specialize it to this particular case:</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">bsequence ::</span> <span class="dt">Options_</span> (<span class="dt">Compose</span> ((<span class="ot">-&gt;</span>) <span class="dt">A.Value</span>) <span class="dt">Maybe</span>)</span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>          <span class="ot">-&gt;</span> (<span class="dt">A.Value</span> <span class="ot">-&gt;</span> <span class="dt">Options_</span> <span class="dt">Maybe</span>)</span></code></pre></div>
<p>We use the <code>-&gt;</code> applicative (also known as
<code>Reader</code>) to extract the function Functor to the outside of
the structure! This of course requires that the individual fields can be
traversed; implying the <code>TraversableB</code> constraint. Hopefully
this demonstrates the flexibility of this technique, we can provide an
arbitrary lens chain to extract the value for each setting, maybe it's
overkill in this case, but I can think of a few situations where it
would be pretty handy.</p>
<p>While we're at it, let's <code>bsequence</code> our earlier
Environment Variable object to get the IO on the outside!</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">envOpts ::</span> <span class="dt">IO</span> (<span class="dt">Options_</span> <span class="dt">Maybe</span>)</span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a>envOpts <span class="ot">=</span> bsequence</span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Options_</span></span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- serverHost is already a string so we don&#39;t need to &#39;read&#39; it.</span></span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a>    { serverHost <span class="ot">=</span> <span class="dt">Compose</span> <span class="op">.</span> lookupEnv <span class="op">$</span> <span class="st">&quot;SERVER_HOST&quot;</span></span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a>    , numThreads <span class="ot">=</span> readEnv <span class="st">&quot;NUM_THREADS&quot;</span></span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- We can &#39;ignore&#39; a field by simply returning Nothing.</span></span>
<span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a>    , verbosity    <span class="ot">=</span> <span class="dt">Compose</span> <span class="op">.</span> <span class="fu">pure</span> <span class="op">$</span> <span class="dt">Nothing</span></span>
<span id="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a>    }</span></code></pre></div>
<p>This is dragging on a bit; let's see how we can actually use these
things!</p>
<h2 id="combining-options-objects">Combining Options Objects</h2>
<p>Now that we've got two different ways to collect options for our
program let's see how we can combine them. Let's write a simple action
in IO for getting and combining our options parsers.</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="kw">import</span> <span class="dt">Control.Applicative</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a><span class="co">-- Fake config file for convenience</span></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a><span class="ot">readConfigFile ::</span> <span class="dt">IO</span> <span class="dt">A.Value</span></span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a>readConfigFile <span class="ot">=</span></span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a>    <span class="fu">pure</span> <span class="op">$</span> A.object [ <span class="st">&quot;host&quot;</span> <span class="op">A..=</span> <span class="dt">A.String</span> <span class="st">&quot;example.com&quot;</span></span>
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a>                    , <span class="st">&quot;verbosity&quot;</span> <span class="op">A..=</span> <span class="dt">A.Number</span> <span class="dv">42</span></span>
<span id="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a>                    ]</span>
<span id="cb15-9"><a href="#cb15-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-10"><a href="#cb15-10" aria-hidden="true" tabindex="-1"></a><span class="ot">getOptions ::</span> <span class="dt">IO</span> (<span class="dt">Options_</span> <span class="dt">Maybe</span>)</span>
<span id="cb15-11"><a href="#cb15-11" aria-hidden="true" tabindex="-1"></a>getOptions <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb15-12"><a href="#cb15-12" aria-hidden="true" tabindex="-1"></a>    configJson <span class="ot">&lt;-</span> readConfigFile</span>
<span id="cb15-13"><a href="#cb15-13" aria-hidden="true" tabindex="-1"></a>    envOpts&#39; <span class="ot">&lt;-</span> envOpts</span>
<span id="cb15-14"><a href="#cb15-14" aria-hidden="true" tabindex="-1"></a>    <span class="fu">return</span> <span class="op">$</span> bzipWith (<span class="op">&lt;|&gt;</span>) envOpts&#39; (jsonOptsCustom configJson)</span></code></pre></div>
<p>Let's try it out, then I'll explain it.</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="op">&gt;</span> getOptions</span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Options_</span> {serverHost <span class="ot">=</span> <span class="dt">Just</span> <span class="st">&quot;example.com&quot;</span>, numThreads <span class="ot">=</span> <span class="dt">Nothing</span>, verbosity <span class="ot">=</span> <span class="dt">Just</span> <span class="dv">42</span>}</span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> setEnv <span class="st">&quot;NUM_THREADS&quot;</span> <span class="st">&quot;1337&quot;</span></span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> getOptions</span>
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a><span class="dt">Options_</span> {serverHost <span class="ot">=</span> <span class="dt">Just</span> <span class="st">&quot;example.com&quot;</span>, numThreads <span class="ot">=</span> <span class="dt">Just</span> <span class="dv">1337</span>, verbosity <span class="ot">=</span> <span class="dt">Just</span> <span class="dv">42</span>}</span>
<span id="cb16-7"><a href="#cb16-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-8"><a href="#cb16-8" aria-hidden="true" tabindex="-1"></a><span class="co">-- We&#39;ve set things up so that environment variables override our JSON config.</span></span>
<span id="cb16-9"><a href="#cb16-9" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> setEnv <span class="st">&quot;SERVER_HOST&quot;</span> <span class="st">&quot;chrispenner.ca&quot;</span></span>
<span id="cb16-10"><a href="#cb16-10" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> getOptions</span>
<span id="cb16-11"><a href="#cb16-11" aria-hidden="true" tabindex="-1"></a><span class="dt">Options_</span> {serverHost <span class="ot">=</span> <span class="dt">Just</span> <span class="st">&quot;chrispenner.ca&quot;</span>, numThreads <span class="ot">=</span> <span class="dt">Just</span> <span class="dv">1337</span>, verbosity <span class="ot">=</span> <span class="dt">Just</span> <span class="dv">42</span>}</span></code></pre></div>
<p>Now that we're combining sets of config values we need to decide what
semantics we want when values overlap! I've decided to use
<code>&lt;|&gt;</code> from <code>Alternative</code> to combine our
<code>Maybe</code> values. This basically means "take the first
non-Nothing value and ignore the rest". That means in our case that the
first setting to be "set" wins out. <code>bzipWith</code> performs
element-wise zipping of each element within our <code>Options_</code>
record, with the caveat that the function you give it must work over any
possible <code>a</code> contained inside. In our case the type is
specialized to:</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="ot">bzipWith  ::</span> (<span class="kw">forall</span> a<span class="op">.</span> <span class="dt">Maybe</span> a <span class="ot">-&gt;</span> <span class="dt">Maybe</span> a <span class="ot">-&gt;</span> <span class="dt">Maybe</span> a)</span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a>          <span class="ot">-&gt;</span> <span class="dt">Options_</span> <span class="dt">Maybe</span> <span class="ot">-&gt;</span> <span class="dt">Options_</span> <span class="dt">Maybe</span> <span class="ot">-&gt;</span> <span class="dt">Options_</span> <span class="dt">Maybe</span></span></code></pre></div>
<p>Which does what we want. This end bit is going to get messy if we add
any more sources though, let's see if we can't clean it up! My first
thought is that I'd love to use <code>&lt;|&gt;</code> without any
lifting/zipping, but the kinds don't line up; <code>Options_</code> is
kind <code>(Type -&gt; Type) -&gt; Type</code> whereas
<code>Type -&gt; Type</code> is required by <code>Alternative</code>.
How do we lift Alternative to Higher Kinds? Well we could try something
clever, <strong>OR</strong> we could go the opposite direction and use
<code>Alternative</code> to build a <code>Monoid</code> instance for our
type; then use that to combine our values!</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">instance</span> (<span class="dt">Alternative</span> f) <span class="ot">=&gt;</span> <span class="dt">Semigroup</span> (<span class="dt">Options_</span> f) <span class="kw">where</span></span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a>  (<span class="op">&lt;&gt;</span>) <span class="ot">=</span> bzipWith (<span class="op">&lt;|&gt;</span>)</span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> (<span class="dt">Alternative</span> f) <span class="ot">=&gt;</span> <span class="dt">Monoid</span> (<span class="dt">Options_</span> f) <span class="kw">where</span></span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a>  <span class="fu">mempty</span> <span class="ot">=</span> buniq empty</span></code></pre></div>
<p>Now we have a Monoid for <code>Options_</code> whenever
<code>f</code> is an <code>Alternative</code> such as
<code>Maybe</code>! There are many possible <code>Monoid</code> instance
for HKDTs, but in our case it works great! <code>Alternative</code> is
actually just a Monoid in the category of Applicative Functors, so it
makes sense that it makes a suitable Monoid if we apply it to values
within an HKDT.</p>
<p>Let's see how we can refactor things.</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="ot">getOptions ::</span> <span class="dt">IO</span> (<span class="dt">Options_</span> <span class="dt">Maybe</span>)</span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a>getOptions <span class="ot">=</span> envOpts <span class="op">&lt;&gt;</span> (jsonOptsCustom <span class="op">&lt;$&gt;</span> readConfigFile)</span></code></pre></div>
<p>Wait a minute; what about the <code>IO</code>? Here I'm actually
employing <code>IO</code>s little known Monoid instance! <code>IO</code>
is a Monoid whenever the result of the <code>IO</code> is a Monoid; it
simply runs both <code>IO</code> actions then <code>mappends</code> the
results (e.g. <code>liftA2 (&lt;&gt;)</code>). In this case it's
perfect! As we get even more possible option parsers we could even just
put them in a list and <code>fold</code> them together:
<code>fold [envOpts, jsonOptsCustom &lt;$&gt; readConfigFile, ...]</code></p>
<p>But wait! There's more!</p>
<h2 id="setting-default-values">Setting Default Values</h2>
<p>We've seen how we can specify multiple <strong>partial</strong>
configuration sources, but at the end of the day we're still left with
an <code>Options_ Maybe</code>! What if we want to guarantee that we
have a value for all required config values? Let's write a new
helper.</p>
<div class="sourceCode" id="cb20"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="ot">withDefaults ::</span> <span class="dt">ProductB</span> b <span class="ot">=&gt;</span> b <span class="dt">Identity</span> <span class="ot">-&gt;</span> b <span class="dt">Maybe</span> <span class="ot">-&gt;</span> b <span class="dt">Identity</span></span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a>withDefaults <span class="ot">=</span> bzipWith fromMaybeI</span>
<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a><span class="ot">    fromMaybeI ::</span> <span class="dt">Identity</span> a <span class="ot">-&gt;</span> <span class="dt">Maybe</span> a <span class="ot">-&gt;</span> <span class="dt">Identity</span> a</span>
<span id="cb20-5"><a href="#cb20-5" aria-hidden="true" tabindex="-1"></a>    fromMaybeI (<span class="dt">Identity</span> a) <span class="dt">Nothing</span>  <span class="ot">=</span> <span class="dt">Identity</span> a</span>
<span id="cb20-6"><a href="#cb20-6" aria-hidden="true" tabindex="-1"></a>    fromMaybeI _            (<span class="dt">Just</span> a) <span class="ot">=</span> <span class="dt">Identity</span> a</span></code></pre></div>
<p>This new helper uses our old friend <code>bzipWith</code> to lift a
slightly altered <code>fromMaybe</code> to run over HKDTs! We have to do
a little bit of annoying wrapping/unwrapping of Identity, but it's not
too bad. This function will take the config value from any
<code>Just</code>'s in our <code>Options_ Maybe</code> and will choose
the default for the <code>Nothing</code>s!</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="kw">import</span> <span class="dt">Data.Foldable</span></span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a><span class="co">---</span></span>
<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">Options</span> <span class="ot">=</span> <span class="dt">Options_</span> <span class="dt">Identity</span></span>
<span id="cb21-4"><a href="#cb21-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-5"><a href="#cb21-5" aria-hidden="true" tabindex="-1"></a><span class="ot">getOptions ::</span> <span class="dt">IO</span> <span class="dt">Options</span></span>
<span id="cb21-6"><a href="#cb21-6" aria-hidden="true" tabindex="-1"></a>getOptions <span class="ot">=</span></span>
<span id="cb21-7"><a href="#cb21-7" aria-hidden="true" tabindex="-1"></a>  withDefaults defaultOpts <span class="op">&lt;$&gt;</span> fold [envOpts, jsonOptsCustom <span class="op">&lt;$&gt;</span> readConfigFile]</span></code></pre></div>
<p>We introduce the alias <code>type Options = Options_ Identity</code>
as a convenience.</p>
<h2 id="better-errors">Better Errors</h2>
<p>So far our system silently fails in a lot of places. Let's see how
HKDTs can give us more expressive error handling!</p>
<p>The first cool thing is that we can store error messages directly
alongside fields they pertain to!</p>
<div class="sourceCode" id="cb22"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE OverloadedStrings #-}</span></span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a><span class="co">---</span></span>
<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a><span class="ot">optErrors ::</span> <span class="dt">Options_</span> (<span class="dt">Const</span> <span class="dt">String</span>)</span>
<span id="cb22-4"><a href="#cb22-4" aria-hidden="true" tabindex="-1"></a>optErrors <span class="ot">=</span></span>
<span id="cb22-5"><a href="#cb22-5" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Options_</span></span>
<span id="cb22-6"><a href="#cb22-6" aria-hidden="true" tabindex="-1"></a>    { serverHost <span class="ot">=</span> <span class="st">&quot;server host required but not provided&quot;</span></span>
<span id="cb22-7"><a href="#cb22-7" aria-hidden="true" tabindex="-1"></a>    , numThreads <span class="ot">=</span> <span class="st">&quot;num threads required but not provided&quot;</span></span>
<span id="cb22-8"><a href="#cb22-8" aria-hidden="true" tabindex="-1"></a>    , verbosity  <span class="ot">=</span> <span class="st">&quot;verbosity required but not provided&quot;</span></span>
<span id="cb22-9"><a href="#cb22-9" aria-hidden="true" tabindex="-1"></a>    }</span></code></pre></div>
<p>If we use <code>Const String</code> in our HKDT we are saying that we
actually don't care about the type of the field itself, we just want to
store a string no matter what! If we turn on
<code>OverloadedStrings</code> we can even leave out the
<code>Const</code> constructor if we like! But I'll leave that choice up
to you.</p>
<p>Now that we've got errors which relate to each field we can construct
a helpful error message if we're missing required fields:</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="kw">import</span> <span class="dt">Data.Either.Validation</span></span>
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a><span class="co">---</span></span>
<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a><span class="ot">validateOptions ::</span> (<span class="dt">TraversableB</span> b, <span class="dt">ProductB</span> b)</span>
<span id="cb23-4"><a href="#cb23-4" aria-hidden="true" tabindex="-1"></a>                <span class="ot">=&gt;</span> b (<span class="dt">Const</span> <span class="dt">String</span>)</span>
<span id="cb23-5"><a href="#cb23-5" aria-hidden="true" tabindex="-1"></a>                <span class="ot">-&gt;</span> b <span class="dt">Maybe</span></span>
<span id="cb23-6"><a href="#cb23-6" aria-hidden="true" tabindex="-1"></a>                <span class="ot">-&gt;</span> <span class="dt">Validation</span> [<span class="dt">String</span>] (b <span class="dt">Identity</span>)</span>
<span id="cb23-7"><a href="#cb23-7" aria-hidden="true" tabindex="-1"></a>validateOptions errMsgs mOpts <span class="ot">=</span> bsequence&#39; <span class="op">$</span> bzipWith validate mOpts errMsgs</span>
<span id="cb23-8"><a href="#cb23-8" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb23-9"><a href="#cb23-9" aria-hidden="true" tabindex="-1"></a><span class="ot">    validate ::</span> <span class="dt">Maybe</span> a <span class="ot">-&gt;</span> <span class="dt">Const</span> <span class="dt">String</span> a <span class="ot">-&gt;</span> <span class="dt">Validation</span> [<span class="dt">String</span>] a</span>
<span id="cb23-10"><a href="#cb23-10" aria-hidden="true" tabindex="-1"></a>    validate (<span class="dt">Just</span> x) _          <span class="ot">=</span> <span class="dt">Success</span> x</span>
<span id="cb23-11"><a href="#cb23-11" aria-hidden="true" tabindex="-1"></a>    validate <span class="dt">Nothing</span> (<span class="dt">Const</span> err) <span class="ot">=</span> <span class="dt">Failure</span> [err]</span></code></pre></div>
<p><code>validateOptions</code> takes any traversable product HKDT with
<code>Maybe</code> fields and an HKDT filled with error messages inside
<code>Const</code> and will return a <code>Validation</code> object
containing either a summary of errors or a validated
<code>Identity</code> HKDT. Just as before we use <code>bzipWith</code>
with a function which operates at the level of functors as a Natural
Transformation; i.e. it cares only about the containers, not the values.
Note that Validation is very similar to the <code>Either</code> type,
but accumulates all available errors rather than failing fast. We use
<code>bsequence'</code> here, which is just like <code>bsequence</code>;
but saves us the trouble of explicitly threading an
<code>Identity</code> into our structure. Check the docs in
<code>barbies</code> if you'd like to learn more.</p>
<div class="sourceCode" id="cb24"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="ot">getOptions ::</span> <span class="dt">IO</span> (<span class="dt">Validation</span> [<span class="dt">String</span>] <span class="dt">Options</span>)</span>
<span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a>getOptions <span class="ot">=</span></span>
<span id="cb24-3"><a href="#cb24-3" aria-hidden="true" tabindex="-1"></a>  validateOptions optErrors <span class="op">&lt;$&gt;</span> fold [envOpts, jsonOptsCustom <span class="op">&lt;$&gt;</span> readConfigFile]</span></code></pre></div>
<p>Now if we end up with values missing we get a list of errors!</p>
<div class="sourceCode" id="cb25"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> getOptions</span>
<span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Failure</span> [<span class="st">&quot;num threads required but not provided&quot;</span>]</span></code></pre></div>
<p>You can trust me that if we had more than one thing missing it would
collect them all. That's a lot of content all at once, so I'll leave
some other experiments for next time. Once you start to experiment a
world of opportunities opens up; you can describe validation, forms,
documentations, schemas, and a bunch of other stuff I haven't even
though of yet!! A challenge for the reader: try writing a proper
validator using HKDTs which validates that each field fulfills specific
properties. For example, check that the number of threads is &gt; 0;
check that the host is non-empty, etc. You may find the following
newtype helpful ;)
<code>newtype Checker a = Checker (a -&gt; Maybe String)</code></p>
<h2 id="bonus-parsing-cli-options">Bonus: Parsing CLI Options</h2>
<p>Just for fun here's a bonus config source for getting options from
the Command Line using Optparse Applicative</p>
<div class="sourceCode" id="cb26"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Options.Applicative</span> <span class="kw">hiding</span> (<span class="dt">Failure</span>, <span class="dt">Success</span>)</span>
<span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a><span class="co">---</span></span>
<span id="cb26-3"><a href="#cb26-3" aria-hidden="true" tabindex="-1"></a><span class="ot">cliOptsParser ::</span> <span class="dt">Options_</span> <span class="dt">Parser</span></span>
<span id="cb26-4"><a href="#cb26-4" aria-hidden="true" tabindex="-1"></a>cliOptsParser <span class="ot">=</span></span>
<span id="cb26-5"><a href="#cb26-5" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Options_</span></span>
<span id="cb26-6"><a href="#cb26-6" aria-hidden="true" tabindex="-1"></a>    { serverHost <span class="ot">=</span></span>
<span id="cb26-7"><a href="#cb26-7" aria-hidden="true" tabindex="-1"></a>          strOption (long <span class="st">&quot;serverHost&quot;</span> <span class="op">&lt;&gt;</span> metavar <span class="st">&quot;HOST&quot;</span> <span class="op">&lt;&gt;</span> help <span class="st">&quot;host for API interactions&quot;</span>)</span>
<span id="cb26-8"><a href="#cb26-8" aria-hidden="true" tabindex="-1"></a>    , numThreads <span class="ot">=</span></span>
<span id="cb26-9"><a href="#cb26-9" aria-hidden="true" tabindex="-1"></a>          option auto</span>
<span id="cb26-10"><a href="#cb26-10" aria-hidden="true" tabindex="-1"></a>                 (long <span class="st">&quot;threads&quot;</span> <span class="op">&lt;&gt;</span> short <span class="ch">&#39;t&#39;</span> <span class="op">&lt;&gt;</span> help <span class="st">&quot;number of threads&quot;</span> <span class="op">&lt;&gt;</span> metavar <span class="st">&quot;INT&quot;</span>)</span>
<span id="cb26-11"><a href="#cb26-11" aria-hidden="true" tabindex="-1"></a>    , verbosity  <span class="ot">=</span> option auto</span>
<span id="cb26-12"><a href="#cb26-12" aria-hidden="true" tabindex="-1"></a>                          (long <span class="st">&quot;verbosity&quot;</span></span>
<span id="cb26-13"><a href="#cb26-13" aria-hidden="true" tabindex="-1"></a>                           <span class="op">&lt;&gt;</span> short <span class="ch">&#39;v&#39;</span></span>
<span id="cb26-14"><a href="#cb26-14" aria-hidden="true" tabindex="-1"></a>                           <span class="op">&lt;&gt;</span> help <span class="st">&quot;Level of verbosity&quot;</span></span>
<span id="cb26-15"><a href="#cb26-15" aria-hidden="true" tabindex="-1"></a>                           <span class="op">&lt;&gt;</span> metavar <span class="st">&quot;VERBOSITY&quot;</span>)</span>
<span id="cb26-16"><a href="#cb26-16" aria-hidden="true" tabindex="-1"></a>    }</span>
<span id="cb26-17"><a href="#cb26-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-18"><a href="#cb26-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-19"><a href="#cb26-19" aria-hidden="true" tabindex="-1"></a><span class="ot">mkOptional ::</span> <span class="dt">FunctorB</span> b <span class="ot">=&gt;</span> b <span class="dt">Parser</span> <span class="ot">-&gt;</span> b (<span class="dt">Parser</span> <span class="ot">`Compose`</span> <span class="dt">Maybe</span>)</span>
<span id="cb26-20"><a href="#cb26-20" aria-hidden="true" tabindex="-1"></a>mkOptional <span class="ot">=</span> bmap (<span class="dt">Compose</span> <span class="op">.</span> optional)</span>
<span id="cb26-21"><a href="#cb26-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-22"><a href="#cb26-22" aria-hidden="true" tabindex="-1"></a><span class="ot">toParserInfo ::</span> (<span class="dt">TraversableB</span> b) <span class="ot">=&gt;</span> b (<span class="dt">Parser</span> <span class="ot">`Compose`</span> <span class="dt">Maybe</span>) <span class="ot">-&gt;</span> <span class="dt">ParserInfo</span> (b <span class="dt">Maybe</span>)</span>
<span id="cb26-23"><a href="#cb26-23" aria-hidden="true" tabindex="-1"></a>toParserInfo b <span class="ot">=</span> info (bsequence b) briefDesc</span>
<span id="cb26-24"><a href="#cb26-24" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-25"><a href="#cb26-25" aria-hidden="true" tabindex="-1"></a><span class="ot">cliOpts ::</span> <span class="dt">IO</span> (<span class="dt">Options_</span> <span class="dt">Maybe</span>)</span>
<span id="cb26-26"><a href="#cb26-26" aria-hidden="true" tabindex="-1"></a>cliOpts <span class="ot">=</span> execParser <span class="op">$</span> toParserInfo (mkOptional cliOptsParser)</span>
<span id="cb26-27"><a href="#cb26-27" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-28"><a href="#cb26-28" aria-hidden="true" tabindex="-1"></a><span class="ot">getOptions ::</span> <span class="dt">IO</span> (<span class="dt">Validation</span> [<span class="dt">String</span>] <span class="dt">Options</span>)</span>
<span id="cb26-29"><a href="#cb26-29" aria-hidden="true" tabindex="-1"></a>getOptions <span class="ot">=</span></span>
<span id="cb26-30"><a href="#cb26-30" aria-hidden="true" tabindex="-1"></a>  validateOptions optErrors <span class="op">&lt;$&gt;</span> fold [cliOpts, envOpts, jsonOptsCustom <span class="op">&lt;$&gt;</span> readConfigFile]</span></code></pre></div>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Mocking Effects using Constraints and Phantom Data Kinds</title>
      <link href="https://chrispenner.ca/posts/mock-effects-with-data-kinds"/>
      <id>https://chrispenner.ca/posts/mock-effects-with-data-kinds</id>
      <updated>2018-09-29T00:00:00Z</updated>
      <summary>We learn a method to mock multiple effects when writing tests without an
exponential explosion of instances.</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/mock-effects-with-data-kinds/phantom.jpg" alt="Mocking Effects using Constraints and Phantom Data Kinds">
              <p>This ended up being a pretty long post; if you're pretty comfortable
with monad constraints and testing in Haskell you may want to jump down
to the Phantom Data Kinds section and get to the interesting stuff!</p>
<h2 id="refresher-on-granular-classes">Refresher on granular
classes</h2>
<p>I've been seeing a lot of talk on the <a
href="https://reddit.com/r/haskell">Haskell subreddit</a> about how to
properly test Haskell applications; particular how to test actions which
require effects. I've seen a lot of confusion/concern about writing your
own monad transformers in tests. This post is my attempt to clear up
some confusion and misconceptions and show off my particular ideas for
testing using <code>mtl-style</code> constraints. The ideas contained
here can also help you with writing multiple 'interpreters' for your
monad stacks without needing a <code>newtype</code> for each permutation
of possible implementations.</p>
<p>First things first, what do I mean by <code>mtl-style</code>
constraints? I'd recommend you consult <a
href="https://chrispenner.ca/posts/monadio-considered-harmful">MonadIO
Considered Harmful</a>, it's a post I wrote on the topic almost exactly
a year ago. Here's the spark-notes version:</p>
<ul>
<li>Monads with semantics attached should define a <code>Monad*</code>
type-class for interacting with those constraints (E.g.
<code>MonadState</code>, <code>MonadReader</code>)</li>
<li>Actions which require effects should use type-class constraints
instead of using concrete monads (E.g.
<code>myAction :: MonadReader AppEnv m =&gt; m ()</code> rather than
<code>myAction :: AppM ()</code>)</li>
<li>Your app should break up 'big' monad classes into smaller ones with
clearer semantics and intent. (E.g. Break down <code>MonadIO</code> into
<code>MonadHttp</code> and <code>MonadFilesystem</code>, etc.)</li>
</ul>
<p>Okay, so assuming we're all on board with writing our code
polymorphically using Monad Constraints, what's the problem? Well, the
reason we're doing it polymorphically is so we can specialize the monad
to <strong>different implementations</strong> if we want! This is one
way to implement the <a
href="https://en.wikipedia.org/wiki/Dependency_injection"><strong>dependency
injection</strong></a> pattern in Haskell; and lets us substitute out
the implementation of our monadic effects with 'dummy' or 'mock'
versions in tests.</p>
<p>The trick is that we run into a lot of annoying repetition and
boiler-plate which gets out of control as we scale up the number of
effects we use. To show the problem let's assume we have some action
that does something, and needs the following three constraints which you
can assume are type-classes we've defined using the 'granular mtl'
style:</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">myAction ::</span> (<span class="dt">MonadFileSystem</span> m, <span class="dt">MonadDB</span> m, <span class="dt">MonadLogger</span> m) <span class="ot">=&gt;</span> m ()</span></code></pre></div>
<p>Now, assume we've already implemented <code>MonadFileSystem</code>,
<code>MonadDB</code>, and <code>MonadLogger</code> for our application's
main monad, but when we test it we probably don't want to hit our real
DB or file-system so we should probably mock those out. We'll need a new
monad type to implement instances against:</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">data</span> <span class="dt">TestState</span> <span class="ot">=</span> <span class="dt">TestState</span> </span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>    {<span class="ot"> fakeFilesystem ::</span> <span class="dt">Map</span> <span class="dt">String</span> <span class="dt">String</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>    ,<span class="ot"> fakeDB ::</span> <span class="dt">Map</span> <span class="dt">String</span> <span class="dt">String</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>    ,<span class="ot"> logs ::</span> [<span class="dt">String</span>]</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>    }</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">TestM</span> a <span class="ot">=</span> <span class="dt">TestM</span> (<span class="dt">State</span> <span class="dt">TestState</span> a)</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 class="kw">instance</span> <span class="dt">MonadFileSystem</span> <span class="dt">TestM</span> <span class="kw">where</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a><span class="co">-- ...</span></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">MonadDB</span> <span class="dt">TestM</span> <span class="kw">where</span></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a><span class="co">-- ...</span></span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">MonadLogger</span> <span class="dt">TestM</span> <span class="kw">where</span></span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a><span class="co">-- ...</span></span></code></pre></div>
<p>I'm not getting into many details yet and have elided the
implementations here for brevity, but hopefully that shows how you could
implement those interfaces in terms of some pure monad stack like
<code>State</code> in order to more easily write tests. BUT! What if for
a new test we want the file-system to behave differently and fail on
every request to read a file? We could add a boolean into the state that
dictates this behaviour, but that will definitely complicate the
implementation of our instance, we could add a newtype wrapper which has
a different <code>MonadFileSystem</code> instance, but we'd need to
regain all our instances for the other type-classes again! We can use
<code>GeneralizedNewtypeDeriving</code> to help, but say we now want
multiple behaviours for our MonadDB instance! Things get out of control
really quickly, this post investigates a (slightly) cleaner way to go
about this.</p>
<p>Our goals are as follows:</p>
<ul>
<li>I want to write exactly 1 instance definition per type-class
behaviour I want</li>
<li>Adding a new effect or behaviour shouldn't require any
newtypes.</li>
<li>I should be able to easily choose a set of behaviours for each of my
effects each time I run a test.</li>
</ul>
<p>That's a tall order! Let's dig in and see if we can manage it!</p>
<h2 id="case-study">Case Study</h2>
<p>This topic is tough to explain without concrete examples, so bear
with me while we set some things up. Let's start by looking at how
someone may have written a really simple app and some functions for
working with their database.</p>
<p>Here's our base monad type:</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">{-# LANGUAGE GeneralizedNewtypeDeriving #-}</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">import</span> <span class="dt">Control.Monad.Except</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Monad.IO.Class</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 class="kw">data</span> <span class="dt">DBError</span> <span class="ot">=</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>  <span class="dt">DBError</span> <span class="dt">String</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Eq</span>, <span class="dt">Show</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 class="co">-- Our application can access the database via IO and possibly throw DB errors.</span></span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">AppM</span> a <span class="ot">=</span> <span class="dt">AppM</span></span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a>  {<span class="ot"> runAppM ::</span> <span class="dt">ExceptT</span> <span class="dt">DBError</span> <span class="dt">IO</span> a</span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a>  } <span class="kw">deriving</span> (<span class="dt">Functor</span>, <span class="dt">Applicative</span>, <span class="dt">Monad</span>, <span class="dt">MonadIO</span>, <span class="dt">MonadError</span> <span class="dt">DBError</span>)</span></code></pre></div>
<p>We've abstracted over our database actions already with the following
type-class:</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 MultiParamTypeClasses #-}</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE FunctionalDependencies #-}</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">Key</span> <span class="ot">=</span> <span class="dt">String</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="co">-- Our database associates string keys to some value type.</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a><span class="co">-- The specific value we can fetch is dependent on the monad</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a><span class="co">-- (but we&#39;ll just use strings for simplicity in our case)</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> (<span class="dt">MonadError</span> <span class="dt">DBError</span> m) <span class="ot">=&gt;</span> <span class="dt">MonadDB</span> m v <span class="op">|</span> m <span class="ot">-&gt;</span> v <span class="kw">where</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a><span class="ot">  getEntity ::</span> <span class="dt">Key</span> <span class="ot">-&gt;</span> m v</span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a><span class="ot">  storeEntity ::</span> <span class="dt">Key</span> <span class="ot">-&gt;</span> v <span class="ot">-&gt;</span> m ()</span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">MonadDB</span> <span class="dt">AppM</span> <span class="dt">String</span> <span class="kw">where</span></span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a><span class="co">-- ...</span></span>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a><span class="co">-- Assume we&#39;ve written some instance for interacting with our DB via IO, </span></span>
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a><span class="co">-- which returns any errors via ExceptT.</span></span></code></pre></div>
<p>Cool! This looks pretty normal, we have a primary app monad and we
can get and store strings in our database via IO using it!</p>
<p>Now that we've got our basic DB interface let's say we want to write
a more complex action using it:</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="co">-- given a database key and a monad which can interact with a database containing strings</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- we can look up the value, uppercase it, then write it back.</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="ot">upperCase ::</span> (<span class="dt">MonadDB</span> m <span class="dt">String</span>) <span class="ot">=&gt;</span> <span class="dt">Key</span> <span class="ot">-&gt;</span> m ()</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>upperCase key <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>  thing <span class="ot">&lt;-</span> getEntity key</span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a>  storeEntity key (<span class="fu">fmap</span> <span class="fu">toUpper</span> thing)</span></code></pre></div>
<p>It's a pretty simple action, but we should probably add some unit
tests! Let's set it up using our AppM instance!</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="co">-- Spec.hs</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="ot">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>  hspec <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>    describe <span class="st">&quot;upperCase&quot;</span> <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>      it <span class="st">&quot;uppercases the value stored at the given key in the DB&quot;</span> <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a>        result <span class="ot">&lt;-</span></span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a>          <span class="co">-- we unpack AppM, run the exceptT, then lift it into the IO part of our spec</span></span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a>          liftIO <span class="op">.</span> runExceptT <span class="op">.</span> runAppM <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a>            storeEntity <span class="st">&quot;my-key&quot;</span> <span class="st">&quot;value&quot;</span></span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a>            upperCase <span class="st">&quot;my-key&quot;</span></span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a>            getEntity <span class="st">&quot;my-key&quot;</span></span>
<span id="cb6-13"><a href="#cb6-13" aria-hidden="true" tabindex="-1"></a>        result <span class="ot">`shouldBe`</span> <span class="dt">Right</span> <span class="st">&quot;VALUE&quot;</span></span></code></pre></div>
<p>Well, this should work, but we're using <code>IO</code> directly in
tests; not only is this going to be slow; but it means we need to have a
database running somewhere, and that the tests might pass or fail
depending on the initial state of that database! Clearly that's not
ideal! We really only want to test the semantics of
<code>upperCase</code> and how it <strong>glues together</strong> the
interface of our database; we don't really care which database it's
operating over.</p>
<p>Our <code>uppercase</code> action is polymorphic over the monad it
uses, so that means we can write a new instance for <code>MonadDB</code>
and get it to use that in the tests instead!</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="kw">import</span> <span class="dt">Data.Map</span> <span class="kw">as</span> <span class="dt">M</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="co">-- We&#39;ll use a Map as our database implementation, storing it in a state monad</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="co">-- We also add ExceptT so we can see if our DB failed to look something up!</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">TestM</span> a <span class="ot">=</span> <span class="dt">TestM</span></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>  {<span class="ot"> runTestM ::</span> <span class="dt">ExceptT</span> <span class="dt">DBError</span> (<span class="dt">State</span> (<span class="dt">M.Map</span> <span class="dt">String</span> <span class="dt">String</span>)) a</span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a>  } <span class="kw">deriving</span> ( <span class="dt">Functor</span></span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a>             , <span class="dt">Applicative</span></span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a>             , <span class="dt">Monad</span></span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a>             , <span class="dt">MonadError</span> <span class="dt">DBError</span></span>
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a>             , <span class="dt">MonadState</span> (<span class="dt">M.Map</span> <span class="dt">String</span> <span class="dt">String</span>)</span>
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true" tabindex="-1"></a>             )</span>
<span id="cb7-13"><a href="#cb7-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-14"><a href="#cb7-14" aria-hidden="true" tabindex="-1"></a><span class="co">-- We&#39;ll implement an instance of MonadDB for our TestM monad.</span></span>
<span id="cb7-15"><a href="#cb7-15" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">MonadDB</span> <span class="dt">TestM</span> <span class="dt">String</span> <span class="kw">where</span></span>
<span id="cb7-16"><a href="#cb7-16" aria-hidden="true" tabindex="-1"></a>  getEntity key <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb7-17"><a href="#cb7-17" aria-hidden="true" tabindex="-1"></a>    db <span class="ot">&lt;-</span> get</span>
<span id="cb7-18"><a href="#cb7-18" aria-hidden="true" tabindex="-1"></a>    <span class="kw">case</span> M.lookup key db <span class="kw">of</span></span>
<span id="cb7-19"><a href="#cb7-19" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Nothing</span> <span class="ot">-&gt;</span> throwError <span class="op">.</span> <span class="dt">DBError</span> <span class="op">$</span> <span class="st">&quot;didn&#39;t find &quot;</span> <span class="op">++</span> key <span class="op">++</span> <span class="st">&quot; in db&quot;</span></span>
<span id="cb7-20"><a href="#cb7-20" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Just</span> v <span class="ot">-&gt;</span> <span class="fu">return</span> v</span>
<span id="cb7-21"><a href="#cb7-21" aria-hidden="true" tabindex="-1"></a>  storeEntity key value <span class="ot">=</span> modify (M.insert key value)</span>
<span id="cb7-22"><a href="#cb7-22" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-23"><a href="#cb7-23" aria-hidden="true" tabindex="-1"></a><span class="ot">runTestM&#39; ::</span> <span class="dt">M.Map</span> <span class="dt">String</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">TestM</span> a <span class="ot">-&gt;</span> <span class="dt">Either</span> <span class="dt">DBError</span> a</span>
<span id="cb7-24"><a href="#cb7-24" aria-hidden="true" tabindex="-1"></a>runTestM&#39; db (<span class="dt">TestM</span> m) <span class="ot">=</span> <span class="fu">flip</span> evalState db <span class="op">.</span> runExceptT <span class="op">$</span> m</span></code></pre></div>
<p>Now we have a completely <strong>pure</strong> way of modeling our
DB, which we can seed with initial data, and we can even inspect the
final state if we like! This makes writing tests <em>so</em> much
easier. We can re-write the <code>upperCase</code> test using
<code>State</code> instead of <code>IO</code>! This means we have fewer
dependencies, fewer unknowns, and can more directly test the behaviour
of the action which we actually care about.</p>
<p>Here's the re-written spec, the test itself is the same, but we no
longer run it in IO:</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>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>  hspec <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>    describe <span class="st">&quot;upperCase&quot;</span> <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a>      it <span class="st">&quot;uppercases the value stored at the given key in the DB&quot;</span> <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a>        <span class="kw">let</span> result <span class="ot">=</span></span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a>              runTestM&#39; <span class="fu">mempty</span> <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a>                storeEntity <span class="st">&quot;my-key&quot;</span> <span class="st">&quot;value&quot;</span></span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a>                upperCase <span class="st">&quot;my-key&quot;</span></span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a>                getEntity <span class="st">&quot;my-key&quot;</span></span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a>        result <span class="ot">`shouldBe`</span> <span class="dt">Right</span> <span class="st">&quot;VALUE&quot;</span></span></code></pre></div>
<p>Nifty!</p>
<h2 id="parameterizing-test-implementations">Parameterizing test
implementations</h2>
<p>The thing about <strong>test</strong>s is that you often want to
<strong>test</strong> unique and interesting behaviour! This means we'll
probably want multiple implementations of our mocked services which each
behave differently. Let's say that we want to test what happens if our
DB fails on every single call? We <strong>could</strong> implement a
whole new <code>TestM</code> monad with a new instance for
<code>MonadDB</code> which errors on every call, and this would work
fine, but in the real world we'll probably be mocking out a half-dozen
services or more! That means we'll need a half dozen instances for each
and every <code>TestM</code> we build! I don't feel like working
overtime, so let's see if we can knock down the boilerplate by an order
of magnitude. It's getting tough to talk about this abstractly so let's
expand our example to include at least one other mocked service. We'll
add some capability to our AppM to handle input and output from the
console!</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">class</span> <span class="dt">MonadCli</span> m <span class="kw">where</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- &#39;print&#39; something to output</span></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a><span class="ot">  say ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> m ()</span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- get a string from the user input</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a><span class="ot">  listen ::</span> m <span class="dt">String</span></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">MonadCli</span> <span class="dt">AppM</span> <span class="kw">where</span></span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a>  say <span class="ot">=</span> liftIO <span class="op">.</span> <span class="fu">print</span></span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a>  listen <span class="ot">=</span> liftIO <span class="fu">getLine</span></span></code></pre></div>
<p>Now we can get something from the user and store it in the DB!</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">storeName ::</span> (<span class="dt">MonadDB</span> m <span class="dt">String</span>, <span class="dt">MonadCli</span> m) <span class="ot">=&gt;</span> m ()</span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>storeName <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>  say <span class="st">&quot;What&#39;s your name?&quot;</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>  name <span class="ot">&lt;-</span> listen</span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>  storeEntity <span class="st">&quot;name&quot;</span> name</span></code></pre></div>
<p>Let's jump into testing it! To do so we'll need to make
<code>TestM</code> an instance of <code>MonadCli</code> too! Now that we
have multiple concerns going on I'm going to use a shared state and add
some lenses to make working with everything a bit easier. It's a bit of
set-up up-front, but from now on adding additional functionality should
be pretty straight-forward!</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">{-# LANGUAGE TemplateHaskell #-}</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Lens</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">-- We&#39;ll store all our mock data in this data type</span></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">TestState</span> <span class="ot">=</span> <span class="dt">TestState</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>  {<span class="ot"> _cliInput ::</span> [<span class="dt">String</span>]</span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a>  ,<span class="ot"> _cliOutput ::</span> [<span class="dt">String</span>]</span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a>  ,<span class="ot"> _db ::</span> <span class="dt">Map</span> <span class="dt">String</span> <span class="dt">String</span></span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a>  } <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</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>makeLenses &#39;<span class="dt">&#39;TestState</span></span>
<span id="cb11-12"><a href="#cb11-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-13"><a href="#cb11-13" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">TestM</span> a <span class="ot">=</span> <span class="dt">TestM</span></span>
<span id="cb11-14"><a href="#cb11-14" aria-hidden="true" tabindex="-1"></a>  {<span class="ot"> runTestM ::</span> <span class="dt">ExceptT</span> <span class="dt">DBError</span> (<span class="dt">State</span> <span class="dt">TestState</span>) a</span>
<span id="cb11-15"><a href="#cb11-15" aria-hidden="true" tabindex="-1"></a>  } <span class="kw">deriving</span> ( <span class="dt">Functor</span></span>
<span id="cb11-16"><a href="#cb11-16" aria-hidden="true" tabindex="-1"></a>             , <span class="dt">Applicative</span></span>
<span id="cb11-17"><a href="#cb11-17" aria-hidden="true" tabindex="-1"></a>             , <span class="dt">Monad</span></span>
<span id="cb11-18"><a href="#cb11-18" aria-hidden="true" tabindex="-1"></a>             , <span class="dt">MonadError</span> <span class="dt">DBError</span></span>
<span id="cb11-19"><a href="#cb11-19" aria-hidden="true" tabindex="-1"></a>             , <span class="dt">MonadState</span> <span class="dt">TestState</span></span>
<span id="cb11-20"><a href="#cb11-20" aria-hidden="true" tabindex="-1"></a>             )</span>
<span id="cb11-21"><a href="#cb11-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-22"><a href="#cb11-22" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-23"><a href="#cb11-23" aria-hidden="true" tabindex="-1"></a><span class="ot">runTestM&#39; ::</span> <span class="dt">TestState</span> <span class="ot">-&gt;</span> <span class="dt">TestM</span> a <span class="ot">-&gt;</span> <span class="dt">Either</span> <span class="dt">DBError</span> a</span>
<span id="cb11-24"><a href="#cb11-24" aria-hidden="true" tabindex="-1"></a>runTestM&#39; startState (<span class="dt">TestM</span> m) <span class="ot">=</span> <span class="fu">flip</span> evalState startState <span class="op">.</span> runExceptT <span class="op">$</span> m</span>
<span id="cb11-25"><a href="#cb11-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-26"><a href="#cb11-26" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">MonadDB</span> <span class="dt">TestM</span> <span class="dt">String</span> <span class="kw">where</span></span>
<span id="cb11-27"><a href="#cb11-27" aria-hidden="true" tabindex="-1"></a><span class="co">-- Implementation here&#39;s not important, assume we do pretty much the same thing as earlier</span></span>
<span id="cb11-28"><a href="#cb11-28" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-29"><a href="#cb11-29" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">MonadCli</span> <span class="dt">TestM</span> <span class="kw">where</span></span>
<span id="cb11-30"><a href="#cb11-30" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- We&#39;ll just record things we say in our list of output</span></span>
<span id="cb11-31"><a href="#cb11-31" aria-hidden="true" tabindex="-1"></a>  say msg <span class="ot">=</span> cliOutput <span class="op">%=</span> (<span class="op">++</span> [msg])</span>
<span id="cb11-32"><a href="#cb11-32" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- We&#39;ll pull input from our state as long as we have some.</span></span>
<span id="cb11-33"><a href="#cb11-33" aria-hidden="true" tabindex="-1"></a>  listen <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb11-34"><a href="#cb11-34" aria-hidden="true" tabindex="-1"></a>    inputs <span class="ot">&lt;-</span> use cliInput</span>
<span id="cb11-35"><a href="#cb11-35" aria-hidden="true" tabindex="-1"></a>    <span class="kw">case</span> inputs <span class="kw">of</span></span>
<span id="cb11-36"><a href="#cb11-36" aria-hidden="true" tabindex="-1"></a>      [] <span class="ot">-&gt;</span> <span class="fu">return</span> <span class="st">&quot;NO MORE INPUT&quot;</span></span>
<span id="cb11-37"><a href="#cb11-37" aria-hidden="true" tabindex="-1"></a>      (msg<span class="op">:</span>rest) <span class="ot">-&gt;</span> cliInput <span class="op">.=</span> rest <span class="op">&gt;&gt;</span> <span class="fu">return</span> msg</span>
<span id="cb11-38"><a href="#cb11-38" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-39"><a href="#cb11-39" aria-hidden="true" tabindex="-1"></a><span class="ot">emptyState ::</span> <span class="dt">TestState</span></span>
<span id="cb11-40"><a href="#cb11-40" aria-hidden="true" tabindex="-1"></a>emptyState <span class="ot">=</span> <span class="dt">TestState</span> {_cliInput <span class="ot">=</span> <span class="fu">mempty</span>, _cliOutput <span class="ot">=</span> <span class="fu">mempty</span>, _db <span class="ot">=</span> <span class="fu">mempty</span>}</span></code></pre></div>
<p>Now we can test our <code>storeName</code> function!</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">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>  hspec <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>    describe <span class="st">&quot;storeName&quot;</span> <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a>      it <span class="st">&quot;stores a name from user input&quot;</span> <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a>        <span class="kw">let</span> result <span class="ot">=</span></span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a>              <span class="co">-- We&#39;ll seed a name as our cli input</span></span>
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a>              runTestM&#39; (emptyState <span class="op">&amp;</span> cliInput <span class="op">.~</span> [<span class="st">&quot;Steven&quot;</span>]) <span class="op">$</span></span>
<span id="cb12-9"><a href="#cb12-9" aria-hidden="true" tabindex="-1"></a>              <span class="co">-- Running storeName should store the cli input </span></span>
<span id="cb12-10"><a href="#cb12-10" aria-hidden="true" tabindex="-1"></a>              <span class="co">-- in the DB under the &quot;name&quot; key!</span></span>
<span id="cb12-11"><a href="#cb12-11" aria-hidden="true" tabindex="-1"></a>              storeName <span class="op">&gt;&gt;</span> getEntity <span class="st">&quot;name&quot;</span></span>
<span id="cb12-12"><a href="#cb12-12" aria-hidden="true" tabindex="-1"></a>        result <span class="ot">`shouldBe`</span> <span class="dt">Right</span> <span class="st">&quot;Steven&quot;</span></span></code></pre></div>
<p>Hopefully that comes out green!</p>
<p>Great! So, like I said before we'd like to customize our
implementations of some of our mocked out services, let's say we want
the DB to fail on every call! One option would be to wrap
<code>TestM</code> in a newtype and use <code>deriving MonadCli</code>
with <code>GeneralizedNewtypeDeriving</code> to get back our
implementation of <code>MonadCli</code> then write a NEW instance for
<code>MonadDB</code> which fails on every call. If we have to do this
for every customized behaviour for each of our services though this
results in an <code>(n*k)</code> number of newtypes! We need a different
newtype for EACH pairing of every possible set of behaviours we can
imagine! Let's solve this problem the way we solve all problems in
Haskell: Add more type parameters!</p>
<h2 id="phantom-data-kinds">Phantom Data Kinds</h2>
<p>Let's parameterize <code>TestM</code> with slots which represent
possible implementations of each service. To help users know how it
works and also prevent incorrect usage we'll qualify the parameters
using <code>DataKinds</code>!</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">{-# LANGUAGE DataKinds #-}</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE KindSignatures #-}</span></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">DBImpl</span></span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a>  <span class="ot">=</span> <span class="dt">DBUseMap</span></span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">DBOnFire</span></span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">CliImpl</span></span>
<span id="cb13-9"><a href="#cb13-9" aria-hidden="true" tabindex="-1"></a>  <span class="ot">=</span> <span class="dt">CliUseList</span></span>
<span id="cb13-10"><a href="#cb13-10" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">CliStatic</span></span>
<span id="cb13-11"><a href="#cb13-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-12"><a href="#cb13-12" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">TestM</span> (<span class="ot">db ::</span> <span class="dt">DBImpl</span>) (<span class="ot">cli ::</span> <span class="dt">CliImpl</span>) a <span class="ot">=</span> <span class="dt">TestM</span></span>
<span id="cb13-13"><a href="#cb13-13" aria-hidden="true" tabindex="-1"></a>  {<span class="ot"> runTestM ::</span> <span class="dt">ExceptT</span> <span class="dt">DBError</span> (<span class="dt">State</span> <span class="dt">TestState</span>) a</span>
<span id="cb13-14"><a href="#cb13-14" aria-hidden="true" tabindex="-1"></a>  } <span class="kw">deriving</span> ( <span class="dt">Functor</span></span>
<span id="cb13-15"><a href="#cb13-15" aria-hidden="true" tabindex="-1"></a>             , <span class="dt">Applicative</span></span>
<span id="cb13-16"><a href="#cb13-16" aria-hidden="true" tabindex="-1"></a>             , <span class="dt">Monad</span></span>
<span id="cb13-17"><a href="#cb13-17" aria-hidden="true" tabindex="-1"></a>             , <span class="dt">MonadError</span> <span class="dt">DBError</span></span>
<span id="cb13-18"><a href="#cb13-18" aria-hidden="true" tabindex="-1"></a>             , <span class="dt">MonadState</span> <span class="dt">TestState</span></span>
<span id="cb13-19"><a href="#cb13-19" aria-hidden="true" tabindex="-1"></a>             )</span>
<span id="cb13-20"><a href="#cb13-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-21"><a href="#cb13-21" aria-hidden="true" tabindex="-1"></a><span class="ot">runTestM&#39; ::</span> <span class="dt">TestState</span> <span class="ot">-&gt;</span> <span class="dt">TestM</span> db cli a <span class="ot">-&gt;</span> <span class="dt">Either</span> <span class="dt">DBError</span> a</span>
<span id="cb13-22"><a href="#cb13-22" aria-hidden="true" tabindex="-1"></a>runTestM&#39; startState (<span class="dt">TestM</span> m) <span class="ot">=</span> <span class="fu">flip</span> evalState startState <span class="op">.</span> runExceptT <span class="op">$</span> m</span></code></pre></div>
<p>Notice that we don't actually need to use these params inside the
definition of the <code>TestM</code> newtype; they're just there as
annotations for the compiler, I call these 👻 Phantom Data Kinds 👻. Now
let's update the instance we've defined already to handle the type
params, as well as add some new instances!</p>
<p>The instance signatures are the most important part here; but read
the rest if you like 🤷‍♂️</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="kw">instance</span> <span class="dt">MonadDB</span> (<span class="dt">TestM</span> <span class="dt">DBUseMap</span> cli) <span class="dt">String</span> <span class="kw">where</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a>  getEntity key <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a>    db&#39; <span class="ot">&lt;-</span> use db</span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">case</span> M.lookup key db&#39; <span class="kw">of</span></span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Nothing</span> <span class="ot">-&gt;</span> throwError <span class="op">.</span> <span class="dt">DBError</span> <span class="op">$</span> <span class="st">&quot;didn&#39;t find &quot;</span> <span class="op">++</span> key <span class="op">++</span> <span class="st">&quot; in db&quot;</span></span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Just</span> v <span class="ot">-&gt;</span> <span class="fu">return</span> v</span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a>  storeEntity key value <span class="ot">=</span> db <span class="op">%=</span> M.insert key value</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="co">-- This DB mock tests how actions react if every call to the DB fails</span></span>
<span id="cb14-10"><a href="#cb14-10" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">MonadDB</span> (<span class="dt">TestM</span> <span class="dt">DBOnFire</span> cli) <span class="dt">String</span> <span class="kw">where</span></span>
<span id="cb14-11"><a href="#cb14-11" aria-hidden="true" tabindex="-1"></a>  getEntity _ <span class="ot">=</span> throwError <span class="op">.</span> <span class="dt">DBError</span> <span class="op">$</span> <span class="st">&quot;🔥 DB is on FIRE! 🔥&quot;</span></span>
<span id="cb14-12"><a href="#cb14-12" aria-hidden="true" tabindex="-1"></a>  storeEntity _ _ <span class="ot">=</span> throwError <span class="op">.</span> <span class="dt">DBError</span> <span class="op">$</span> <span class="st">&quot;🔥 DB is on FIRE! 🔥&quot;</span></span>
<span id="cb14-13"><a href="#cb14-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-14"><a href="#cb14-14" aria-hidden="true" tabindex="-1"></a><span class="co">-- A simple cli mock which pulls input from a list and </span></span>
<span id="cb14-15"><a href="#cb14-15" aria-hidden="true" tabindex="-1"></a><span class="co">-- stores printed strings in state for later inspection</span></span>
<span id="cb14-16"><a href="#cb14-16" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">MonadCli</span> (<span class="dt">TestM</span> db <span class="dt">CliUseList</span>) <span class="kw">where</span></span>
<span id="cb14-17"><a href="#cb14-17" aria-hidden="true" tabindex="-1"></a>  say msg <span class="ot">=</span> cliOutput <span class="op">%=</span> (msg <span class="op">:</span>)</span>
<span id="cb14-18"><a href="#cb14-18" aria-hidden="true" tabindex="-1"></a>  listen <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb14-19"><a href="#cb14-19" aria-hidden="true" tabindex="-1"></a>    inputs <span class="ot">&lt;-</span> use cliInput</span>
<span id="cb14-20"><a href="#cb14-20" aria-hidden="true" tabindex="-1"></a>    <span class="kw">case</span> inputs <span class="kw">of</span></span>
<span id="cb14-21"><a href="#cb14-21" aria-hidden="true" tabindex="-1"></a>      [] <span class="ot">-&gt;</span> <span class="fu">return</span> <span class="st">&quot;NO MORE INPUT&quot;</span></span>
<span id="cb14-22"><a href="#cb14-22" aria-hidden="true" tabindex="-1"></a>      (msg<span class="op">:</span>rest) <span class="ot">-&gt;</span> cliInput <span class="op">.=</span> rest <span class="op">&gt;&gt;</span> <span class="fu">return</span> msg</span>
<span id="cb14-23"><a href="#cb14-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-24"><a href="#cb14-24" aria-hidden="true" tabindex="-1"></a><span class="co">-- A simple cli mock which always returns the same thing</span></span>
<span id="cb14-25"><a href="#cb14-25" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">MonadCli</span> (<span class="dt">TestM</span> db <span class="dt">CliStatic</span>) <span class="kw">where</span></span>
<span id="cb14-26"><a href="#cb14-26" aria-hidden="true" tabindex="-1"></a>  say _ <span class="ot">=</span> <span class="fu">return</span> ()</span>
<span id="cb14-27"><a href="#cb14-27" aria-hidden="true" tabindex="-1"></a>  listen <span class="ot">=</span> <span class="fu">return</span> <span class="st">&quot;INPUT&quot;</span></span></code></pre></div>
<p>The cool thing about this is that each instance can choose an
instance based on one parameter while leaving the type variable in the
other slots unspecified! So for our MonadDB implementation we can have a
different implementation for each value of the <code>db :: DBImpl</code>
type param while not caring at all what's in the
<code>cli :: CliImpl</code> parameter! This means that we only need to
implement each behaviour once, and we can mix and match implementations
for different services at will! We <em>do</em> need to make sure that
there's some way to actually implement that behaviour against our
<code>TestM</code>; but for the vast majority of cases you can just
carve out a spot in the <code>State</code> to keep track of what you
need for your mock. Using lenses means that adding something new won't
affect existing implementations.</p>
<p>Whoops; just about forgot, we need a way to pick which behaviour we
want when we're actually running our tests!
<code>TypeApplications</code> are a huge help here! We use
<code>TypeApplications</code> to pick which <code>DBImpl</code> and
<code>CliImpl</code> we want so that GHC doesn't get mad at us about
ambiguous type variables. Use them like this:</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">{-# LANGUAGE TypeApplications #-}</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a>runTestM&#39; <span class="op">@</span><span class="dt">DBUseMap</span> <span class="op">@</span><span class="dt">CliUseList</span></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a>            (emptyState <span class="op">&amp;</span> cliInput <span class="op">.~</span> [<span class="st">&quot;Steven&quot;</span>]) <span class="op">$</span></span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a>            storeName <span class="op">&gt;&gt;</span> getEntity <span class="st">&quot;name&quot;</span></span></code></pre></div>
<p>Now you can pretty easily keep a separate module where you define
<code>TestM</code> and all of its behaviours and instances, then just
use Type Applications to specialize your test monad when you run it to
get the behaviour you want!</p>
<p>And that wraps up our dive into testing using <code>mtl-style</code>
constraints! Thanks for joining me!</p>
<p>Special thanks to Sandy Maguire A.K.A. isovector for proofreading and
helping me vet my ideas!</p>
<p>If you have questions or comments hit me up on <a
href="https://twitter.com/chrislpenner">Twitter</a> or <a
href="https://www.reddit.com/user/ChrisPenner">Reddit</a>!</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Update Monads: Variation on State Monads</title>
      <link href="https://chrispenner.ca/posts/update-monad"/>
      <id>https://chrispenner.ca/posts/update-monad</id>
      <updated>2018-09-03T00:00:00Z</updated>
      <summary>We explore the applications and implementation of a generalized version
of Reader/Writer monads.</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/update-monad/change.jpg" alt="Update Monads: Variation on State Monads">
              <p>Today we're going to take a peek at the Update monad! It's a monad
which was formalized and described in <a
href="https://danelahman.github.io/papers/types13postproc.pdf">Update
Monads: Cointerpreting Directed Containers</a> by Danel Ahman and Tarmo
Uustalu. Most folks probably haven't heard of it before, likely because
most of what you'd use it for is well encompassed by the Reader, Writer,
and State monads. The Update Monad can do everything that Reader,
Writer, and State can do, but as a trade-off tends to be less efficient
at each of those tasks. It's definitely still worth checking out though;
not only is it interesting, there are a few things it handles quite
elegantly that might be a bit awkward to do in other ways.</p>
<p>Heads up; this probably isn't a great post for absolute beginners,
you'll want to have a decent understanding of <a
href="https://wiki.haskell.org/Monoid">monoids</a> and how <a
href="https://wiki.haskell.org/State_Monad">StateT</a> works before you
dive in here.</p>
<p>For readers who've spent a bit of time in Javascript land you may
notice that the Update Monad is basically a formalization of the <a
href="https://www.dotnetcurry.com/reactjs/1356/redux-pattern-tutorial">Flux
architecture</a>, most commonly associated with the Redux library;
although of course the Update Monad paper came first 😉. Most of the
concepts carry over in some form. The <code>Store</code> in redux
corresponds to the state of the Update monad, the <code>Action</code>s
in Redux correspond directly to our monoidal Actions in the Update
monad, and the view and dispatcher are left up to the implementor, but
could be likened to a base monad in a monad transformer stack which
could render, react, or get user input (e.g. IO).</p>
<p>The Update monad is very similar to the State monad; and in fact you
can implement either of them in terms of the other! Each has tasks at
which it excels; the Update Monad is good at keeping an audit log of
updates and limiting computations to a fixed set of permissible updates.
State on the other hand has a simpler interface, less boiler-plate, and
is MUCH more efficient at most practical tasks. It's no wonder that
<code>State</code> won out in the end, but the Update monad is still fun
to look at!</p>
<h2 id="structure-of-the-update-monad">Structure of the Update
Monad</h2>
<p>The Update Monad kinda looks like Reader, Writer and State got into a
horrific car accident and are now hopelessly entangled! Each computation
receives the current computation <code>state</code> (like
<code>Reader</code>) and can result in a monoidal action (like
<code>Writer</code>). The action is them applied to the state according
to a helper typeclass which I'll call <code>ApplyAction</code>: it has a
single method <code>applyAction :: p -&gt; s -&gt; s</code>; which
applies a given monoidal action <code>p</code> to a state resulting in a
new state. This edited state is passed on to the next computation (like
<code>State</code>) and away we go! Here's my implementation of this
idea for a new data type called <code>Update</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="kw">class</span> (<span class="dt">Monoid</span> p) <span class="ot">=&gt;</span> <span class="dt">ApplyAction</span> p s <span class="kw">where</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="ot">  applyAction ::</span> p <span class="ot">-&gt;</span> s <span class="ot">-&gt;</span> s</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Update</span> s p a <span class="ot">=</span> <span class="dt">Update</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>  {<span class="ot"> runUpdate ::</span> (s <span class="ot">-&gt;</span> (p, a))</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>  } <span class="kw">deriving</span> (<span class="dt">Functor</span>)</span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> (<span class="dt">ApplyAction</span> p s) <span class="ot">=&gt;</span> <span class="dt">Applicative</span> (<span class="dt">Update</span> s p) <span class="kw">where</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>  <span class="fu">pure</span> a <span class="ot">=</span> <span class="dt">Update</span> <span class="op">$</span> \_ <span class="ot">-&gt;</span> (<span class="fu">mempty</span>, a)</span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Update</span> u <span class="op">&lt;*&gt;</span> <span class="dt">Update</span> t <span class="ot">=</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Update</span> <span class="op">$</span> \s</span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a>      <span class="co">-- Run the first &#39;Update&#39; with the initial state </span></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a>      <span class="co">-- and get the monoidal action and the function out</span></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a>     <span class="ot">-&gt;</span></span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a>      <span class="kw">let</span> (p, f) <span class="ot">=</span> u s</span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a>      <span class="co">-- Run the second &#39;Update&#39; with a state which has been altered by</span></span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a>      <span class="co">-- the first action to get the &#39;a&#39; and another action</span></span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a>          (p&#39;, a) <span class="ot">=</span> t (applyAction p s)</span>
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a>      <span class="co">-- Combine the actions together and run the function</span></span>
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a>       <span class="kw">in</span> (p&#39; <span class="op">&lt;&gt;</span> p, f a)</span>
<span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-22"><a href="#cb1-22" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> (<span class="dt">ApplyAction</span> p s) <span class="ot">=&gt;</span> <span class="dt">Monad</span> (<span class="dt">Update</span> s p) <span class="kw">where</span></span>
<span id="cb1-23"><a href="#cb1-23" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Update</span> u <span class="op">&gt;&gt;=</span> f <span class="ot">=</span></span>
<span id="cb1-24"><a href="#cb1-24" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Update</span> <span class="op">$</span> \s</span>
<span id="cb1-25"><a href="#cb1-25" aria-hidden="true" tabindex="-1"></a>      <span class="co">-- Run the first &#39;Update&#39; with the initial state </span></span>
<span id="cb1-26"><a href="#cb1-26" aria-hidden="true" tabindex="-1"></a>      <span class="co">-- and get the monoidal action and the function out</span></span>
<span id="cb1-27"><a href="#cb1-27" aria-hidden="true" tabindex="-1"></a>     <span class="ot">-&gt;</span></span>
<span id="cb1-28"><a href="#cb1-28" aria-hidden="true" tabindex="-1"></a>      <span class="kw">let</span> (p, a) <span class="ot">=</span> u s</span>
<span id="cb1-29"><a href="#cb1-29" aria-hidden="true" tabindex="-1"></a>      <span class="co">-- Run the given function over our resulting value to get our next Update</span></span>
<span id="cb1-30"><a href="#cb1-30" aria-hidden="true" tabindex="-1"></a>          <span class="dt">Update</span> t <span class="ot">=</span> f a</span>
<span id="cb1-31"><a href="#cb1-31" aria-hidden="true" tabindex="-1"></a>      <span class="co">-- Run our new &#39;Update&#39; over the altered state</span></span>
<span id="cb1-32"><a href="#cb1-32" aria-hidden="true" tabindex="-1"></a>          (p&#39;, a&#39;) <span class="ot">=</span> t (applyAction p s)</span>
<span id="cb1-33"><a href="#cb1-33" aria-hidden="true" tabindex="-1"></a>      <span class="co">-- Combine the actions together and return the result</span></span>
<span id="cb1-34"><a href="#cb1-34" aria-hidden="true" tabindex="-1"></a>       <span class="kw">in</span> (p <span class="op">&lt;&gt;</span> p&#39;, a&#39;)</span></code></pre></div>
<p>We could of course also implement an <code>UpdateT</code> monad
transformer, but for the purposes of clarity I find it's easier to
understand the concrete <code>Update</code> type. If you like you can
take a peek at some other fun implementations <a
href="https://github.com/chrispenner/update-monad">here</a>. Hopefully
it's relatively clear from the implementation how things fit together.
Hopefully you can kind of see the similarities to Reader and Writer; we
are always returning and combining our monoidal actions as we continue
along, and each action has access to the state, but can't
<em>directly</em> modify it (you may only modify it by providing
<strong>actions</strong>). It's also worth noting that within any
individual step has only the latest <code>state</code> and it's not
possible to view any previous actions which may have occurred, just like
the Writer monad.</p>
<p>Now that we've implemented our Update Monad we've got our
<code>&gt;&gt;=</code> and <code>return</code>; but how do we actually
accomplish anything with it? There's no <code>MonadUpdate</code>
type-class provided in the paper, but here's my personal take on how to
get some utility out of it, I've narrowed it down to these two methods
which seem to encompass the core ideas behind the Update 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="ot">{-# LANGUAGE FunctionalDependencies #-}</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> (<span class="dt">ApplyAction</span> s p, <span class="dt">Monad</span> m) <span class="ot">=&gt;</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>      <span class="co">-- Because each of our methods only uses p OR m but not both </span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>      <span class="co">-- we use functional dependencies to assert to the type system that </span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>      <span class="co">-- both s and p are determined by &#39;m&#39;; this helps GHC be confident</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>      <span class="co">-- that we can&#39;t end up in spots where types could be ambiguous.</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>      <span class="dt">MonadUpdate</span> m s p <span class="op">|</span> m <span class="ot">-&gt;</span> s , m <span class="ot">-&gt;</span> p</span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a><span class="ot">    putAction ::</span> p <span class="ot">-&gt;</span> m ()</span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a><span class="ot">    getState ::</span> m s</span></code></pre></div>
<p>You'll notice some similarities here too! <code>putAction</code>
matches the signature for <code>tell</code>, and <code>getState</code>
matches <code>ask</code>! This class still provides new value though,
because unlike Reader and Writer the environment and the actions are
related to each other through the <code>ApplyAction</code> class; and
unlike <code>get</code> and <code>put</code> from <code>State</code> our
<code>putAction</code> and <code>getState</code> operate over
<strong>different</strong> types; you can only <code>put</code>
<strong>actions</strong>, and you can only <code>get</code>
<strong>state</strong>. We can formalize the expected relationship
between these methods with these laws I made up (take with a deluge of
salt):</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="co">-- Applying the &#39;empty&#39; action to your state shouldn&#39;t change your state</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>applyAction <span class="fu">mempty</span> <span class="op">==</span> <span class="fu">id</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="co">-- Putting an action and then another action should be the same as </span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="co">-- putting the combination of the two actions.</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a><span class="co">-- This law effectively enforces that `bind` is </span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a><span class="co">-- employing your monoid as expected</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>putAction p <span class="op">&gt;&gt;</span> putAction q <span class="op">==</span> putAction (p <span class="ot">`mappend`</span> q)</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 class="co">-- We expect that when we &#39;put&#39; an action that it gets applied to the state</span></span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a><span class="co">-- and that the change is visible immediately</span></span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a><span class="co">-- This law enforces that your implementation of bind </span></span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a><span class="co">-- is actually applying your monoid to the state using ApplyAction</span></span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a>applyAction p <span class="op">&lt;$&gt;</span> getState <span class="op">==</span> putAction p <span class="op">&gt;&gt;</span> getState</span></code></pre></div>
<p>Okay! Now of course we have to implement <code>MonadUpdate</code> for
our <code>Update</code> monad; easy-peasy:</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">ApplyAction</span> p s) <span class="ot">=&gt;</span> <span class="dt">MonadUpdate</span> (<span class="dt">Update</span> p s) p s <span class="kw">where</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>  putAction p <span class="ot">=</span> <span class="dt">Update</span> <span class="op">$</span> \_ <span class="ot">-&gt;</span> (p, ())</span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>  getState <span class="ot">=</span> <span class="dt">Update</span> <span class="op">$</span> \s <span class="ot">-&gt;</span> (<span class="fu">mempty</span>, s)</span></code></pre></div>
<p>All the plumbing is set up! Let's start looking into some actual
use-cases! I'll start by fully describing one particular use-case so we
get an understanding of how this all works, then we'll experiment by
tweaking our monoid or our <code>applyAction</code> function.</p>
<h2 id="a-concrete-use-case">A Concrete Use-Case</h2>
<p>Let's pick a use-case which I often see used for demonstrating the
State monad so we can see how our Update monad is similar, but slightly
different!</p>
<p>We're going to build a system which allows users to interact with
their bank account! We'll have three actions they can perform:
<code>Deposit</code>, <code>Withdraw</code>, and
<code>CollectInterest</code>. These actions will be applied to a simple
state <code>BankAccount Int</code> which keeps track of how many dollars
we have in the account!</p>
<p>Let's whip up the data types and operations we'll need:</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="co">-- Simple type to keep track our bank balance</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">BankBalance</span> <span class="ot">=</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>  <span class="dt">BankBalance</span> <span class="dt">Int</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Eq</span>, <span class="dt">Ord</span>, <span class="dt">Show</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="co">-- The three types of actions we can take on our account</span></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">AccountAction</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>  <span class="ot">=</span> <span class="dt">Deposit</span> <span class="dt">Int</span></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">Withdraw</span> <span class="dt">Int</span></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">ApplyInterest</span></span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Eq</span>, <span class="dt">Ord</span>, <span class="dt">Show</span>)</span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a><span class="co">-- We can apply any of our actions to our bank balance to get a new balance</span></span>
<span id="cb5-14"><a href="#cb5-14" aria-hidden="true" tabindex="-1"></a><span class="ot">processTransaction ::</span> <span class="dt">AccountAction</span> <span class="ot">-&gt;</span> <span class="dt">BankBalance</span> <span class="ot">-&gt;</span> <span class="dt">BankBalance</span></span>
<span id="cb5-15"><a href="#cb5-15" aria-hidden="true" tabindex="-1"></a>processTransaction (<span class="dt">Deposit</span> n) (<span class="dt">BankBalance</span> b) </span>
<span id="cb5-16"><a href="#cb5-16" aria-hidden="true" tabindex="-1"></a>    <span class="ot">=</span> <span class="dt">BankBalance</span> (b <span class="op">+</span> n)</span>
<span id="cb5-17"><a href="#cb5-17" aria-hidden="true" tabindex="-1"></a>processTransaction (<span class="dt">Withdraw</span> n) (<span class="dt">BankBalance</span> b) </span>
<span id="cb5-18"><a href="#cb5-18" aria-hidden="true" tabindex="-1"></a>    <span class="ot">=</span> <span class="dt">BankBalance</span> (b <span class="op">-</span> n)</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 class="co">-- This is a gross oversimplification...</span></span>
<span id="cb5-21"><a href="#cb5-21" aria-hidden="true" tabindex="-1"></a><span class="co">-- I really hope my bank does something smarter than this</span></span>
<span id="cb5-22"><a href="#cb5-22" aria-hidden="true" tabindex="-1"></a><span class="co">-- We (kinda sorta) add 10% interest, truncating any cents.</span></span>
<span id="cb5-23"><a href="#cb5-23" aria-hidden="true" tabindex="-1"></a><span class="co">-- Who likes pocket-change anyways ¯\_(ツ)_/¯</span></span>
<span id="cb5-24"><a href="#cb5-24" aria-hidden="true" tabindex="-1"></a>processTransaction <span class="dt">ApplyInterest</span> (<span class="dt">BankBalance</span> b) </span>
<span id="cb5-25"><a href="#cb5-25" aria-hidden="true" tabindex="-1"></a>    <span class="ot">=</span> <span class="dt">BankBalance</span> (<span class="fu">fromIntegral</span> balance <span class="op">*</span> <span class="fl">1.1</span>)</span></code></pre></div>
<p>Now we've got our Action type and our State type, let's relate them
together using <code>ApplyAction</code>.</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="kw">instance</span> <span class="dt">ApplyAction</span> <span class="dt">AccountAction</span> <span class="dt">BankBalance</span> <span class="kw">where</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>  applyAction <span class="ot">=</span> processTransaction</span></code></pre></div>
<p>One problem though! <code>AccountAction</code> isn't a monoid! Hrmmm,
this is a bit upsetting; it seems to quite clearly represent the domain
we want to work with, I'd really rather not muck up our data-type just
to make it fit here. Maybe there's something else we can do! In our
case, what does it mean to combine two actions? For a bank balance we
probably just want to run the first action, then the second one! We'll
need a value that acts as an 'empty' value for our monoid's
<code>mempty</code> too; for that we can just have some notion of
performing no actions!</p>
<p>There are a few ways to promote our <code>AccountAction</code> type
into a monoid with these properties; but one in particular stands out (I
can already hear some of you shouting it at your screens). That's right!
The <a href="https://en.wikipedia.org/wiki/Free_monoid">Free Monoid</a>
A.K.A. the List Monoid! Lists are kind of a special monoid in that they
can turn ANY type into a monoid for <strong>free</strong>! We get
<code>mappend == (++)</code> and <code>mempty == []</code>. This means
that instead of <em>actually</em> combining things we kinda just collect
them all, but fear not it still satisfies all the monoid laws correctly.
This isn't a post on Free Monoids though, so we'll upgrade our
<code>AccountAction</code> to <code>[AccountAction]</code> and move
on:</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="kw">instance</span> <span class="dt">ApplyAction</span> [<span class="dt">AccountAction</span>] <span class="dt">BankBalance</span> <span class="kw">where</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>  applyAction actions balance <span class="ot">=</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span><span class="ot"> allTransactions ::</span> <span class="dt">BankBalance</span> <span class="ot">-&gt;</span> <span class="dt">BankBalance</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>        allTransactions <span class="ot">=</span> appEndo <span class="op">$</span> <span class="fu">foldMap</span> (<span class="dt">Endo</span> <span class="op">.</span> processTransaction) (<span class="fu">reverse</span> actions)</span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>     <span class="kw">in</span> allTransactions balance</span></code></pre></div>
<p>We can keep our <code>processTransaction</code> function and
partially apply it to our list of Actions giving us a list of
<code>[BankBalance -&gt; BankBalance]</code>; we can then use the
<code>Endo</code> monoid to compose all of the functions together!
Unfortunately Endo does right-to-left composition, so we'll need to
reverse the list first (keeners will note we could use
<code>Dual . Endo</code> for the same results). Then we use
<code>appEndo</code> to unpack the resulting
<code>BankBalance -&gt; BankBalance</code> which we can apply to our
balance! Now that we have an instance for <code>ApplyAction</code> we
can start writing programs using <code>Update</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="ot">useATM ::</span> <span class="dt">Update</span> [<span class="dt">AccountAction</span>] <span class="dt">BankBalance</span> ()</span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>useATM <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>  putAction [<span class="dt">Deposit</span> <span class="dv">20</span>] <span class="co">-- BankBalance 20</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>  putAction [<span class="dt">Deposit</span> <span class="dv">30</span>] <span class="co">-- BankBalance 50</span></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a>  putAction [<span class="dt">ApplyInterest</span>] <span class="co">-- BankBalance 55</span></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a>  putAction [<span class="dt">Withdraw</span> <span class="dv">10</span>] <span class="co">-- BankBalance 45</span></span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a>  getState</span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a><span class="op">$&gt;</span> runUpdate useATM (<span class="dt">BankBalance</span> <span class="dv">0</span>)</span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a>([<span class="dt">Deposit</span> <span class="dv">20</span>,<span class="dt">Deposit</span> <span class="dv">30</span>,<span class="dt">ApplyInterest</span>,<span class="dt">Withdraw</span> <span class="dv">10</span>],<span class="dt">BankBalance</span> <span class="dv">45</span>)</span></code></pre></div>
<p>Hrmm, a bit clunky that we have to wrap every action with a list, but
we could pretty easily write a helper
<code>putAction' :: MonadUpdate m [p] s =&gt; p -&gt; m ()</code> to
help with that. By running the program we can see that we've collected
the actions in the right order and have 'combined' them all by running
<code>mappend</code>. We also see that our bank balance ends up where
we'd expect! This seems to be pretty similar to the State Monad, we
could write helpers that perform each of those actions over the State
pretty easily using <code>modify</code>; but the Update Monad gives us a
nice audit log of everything that happened! Not to mention that it
limits the available actions to ones that we support; users can't just
multiply their bank balance by 100, they have use the approved actions.
This means we could verify that actions happened in the correct order,
or we could run the same actions over a different starting state and see
how it works out!</p>
<p>The Update Monad also has a few tricks when it comes to testing your
programs. Since the only thing that can affect our state is a sequence
of actions, we can skip all the monad nonsense and test our business
logic by just testing that our <code>applyAction</code> function works
properly over different lists of actions! Observe:</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">testBankSystem ::</span> <span class="dt">Bool</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>testBankSystem <span class="ot">=</span></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>  applyAction [<span class="dt">Deposit</span> <span class="dv">20</span>, <span class="dt">Deposit</span> <span class="dv">30</span>, <span class="dt">ApplyInterest</span>, <span class="dt">Withdraw</span> <span class="dv">10</span>] (<span class="dt">BankBalance</span> <span class="dv">0</span>) </span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">==</span> <span class="dt">BankBalance</span> <span class="dv">45</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a><span class="op">$&gt;</span> testBankSystem</span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span></span></code></pre></div>
<p>Cool stuff! We can write the tests for our business logic without
worrying about the impure ways we'll probably be getting those actions
(like <code>IO</code>). This separation makes complicated business logic
pretty easy to test, and we can write separate tests for the 'glue' code
with confidence that the logic of our actions is correct and that our
program <strong>CAN'T</strong> edit our state in an invalid way since
all updates <strong>must</strong> be performed through the
<code>performTransaction</code> function. Note that using an impure base
monad like IO could certainly cause the list of actions which are
collected to change, but the list of actions which is collected
<strong>fully describes</strong> the state changes which take place; and
so testing only the application of actions is sufficient for testing
state updates.</p>
<p>There's really only so much we can do with <code>Update</code> alone,
but it's pretty easy to write an <code>UpdateT</code> transformer! I'll
leave you to check out the implementation <a
href="https://github.com/ChrisPenner/update-monad/blob/master/src/UpdateT.hs">here</a>
if you like; but this allows us to do things like decide which actions
to take based on user input (via <code>IO</code>), use our state to make
choices in the middle of our monad, or use other monads to perform more
interesting logic!</p>
<h2 id="customizing-the-update-monad-with-monoids">Customizing the
Update Monad with Monoids</h2>
<p>Okay! We've got one concrete use-case under our belts and have a
pretty good understanding of how all this works! let's see what we can
tweak to make things a bit more interesting!</p>
<p>Something that immediately interested me with the update monad is
that there are several distinct places to tweak its behaviour without
even needing to change which implementation of <code>MonadUpdate</code>
we use! We can change the action monoid, or which state we carry, or
even our <code>applyAction</code> function! This sort of tweakability
leads to all sorts of cool behaviour without too much work, and people
can build all sorts of things we didn't initially expect when we wrote
the type-classes!</p>
<p>I won't get super in depth on each of these and encourage you to
implement them yourself, but here are a few ideas to start with!</p>
<p>Customizations:</p>
<ul>
<li><code>Update w () a</code> with <code>applyAction _ () = ()</code>
<ul>
<li>A simple implementation of <code>Writer</code>!</li>
<li>The state doesn't matter; only the monoidal actions are
tracked!</li>
</ul></li>
<li><code>Update () r a</code> with <code>applyAction () r = r</code>
<ul>
<li>A simple implementation of <code>Reader</code>!</li>
<li>There're no sensible updates to do; so your state always stays the
same.</li>
</ul></li>
<li><code>Update (Last s) s a</code> with
<code>applyAction (Last p) s = fromMaybe s p</code>
<ul>
<li>This is the state monad implemented in Update!</li>
<li><code>get == getState</code></li>
<li><code>put == putAction . Last . Just</code></li>
<li><code>modify f == getState &gt;&gt;= putAction . Last . Just . f</code></li>
</ul></li>
<li><code>Update (Dual (Endo s)) s a</code> with
<code>applyAction (Dual (Endo p)) s = p s</code>
<ul>
<li>Another possible implementation of State inside Update!</li>
<li><code>get == getState</code></li>
<li><code>put == putAction . Dual . Endo . const</code></li>
<li><code>modify == putAction . Dual . Endo</code></li>
</ul></li>
<li><code>Update Any Bool a</code> with
<code>applyAction (Any b) s = b || s</code>
<ul>
<li>You could implement a short-circuiting approach where future actions
don't bother running if any previous action has succeeded! You can flip
the logic using <code>All</code> and <code>&amp;&amp;</code>.</li>
</ul></li>
</ul>
<h2 id="bonus-performance">Bonus: Performance</h2>
<p>The definition of the Update monad given here is quite simple because
it's the easiest to explain, but there are a few problems with it; the
most notable is that it ONLY passes along the new monoidal sum; NOT the
edited state from step to step. In mathematic terms it's still correct
since we can compute an up-to-date version of the state; but we have to
compute it from scratch every time we run an action! Clearly not great
for performance! Like I said earlier you can actually implement a more
efficient version of <code>MonadUpdate</code> using <code>State</code>!
We DO still need a dependency on <code>ApplyAction p s</code> though, so
keep that in mind. If we have one available we can do something like
this:</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">instance</span> <span class="dt">ApplyAction</span> p s <span class="ot">=&gt;</span> <span class="dt">MonadUpdate</span> (<span class="dt">State</span> (p, s)) p s <span class="kw">where</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>  putAction p&#39; <span class="ot">=</span> modify (\(p, s) <span class="ot">-&gt;</span> (p <span class="op">&lt;&gt;</span> p&#39;, applyAction p&#39; s))</span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>  getState <span class="ot">=</span> <span class="fu">snd</span> <span class="op">&lt;$&gt;</span> get</span></code></pre></div>
<p>Technically we don't even need to keep track of the monoidal sum as
we go along; there's no need for it! Unfortunately due to
FunctionalDependencies in our MonadUpdate class GHC gets mad if it
doesn't show up inside our State Monad <strong>somewhere</strong>. This
implementation keeps track of the latest state and just applies updates
as it goes along, giving us a more efficient implementation. Note that
using <code>put</code> or <code>modify</code> directly will probably
cause some unexpected behaviour in your Update Monad, so you may want to
wrap your <code>State</code> in a newtype first to prevent anyone from
messing with the internals.</p>
<p>Thanks for reading! I'm not perfect and really just go through all
this stuff in my spare time, so if I've missed something (or you enjoyed
the post 😄) please let me know! You can find me on <a
href="https://twitter.com/chrislpenner">Twitter</a> or <a
href="https://www.reddit.com/user/ChrisPenner">Reddit</a>!</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Typesafe Versioned APIs</title>
      <link href="https://chrispenner.ca/posts/typesafe-api-versioning"/>
      <id>https://chrispenner.ca/posts/typesafe-api-versioning</id>
      <updated>2018-08-04T00:00:00Z</updated>
      <summary>Exploring writing multiple versions of your application in a typesafe
way using data-kinds and functional dependencies</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/typesafe-api-versioning/numbers.jpg" alt="Typesafe Versioned APIs">
              <p>Today we're going to look at the idea of using Haskell's type system
to <strong>specialize our app implementation according to type-level
flags</strong>. More specifically we're going to look at a fun way to
write a monadic action which alters its behaviour based on which
<strong>version</strong> of a system it's embedded in, simultaneously
gaining ground on <a
href="https://en.wikipedia.org/wiki/Expression_problem">the expression
problem</a> and giving us compile-time guarantees that we haven't
accidentally mixed up code from different versions of our app!</p>
<p>The concrete example we'll be looking at is a simple web handler
which returns a JSON representation of a User; we'll start with a single
possible representation of the user, but will the evolve our system to
be able to return a different JSON schema depending on which
<strong>version</strong> of the API the user has selected.</p>
<p>Disclaimer; the system I present probably isn't a great idea in a
large production app, but is a fun experiment to learn more about higher
kinded types and functional dependencies so we're going to do it
anyways. Let's dive right in!</p>
<h2 id="starting-app">Starting App</h2>
<p>Let's build a quick starting app so we have something to work with;
I'll elide all the web and http related bits, we'll have a simple
handler that fetches a user and our <code>main</code> will run the
handler and print things out.</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="co">-- You&#39;ll need to have the &#39;mtl&#39; and &#39;aeson&#39; packages in your project</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="ot">{-# LANGUAGE OverloadedStrings #-}</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE NamedFieldPuns #-}</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE GeneralizedNewtypeDeriving #-}</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Monad.IO.Class</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Aeson</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a><span class="co">-- User -----------------------------------</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">User</span> <span class="ot">=</span> <span class="dt">User</span></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a>  {<span class="ot"> name ::</span> <span class="dt">String</span></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a>  } <span class="kw">deriving</span> (<span class="dt">Show</span>)</span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">ToJSON</span> (<span class="dt">User</span>) <span class="kw">where</span></span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a>  toJSON (<span class="dt">User</span> {name}) <span class="ot">=</span> object [<span class="st">&quot;name&quot;</span> <span class="op">.=</span> name]</span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a><span class="co">-- App Monad --------------------------------</span></span>
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">AppM</span> a <span class="ot">=</span> <span class="dt">AppM</span></span>
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a>  {<span class="ot"> runApp ::</span> <span class="dt">IO</span> a</span>
<span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a>  } <span class="kw">deriving</span> (<span class="dt">Functor</span>, <span class="dt">Applicative</span>, <span class="dt">Monad</span>, <span class="dt">MonadIO</span>)</span>
<span id="cb1-22"><a href="#cb1-22" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-23"><a href="#cb1-23" aria-hidden="true" tabindex="-1"></a><span class="co">-- User Service --------------------------------</span></span>
<span id="cb1-24"><a href="#cb1-24" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> (<span class="dt">Monad</span> m) <span class="ot">=&gt;</span></span>
<span id="cb1-25"><a href="#cb1-25" aria-hidden="true" tabindex="-1"></a>      <span class="dt">MonadUserService</span> m</span>
<span id="cb1-26"><a href="#cb1-26" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb1-27"><a href="#cb1-27" aria-hidden="true" tabindex="-1"></a><span class="ot">  getUser ::</span> m <span class="dt">User</span></span>
<span id="cb1-28"><a href="#cb1-28" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-29"><a href="#cb1-29" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">MonadUserService</span> <span class="dt">AppM</span> <span class="kw">where</span></span>
<span id="cb1-30"><a href="#cb1-30" aria-hidden="true" tabindex="-1"></a>  getUser <span class="ot">=</span> <span class="fu">return</span> (<span class="dt">User</span> <span class="st">&quot;Bob Johnson&quot;</span>)</span>
<span id="cb1-31"><a href="#cb1-31" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-32"><a href="#cb1-32" aria-hidden="true" tabindex="-1"></a><span class="co">-- App -----------------------------------------</span></span>
<span id="cb1-33"><a href="#cb1-33" aria-hidden="true" tabindex="-1"></a><span class="ot">userHandler ::</span> (<span class="dt">MonadUserService</span> m) <span class="ot">=&gt;</span> m <span class="dt">Value</span></span>
<span id="cb1-34"><a href="#cb1-34" aria-hidden="true" tabindex="-1"></a>userHandler <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb1-35"><a href="#cb1-35" aria-hidden="true" tabindex="-1"></a>  user <span class="ot">&lt;-</span> getUser</span>
<span id="cb1-36"><a href="#cb1-36" aria-hidden="true" tabindex="-1"></a>  <span class="fu">return</span> <span class="op">$</span> toJSON user</span>
<span id="cb1-37"><a href="#cb1-37" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-38"><a href="#cb1-38" aria-hidden="true" tabindex="-1"></a><span class="ot">app ::</span> (<span class="dt">MonadIO</span> m, <span class="dt">MonadUserService</span> m) <span class="ot">=&gt;</span> m ()</span>
<span id="cb1-39"><a href="#cb1-39" aria-hidden="true" tabindex="-1"></a>app <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb1-40"><a href="#cb1-40" aria-hidden="true" tabindex="-1"></a>  userJSON <span class="ot">&lt;-</span> userHandler</span>
<span id="cb1-41"><a href="#cb1-41" aria-hidden="true" tabindex="-1"></a>  liftIO <span class="op">$</span> <span class="fu">print</span> userJSON</span>
<span id="cb1-42"><a href="#cb1-42" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-43"><a href="#cb1-43" aria-hidden="true" tabindex="-1"></a><span class="ot">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb1-44"><a href="#cb1-44" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> runApp app</span></code></pre></div>
<p>Hopefully that's not too cryptic 😅</p>
<p>We've defined a simple user object and wrote an Aeson
<code>ToJSON</code> instance for it so we can serialize it. Then we
wrote a newtype wrapper around <code>IO</code> which we can use to
implement various instances on; note that we use
<code>GeneralizedNewtypeDeriving</code> to get our <code>Monad</code>
and <code>MonadIO</code> instances for free.</p>
<p>Next we define our interface for a User Service as the
<code>MonadUserService</code> typeclass; this has a single member:
<code>getUser</code> which defines how to get a user within a given
monad. In our case we'll write the simplest possible implementation for
our service and just return a static "Bob Johnson" user.</p>
<p>Next up we have our handler which gets a user, serializes, then
returns it. Lastly we've got an <code>app</code> which calls the user
then prints it, and a <code>main</code> which runs the app.</p>
<p>Brilliant, we're all set up; let's run it and see what we get!</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="op">&gt;</span> main</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Object</span> (fromList [(<span class="st">&quot;name&quot;</span>,<span class="dt">String</span> <span class="st">&quot;Bob Johnson&quot;</span>)])</span></code></pre></div>
<h2 id="chapter-2-wherein-our-api-evolves">Chapter 2; wherein our API
evolves</h2>
<p>They said we'd never succeed, but damn them all! In spite all of our
investor's criticisms our app is doing wonderfully! We have a whole 7 of
users and are making tens of dollars! Some users at large have requested
the ability to get a user's first and last name separately; but other
users have legacy systems built against our v1 API! Clearly it would be
far too much work to duplicate our entire user handler and make
alterations for our v2 API, let's see if we can
<strong>parameterize</strong> our app over our <strong>API
version</strong> and <strong>defer</strong> the choice of app version
(and implementation) until the last possible minute!</p>
<p>Like most Haskell refactors we can just start building what we want
and let the compiler guide the way; let's change our <code>User</code>
data type to reflect the needs of our users:</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="co">-- First attempt</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">User</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>  <span class="ot">=</span> <span class="dt">UserV1</span> {<span class="ot"> name ::</span> <span class="dt">String</span> }</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">UserV2</span> {<span class="ot"> firstName ::</span> <span class="dt">String</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>           ,<span class="ot"> lastName ::</span> <span class="dt">String</span> }</span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Show</span>)</span></code></pre></div>
<p>This reflects the choice in our app that the user type could be
either of the two shapes; but there's a few problems with this approach.
First and foremost is that this means that at EVERY stage in the app
where we use a <code>User</code> we need to pattern match over the
constructors and handle EVERY one; regardless of which version we happen
to be working with. Not only is this not what we wanted, but as we add
more versions later on the number of possible code paths we need to
handle explodes! One way we can avoid this chaos is to let the type
system know that our data is <strong>versioned</strong>. Enter
<code>GADT</code>s!</p>
<h2 id="gadts-with-phantom-types">GADT's with Phantom types</h2>
<p>Take a gander at 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 GADTs #-}</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE DataKinds #-}</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE KindSignatures #-}</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">import</span> <span class="dt">GHC.TypeLits</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">User</span> (<span class="ot">v ::</span> <span class="dt">Nat</span>) <span class="kw">where</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>  <span class="dt">UserV1</span><span class="ot"> ::</span> {<span class="ot"> name ::</span> <span class="dt">String</span>} <span class="ot">-&gt;</span> <span class="dt">User</span> <span class="dv">1</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>  <span class="dt">UserV2</span></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a><span class="ot">    ::</span> {<span class="ot"> firstName ::</span> <span class="dt">String</span></span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a>       ,<span class="ot"> lastName ::</span> <span class="dt">String</span>}</span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a>    <span class="ot">-&gt;</span> <span class="dt">User</span> <span class="dv">2</span></span></code></pre></div>
<p>If you haven't worked with <code>GADT</code>s before this may all
look a bit strange, let's break it down a bit:</p>
<p>First off; in order to even talk about <code>GADT</code>s we need the
<code>GADTs</code> language extension; this unlocks the
<code>data ... where</code> syntax! There's a bit more to it, but the
basic idea is that this allows us to effectively specify our data
constructors like we would normal functions in haskell. This means we
can specify constaints on our parameters, and in our case we can
specialize the types of the resulting value based on which particular
constructor was used. So if someone uses the <code>UserV1</code>
constructor they MUST get a <code>User 1</code>, and similarly with
<code>UserV2</code>. The compiler remembers this info and in our case
can actually tell that if we have a function which accepts a
<code>User 1</code> that we only need to match over the
<code>UserV1</code> constructor since any values of <code>User 1</code>
MUST have been constructed using <code>UserV1</code>.</p>
<p>Maybe I'm getting ahead of myself; how is it we can suddenly have
numbers like <code>1</code> and <code>2</code> in our types? The answer
lies within the <code>(v :: Nat)</code> annotation. This is a
<strong>Kind Signature</strong>, and as such naturally requires the
<code>KindSignatures</code> extension. Others have written more
exhaustively on the subject, but the basic idea is that <code>Nat</code>
is a kind, i.e. a 'type' for types. This means that the <code>v</code>
parameter can't take on just any type, but only types that are part of
the <code>Nat</code> kind, which corresponds to the natural (aka
non-negative) integers. This is handy, because it means people can't
create a user with a version number of <code>String</code> or
<code>()</code> or something silly like that. Lastly we need the
<code>DataKinds</code> extension to allow us to use Data Constructors in
our types; once that's enabled we can import <code>GHC.TypeLits</code>
and use integer literals in our types and GHC will figure it all
out.</p>
<p>The <code>v</code> paramter of our user is also something called a
"phantom type". It's a type parameter on a data type that doesn't
actually have an associated value in the right hand side of the data
definition. These sorts of things are useful for adding additional
information at the type level.</p>
<p>Step one done! We've successfully parameterized our datatype over a
version number at the type level! At this point your compiler is
probably bugging you about the fact that the <code>User</code>
constructor no longer exists; we originally implemented the
<code>ToJSON</code> class for the base User type, but now User needs an
additional type parameter. This is good! It means we can implement a
different instance for each version of user we have; which is basically
what we wanted to do in the first place!</p>
<p>Let's alter our <code>ToJSON</code> instance so it has a single name
parameter for v1 and a separate first and last name for v2!</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">{-# LANGUAGE FlexibleInstances #-}</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- ...</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">ToJSON</span> (<span class="dt">User</span> <span class="dv">1</span>) <span class="kw">where</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>  toJSON (<span class="dt">UserV1</span> {name}) <span class="ot">=</span> object [<span class="st">&quot;name&quot;</span> <span class="op">.=</span> name]</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="kw">instance</span> <span class="dt">ToJSON</span> (<span class="dt">User</span> <span class="dv">2</span>) <span class="kw">where</span></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>  toJSON (<span class="dt">UserV2</span> {firstName, lastName}) <span class="ot">=</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>    object [<span class="st">&quot;firstName&quot;</span> <span class="op">.=</span> firstName, <span class="st">&quot;lastName&quot;</span> <span class="op">.=</span> lastName]</span></code></pre></div>
<p>Here we're specifying <strong>different instances</strong> of
<code>ToJSON</code> for the different members of our <code>User</code>
datatype. Note that, as promised, the compiler KNOWS that only the
matching constructor needs to be matched on and that a
<code>UserV1</code> won't show up in an instance for
<code>User 2</code>. We'll need <code>FlexibleInstances</code> turned on
so GHC can handle complex types like <code>User 1</code> in an instance
definition.</p>
<p>Next it's time to fix up our <code>MonadUserService</code> class, we
know that <code>getUser</code> needs to return a user, but which user
type should it return? We can imagine someone implementing a
<code>MonadUserService</code> for <code>User 1</code> and also for
<code>User 2</code>, so it would be nice if instances could specify
which version they want to work with. To accomplish that we can add an
additional parameter to the class:</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 MultiParamTypeClasses #-}</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- ...</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> (<span class="dt">Monad</span> m) <span class="ot">=&gt;</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>      <span class="dt">MonadUserService</span> v m</span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a><span class="ot">  getUser ::</span> m (<span class="dt">User</span> v)</span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">MonadUserService</span> <span class="dv">1</span> <span class="dt">AppM</span> <span class="kw">where</span></span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a>  getUser <span class="ot">=</span> <span class="fu">return</span> (<span class="dt">UserV1</span> <span class="st">&quot;Bob Johnson&quot;</span>)</span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">MonadUserService</span> <span class="dv">2</span> <span class="dt">AppM</span> <span class="kw">where</span></span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a>  getUser <span class="ot">=</span> <span class="fu">return</span> (<span class="dt">UserV2</span> <span class="st">&quot;Bob&quot;</span> <span class="st">&quot;Johnson&quot;</span>)</span></code></pre></div>
<p>Just like <code>ToJSON</code> we can now implement the typeclass
instance differently for each version of our user. We'll need
<code>MultiParamTypeClasses</code> to add the <code>v</code> parameter
to our typeclass.</p>
<h2 id="generalizing-the-handler-and-app-over-version">Generalizing the
handler and app over version</h2>
<p>We're moving along nicely! Next we need our <code>userHandler</code>
and <code>app</code> to know about version numbers, however this layer
of our app doesn't really care which exact version of user it's working
with, mostly it just cares that certain instances exist for that user.
Ideally we can write versions of these that work for either of our user
versions all at once.</p>
<p>The first step is to introduce our new paramterized typeclasses:</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">{-# LANGUAGE FlexibleContexts #-}</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="ot">userHandler ::</span> (<span class="dt">ToJSON</span> (<span class="dt">User</span> v), <span class="dt">MonadUserService</span> v m) <span class="ot">=&gt;</span> m <span class="dt">Value</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>userHandler <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>  user <span class="ot">&lt;-</span> getUser</span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>  <span class="fu">return</span> <span class="op">$</span> toJSON user</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="ot">app ::</span> (<span class="dt">ToJSON</span> (<span class="dt">User</span> v), <span class="dt">MonadIO</span> m, <span class="dt">MonadUserService</span> v m) <span class="ot">=&gt;</span> m ()</span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a>app <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a>  userJSON <span class="ot">&lt;-</span> userHandler</span>
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a>  liftIO <span class="op">$</span> <span class="fu">print</span> userJSON</span></code></pre></div>
<p>Now we run into a bit of a problem;</p>
<pre><code>    • Could not deduce (MonadUserService v0 m)
      from the context: (MonadIO m, MonadUserService v m)
        bound by the type signature for:
                   app :: forall (m :: * -&gt; *) (v :: Nat).
                          (MonadIO m, MonadUserService v m) =&gt;
                          m ()
        at /Users/cpenner/dev/typesafe-versioning/src/Before2.hs:54:8-48
      The type variable ‘v0’ is ambiguous
    • In the ambiguity check for ‘app’
      To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
      In the type signature:
        app :: (MonadIO m, MonadUserService v m) =&gt; m ()</code></pre>
<p>It's telling us it can't tell which user version we want it to use!
So there are a few ways we can fix this; one way would be to specify the
specific type that we'd like <code>v</code> to be each time it's used;
we can enable <code>AllowAmbiguousTypes</code>,
<code>TypeApplications</code> and <code>ScopedTypeVariables</code> to
try that; but this ends up being pretty verbose and isn't the nicest to
work with. We won't dive into that possibility, but I'd recommend you
give it a try though if you like a challenge!</p>
<p>The other option we have is to clear up the disambiguity by giving
the type system another way to determine what <code>v</code> should be;
in our case the monad <code>m</code> is pervasive throughout our app, so
if we can somehow infer <code>v</code> from <code>m</code> then we can
save ourselves a lot of trouble. We're already associating the two
within the typeclass definition
<code>class (Monad m) =&gt; MonadUserService v m</code>; however the
type system recognizes that there could be an instance for several
different values of <code>v</code>; and of course we've implemented
exactly that!</p>
<p>The way to fix this is to tell the type system that there's
<strong>one-and-only-one</strong> <code>v</code> for each <code>m</code>
using <strong>FunctionalDependencies</strong>; and then find a way to
encode the <code>v</code> inside the <code>m</code> so we can still run
the different versions of our app.</p>
<p>Lets add a new extension and alter our typeclass appropriately:</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">{-# LANGUAGE FunctionalDependencies #-}</span></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="kw">class</span> (<span class="dt">Monad</span> m) <span class="ot">=&gt;</span> <span class="dt">MonadUserService</span> v m <span class="op">|</span> m <span class="ot">-&gt;</span> v</span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a><span class="ot">  getUser ::</span> m (<span class="dt">User</span> v)</span></code></pre></div>
<p>We've added a the <code>| m -&gt; v</code> annotation which reads
something like "... where <code>m</code> determines <code>v</code>".
Adding this annotation allows us to avoid the
<code>Ambiguous Type</code> errors because we've told the type system
that for any given <code>m</code> there's only one <code>v</code>; so if
it knows <code>m</code>, (which in our case it does) then it can safely
determine exactly which <code>v</code> to use.</p>
<p>Now you'll probably see something like this:</p>
<pre><code>Functional dependencies conflict between instance declarations:
    instance MonadUserService 1 AppM
    -- Defined at ...
    instance MonadUserService 2 AppM
    -- Defined at ...</code></pre>
<p>We told the type system there'd only be a single <code>v</code> for
every <code>m</code>; then immediately gave it two instances for
<code>AppM</code>; GHC caught us lying! That's okay, GHC will forgive us
if we can somehow make the two <code>m</code>'s different! We can do
this by adding a phantom type to the <code>AppM</code> monad which
simply denotes which version we're working with; let's try editing our
<code>AppM</code> monad like this:</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">newtype</span> <span class="dt">AppM</span> (<span class="ot">v ::</span> <span class="dt">Nat</span>) a <span class="ot">=</span> <span class="dt">AppM</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>  {<span class="ot"> runApp ::</span> <span class="dt">IO</span> a</span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>  } <span class="kw">deriving</span> (<span class="dt">Functor</span>, <span class="dt">Applicative</span>, <span class="dt">Monad</span>, <span class="dt">MonadIO</span>)</span></code></pre></div>
<p>We've added the <code>(v :: Nat)</code> type argument here, it
doesn't show up any where in our data, meaning it's a <strong>Phantom
Type</strong> which is just there to help use denote something at the
type level, in this case we denote which user version we're currently
working with. Now we can add that additional info to our
<code>MonadUserService</code> instances:</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">instance</span> <span class="dt">MonadUserService</span> <span class="dv">1</span> (<span class="dt">AppM</span> <span class="dv">1</span>) <span class="kw">where</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>  getUser <span class="ot">=</span> <span class="fu">return</span> (<span class="dt">UserV1</span> <span class="st">&quot;Bob Johnson&quot;</span>)</span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">MonadUserService</span> <span class="dv">2</span> (<span class="dt">AppM</span> <span class="dv">2</span>) <span class="kw">where</span></span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a>  getUser <span class="ot">=</span> <span class="fu">return</span> (<span class="dt">UserV2</span> <span class="st">&quot;Bob&quot;</span> <span class="st">&quot;Johnson&quot;</span>)</span></code></pre></div>
<p>It seems a bit redundant, but it gets us where we're going!</p>
<p>Not done yet! We still need to tell GHC which version of our
<code>app</code> we want to run! You can use
<code>TypeApplications</code> for this if you like, but the easier way
is to just specify with a type annotation:</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">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> runApp (<span class="ot">app ::</span> <span class="dt">AppM</span> <span class="dv">1</span> ())</span></code></pre></div>
<p>Try running the different versions and see what you get!</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>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> runApp (<span class="ot">app ::</span> <span class="dt">AppM</span> <span class="dv">1</span> ())</span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Object</span> (fromList [(<span class="st">&quot;name&quot;</span>,<span class="dt">String</span> <span class="st">&quot;Bob Johnson&quot;</span>)])</span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> runApp (<span class="ot">app ::</span> <span class="dt">AppM</span> <span class="dv">2</span> ())</span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Object</span> (fromList [(<span class="st">&quot;lastName&quot;</span>,<span class="dt">String</span> <span class="st">&quot;Johnson&quot;</span>),(<span class="st">&quot;firstName&quot;</span>,<span class="dt">String</span> <span class="st">&quot;Bob&quot;</span>)])</span></code></pre></div>
<p>That should do it! We can quickly and easily switch between versions
of our app by changing the type annotation; if we like we could even
write some aliases to help out:</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">appV1 ::</span> <span class="dt">AppM</span> <span class="dv">1</span> ()</span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>appV1 <span class="ot">=</span> app</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="ot">appV2 ::</span> <span class="dt">AppM</span> <span class="dv">2</span> ()</span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a>appV2 <span class="ot">=</span> app</span></code></pre></div>
<p>Nice! Now we can write our app in such a way that it's
<strong>generic</strong> and <strong>polymorphic</strong> over the
<strong>version</strong> of user when that part of the app doesn't care
which version it is, but we can still <strong>specialize</strong> to a
specific user version when needed by using specific typeclasses or by
pattern matching on the User constructor. The type system will guarantee
that we never accidentally switch between user versions in the middle of
our app; and we can defer the choice of version until the last possible
second (at the top level call site). Sounds like a win to me!</p>
<p>Hope you learned something!</p>
<h2 id="bonus-section-asserting-version-compatibility">Bonus Section:
Asserting Version Compatibility</h2>
<p>If you take this pattern even further you might end up with multiple
versions in your app; something like this:</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="dt">AppM</span> (<span class="ot">userVersion ::</span> <span class="dt">Nat</span>) (<span class="ot">postVersion ::</span> <span class="dt">Nat</span>) a <span class="ot">=</span> <span class="dt">AppM</span></span></code></pre></div>
<p>This works fine of course, but as the number of version parameters
grows it gets tough to keep track of which versions are compatible with
each other, maybe <code>userVersion == 2</code> is only compatible with
a <code>postVersion &gt;= 3</code>? Here's a fun trick using
<code>ConstraintKinds</code> and <code>TypeFamilies</code> to let us
easily assert that our app is never run with incompatible versions:</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="ot">{-# LANGUAGE TypeOperators #-}</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE TypeFamilies #-}</span></span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE UndecidableInstances #-}</span></span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Kind</span></span>
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-7"><a href="#cb17-7" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="kw">family</span> <span class="dt">Compatible</span> (<span class="ot">userVersion ::</span> <span class="dt">Nat</span>) (<span class="ot">postVersion ::</span> <span class="dt">Nat</span>)<span class="ot"> ::</span> <span class="dt">Constraint</span> <span class="kw">where</span></span>
<span id="cb17-8"><a href="#cb17-8" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Compatible</span> <span class="dv">1</span> <span class="dv">1</span> <span class="ot">=</span> ()</span>
<span id="cb17-9"><a href="#cb17-9" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Compatible</span> <span class="dv">2</span> <span class="dv">3</span> <span class="ot">=</span> ()</span>
<span id="cb17-10"><a href="#cb17-10" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Compatible</span> <span class="dv">2</span> <span class="dv">4</span> <span class="ot">=</span> ()</span>
<span id="cb17-11"><a href="#cb17-11" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Compatible</span> a b <span class="ot">=</span> <span class="dt">TypeError</span> (<span class="dt">Text</span> <span class="st">&quot;userVersion &quot;</span> <span class="op">:&lt;&gt;:</span> <span class="dt">ShowType</span> a </span>
<span id="cb17-12"><a href="#cb17-12" aria-hidden="true" tabindex="-1"></a>                         <span class="op">:&lt;&gt;:</span> <span class="dt">Text</span> <span class="st">&quot; is not compatible with postVersion &quot;</span> <span class="op">:&lt;&gt;:</span> <span class="dt">ShowType</span> b)</span></code></pre></div>
<p>You may need to dig into this a bit on your own to understand it
fully, but the basic idea is that it's a function over types which when
given two versions will either result in an empty constraint (i.e.
<code>()</code>) which will allow compilation to continue, or will
result in a failing <code>TypeError</code> and will print a nice error
message to the user. You can use it like this:</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="ot">runAppWithCheck ::</span> <span class="dt">Compatible</span> userVersion postVersion <span class="ot">=&gt;</span> <span class="dt">AppM</span> userVersion postVersion a <span class="ot">-&gt;</span> <span class="dt">IO</span> a</span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- We only really need the additional type information, under the hood we can just call `runApp`</span></span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a>runAppWithCheck <span class="ot">=</span> runApp</span></code></pre></div>
<p>Now if you try to run your app with incompatible versions you'll get
a nice error something like:</p>
<pre><code>error:
    • userVersion 2 is not compatible with postVersion 1
    • In the expression: runAppWithCheck (app :: AppM 2 1 ())
      In an equation for ‘main’:
          main = runAppWithCheck (app :: AppM 2 1 ())
   |
   | main = runAppWithCheck (app :: AppM 2 1 ())</code></pre>
<p>Good stuff! You can even use <code>DataKinds</code> to add a little
structure to your version numbers so you can't accidentally mix up your
userVersions with your postVersions, but I'll leave that for you to
figure out 😉</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Monoidal Sorting</title>
      <link href="https://chrispenner.ca/posts/monoid-sort"/>
      <id>https://chrispenner.ca/posts/monoid-sort</id>
      <updated>2018-07-22T00:00:00Z</updated>
      <summary>We explore a merge-sort monoid</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/monoid-sort/sorting.jpg" alt="Monoidal Sorting">
              <p>As I dive deeper into functional programming I'm beginning to think
that monoids can solve most problems. In general monoids work well in
combination with other structures and algorithms, for instance <a
href="/posts/intro-to-finger-trees">Finger Trees</a>, and folds!</p>
<p>This post is just yet-another-demonstration of how adaptable monoids
can really be by solving a problem most people wouldn't immediately
associate with monoids.</p>
<h2 id="sorting">Sorting</h2>
<p>We're going to write a wrapper around lists which rather than the
traditional monoid for lists (concat) instead sorts the two into each
other; not much to talk about really, lets see the 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="kw">newtype</span> <span class="dt">Sort</span> a <span class="ot">=</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Sort</span> {</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="ot">        getSorted ::</span> [a]</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>    } <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>)</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>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="co">-- So long as the elements can be ordered we can combine two sorted lists using mergeSort</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> (<span class="dt">Ord</span> a) <span class="ot">=&gt;</span> <span class="dt">Monoid</span> (<span class="dt">Sort</span> a) <span class="kw">where</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>  <span class="fu">mempty</span> <span class="ot">=</span> <span class="dt">Sort</span> []</span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>  <span class="fu">mappend</span> (<span class="dt">Sort</span> a) (<span class="dt">Sort</span> b) <span class="ot">=</span> <span class="dt">Sort</span> <span class="op">$</span> mergeSort a b</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="co">-- simple merge sort implementation</span></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a><span class="ot">mergeSort ::</span> <span class="dt">Ord</span> a <span class="ot">=&gt;</span> [a] <span class="ot">-&gt;</span> [a] <span class="ot">-&gt;</span> [a]</span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a>mergeSort [] xs <span class="ot">=</span> xs</span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a>mergeSort xs [] <span class="ot">=</span> xs</span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a>mergeSort (x<span class="op">:</span>xs) (y<span class="op">:</span>ys)</span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> y <span class="op">&lt;</span> x <span class="ot">=</span> y <span class="op">:</span> mergeSort (x <span class="op">:</span> xs) ys</span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a>mergeSort (x<span class="op">:</span>xs) ys <span class="ot">=</span> x <span class="op">:</span> mergeSort xs ys</span>
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a><span class="co">-- We&#39;ll keep the &#39;Sort&#39; constructor private and expose this smart constructor instead so we can</span></span>
<span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a><span class="co">-- guarantee that every list inside a `Sort` is guaranteed to be sorted.</span></span>
<span id="cb1-22"><a href="#cb1-22" aria-hidden="true" tabindex="-1"></a><span class="co">-- We could use a simple sort function for this, but might as well use mergeSort since </span></span>
<span id="cb1-23"><a href="#cb1-23" aria-hidden="true" tabindex="-1"></a><span class="co">-- we already wrote it.</span></span>
<span id="cb1-24"><a href="#cb1-24" aria-hidden="true" tabindex="-1"></a><span class="ot">toSort ::</span> [a] <span class="ot">-&gt;</span> <span class="dt">Sort</span> a</span>
<span id="cb1-25"><a href="#cb1-25" aria-hidden="true" tabindex="-1"></a>toSort <span class="ot">=</span> <span class="fu">foldMap</span> (<span class="dt">Sort</span> <span class="op">.</span> <span class="fu">pure</span>)</span></code></pre></div>
<p>Let's try it out:</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="op">&gt;</span> toSort [<span class="dv">1</span>, <span class="dv">5</span>, <span class="dv">2</span>, <span class="dv">3</span>] <span class="ot">`mappend`</span> toSort [<span class="dv">10</span>, <span class="dv">7</span>, <span class="dv">8</span>, <span class="dv">4</span>]</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Sort</span> {getSorted <span class="ot">=</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>,<span class="dv">5</span>,<span class="dv">7</span>,<span class="dv">8</span>,<span class="dv">10</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="op">&gt;</span> <span class="fu">foldMap</span> (toSort <span class="op">.</span> <span class="fu">pure</span>) [<span class="dv">5</span>, <span class="dv">2</span>, <span class="dv">3</span>, <span class="dv">1</span>, <span class="dv">0</span>, <span class="dv">8</span>]</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Sort</span> {getSorted <span class="ot">=</span> [<span class="dv">0</span>,<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">5</span>,<span class="dv">8</span>]}</span></code></pre></div>
<p>Nothing too complicated really! <code>mappend</code> over sorted
lists just sorts the combined list; we have the benefit in this case of
knowing that any list within a <code>Sort</code> is guaranteed to be
sorted already so we can an efficient merge sort algorithm. This doesn't
make much difference when we're appending small sets of values together,
but in particular cases like FingerTrees where intermediate monoidal
sums are cached it can really speed things up!</p>
<p>Just like that we've got a cool monoid which sorts lists for us, and
by combining it with <code>foldMap</code> we can easily sort the values
from any foldable structure. One other benefit here is that since we
know monoids are associative, if we have a huge list of elements we need
sorted we can actually split up the list, sort chunks in parallel and
combine them all and we have a guarantee that it'll all work out.</p>
<p>Anyways, that's about it for this one, nothing to write home about,
but I think it's fun to discover new monoids!</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>A Practical Introduction to Finger Trees</title>
      <link href="https://chrispenner.ca/posts/intro-to-finger-trees"/>
      <id>https://chrispenner.ca/posts/intro-to-finger-trees</id>
      <updated>2018-07-21T00:00:00Z</updated>
      <summary>How to use finger trees to solve problems by choosing the appropriate
monoid measure.</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/intro-to-finger-trees/finger-tree.jpg" alt="A Practical Introduction to Finger Trees">
              <p>Finger Trees are definitely the coolest data structure I was never
taught in school. The gist of Finger Trees is that they represent
sequences of elements where the elements also have a measurable
'descriptor' of some kind. If that sounds vague it's because it is! The
generality here is what allows Finger Trees to solve so many different
types of problems, but it does require a few examples and explanations
to understand. In this post we'll talk about how the trees work at a
high level, then we'll use them to build a random-access array-like
structure with reasonable performance characteristics.</p>
<p>This data structure stands on the shoulders of giants, it uses a
structure called a <code>Monoid</code> at its core.</p>
<h2 id="monoids">Monoids</h2>
<p>If you're entirely unfamiliar with the concept of monoids, or just
need a refresher, it would be a good idea to get a solid grounding there
first; <a
href="https://www.schoolofhaskell.com/user/mgsloan/monoids-tour">here's
a good place to start</a>.</p>
<p>Monoids are incredibly useful; and the more I learn about Category
Theory the more applications I find for monoidal structures. Once you
start to think in monoids you start to realize how many things you once
thought were unique and interesting problems are actually just a monoid
and a fold away from some other well-solved problem. We're going to
start off by introducing a new tool (i.e. data structure) which employs
monoids to do amazing things! Enter <a
href="https://en.wikipedia.org/wiki/Finger_tree">Finger Trees</a>!
Finger Trees are an adaptable purely functional data structure; they're
actually an extremely general structure which makes it a bit difficult
to explain without a concrete use case. This is because they utilize a
Monoid in the foundation of the data structure, and the Monoid you
choose can drastically affect how the structure behaves. Here's a glance
at the sort of things you could do by choosing different Monoids:</p>
<ul>
<li>Random access/sequence slicing using <a
href="https://hackage.haskell.org/package/base-4.11.1.0/docs/Data-Monoid.html#t:Sum"><code>Sum</code></a>:
see <a
href="https://hackage.haskell.org/package/containers-0.6.0.1/docs/Data-Sequence.html">Data.Sequence</a>;
we'll explore this one just below!</li>
<li>Heap using <a
href="https://hackage.haskell.org/package/base-4.11.1.0/docs/Data-Semigroup.html#t:Max"><code>Max/Min</code></a>:
see <a
href="https://hackage.haskell.org/package/fingertree-0.1.4.1/docs/Data-PriorityQueue-FingerTree.html">Data.PriorityQueue.FingerTree</a></li>
<li>Ordered Sequence slicing using <a
href="https://hackage.haskell.org/package/base-4.11.1.0/docs/Data-Monoid.html#t:Last">Last</a>:
see the section on <a
href="http://www.staff.city.ac.uk/~ross/papers/FingerTree.pdf">Ordered
Sequences</a></li>
<li>Interval Searching using a custom interval expansion Monoid: see <a
href="https://hackage.haskell.org/package/fingertree-0.1.4.1/docs/Data-IntervalMap-FingerTree.html">Data.IntervalMap.FingerTree</a></li>
<li>Text slicing and dicing using a product of <code>Sum</code>s: see <a
href="https://hackage.haskell.org/package/yi-rope">Yi.Rope</a></li>
<li>Performant merge sort using a custom merge monoid: blog post coming
eventually!</li>
<li>Many more! Just use your imagination!</li>
</ul>
<p>How does it all work? Let's learn how to build a simple random-access
\&lt;air-quotes&gt; Array \&lt;/air-quotes&gt; using a Finger Tree so we
can get a sense of things</p>
<h2 id="random-access-array-using-a-finger-trees">Random Access Array
using a Finger Trees</h2>
<p>Let's implement a simple random access list using a Finger Tree!
After a quick glance through the <a
href="https://hackage.haskell.org/package/fingertree-0.1.4.1/docs/Data-FingerTree.html">Data.FingerTree
Docs</a> it's a bit tough to tell where we might start! The workhorse of
the Finger Tree library is the <code>split</code> function:</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">split ::</span> <span class="dt">Measured</span> v a <span class="ot">=&gt;</span> (v <span class="ot">-&gt;</span> <span class="dt">Bool</span>) <span class="ot">-&gt;</span> <span class="dt">FingerTree</span> v a <span class="ot">-&gt;</span> (<span class="dt">FingerTree</span> v a, <span class="dt">FingerTree</span> v a)</span></code></pre></div>
<p>Yikes, let's break this down:</p>
<ul>
<li><code>Measured v a</code>: Measured is a simple typeclass which
given an <code>a</code> can convert it into some monoid
<code>v</code></li>
<li><code>(v -&gt; Bool)</code>: This is our search predicate,
<code>split</code> will use it to split a sequence into two smaller
subsequences: The longest prefix subsequence such that running the
predicate on the measure of this subsequence is <code>False</code>, and
the everything that's left-over.</li>
<li><code>FingerTree v a</code>: This is the tree we want to split, with
a monoidal measure <code>v</code> and elements of type
<code>a</code>.</li>
<li><code>(FingerTree v a, FingerTree v a)</code>: The two (possibly
empty) subsequences, the first is before the split point the second
contains the inflection point of our predicate and everything past
it.</li>
</ul>
<p>That's all great, but how can we actually use it to solve our
problem? What does splitting up a sequence actually have to do with
indexing into a list? Finger Trees get their performance characterics by
searching through subtrees using a strategy very similar to a binary
search, they run the predicate on cached "measures" of subtrees
recursively honing in on the <strong>inflection point</strong> where the
predicate flips from <code>False</code> to <code>True</code>. So what we
need to do is find some pairing of a monoid and a predicate on that
monoid which finds the place in the sequence we're looking for. Getting
the first or last element of a Finger Tree is a simple <code>O(1)</code>
operation, so if we can split the list either directly <em>before</em>
or directly <em>after</em> the index we're looking for, then we're
pretty much done!</p>
<p>Building a predicate for this is pretty simple, we just need to be
able to determine whether the index we're looking for is within some
prefix of our total sequence, which phrased simply is just:
<code>length sequence &gt; index</code>; we can use this predicate to
recursively hone in on the point where adding a single element alters
the predicate's result from false to true, and we've found our index!
The predicate runs on the measure of the values, which must be a monoid;
so we need to represent the length of our sequence as some monoid, the
combination of the monoidal measure of two sequences must also match the
measure of the combination of the sequences themselves! Luckily for us
the length of the combination of two lists is just the sum of the
lengths! This gives us the hint that we can use the <a
href="https://hackage.haskell.org/package/base-4.11.1.0/docs/Data-Monoid.html#t:Sum"><code>Sum</code>
Monoid</a> as our measure!</p>
<p>We're so close now, let's write some code to make it happen.</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">{-# LANGUAGE OverloadedStrings #-}</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE FlexibleInstances #-}</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE MultiParamTypeClasses #-}</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.FingerTree</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Monoid</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a><span class="co">-- We need to wrap our primitive value type in a newtype;</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a><span class="co">-- This allows us to store ANY value in the sequence and helps us avoid</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a><span class="co">-- some trouble with functional dependencies and orphan instances.</span></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">Size</span> a <span class="ot">=</span> <span class="dt">Size</span></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a>  {<span class="ot"> getSize ::</span> a</span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a>  } <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>)</span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-15"><a href="#cb2-15" aria-hidden="true" tabindex="-1"></a><span class="co">-- Measured is the typeclass we implement to tell the FingerTree how to measure</span></span>
<span id="cb2-16"><a href="#cb2-16" aria-hidden="true" tabindex="-1"></a><span class="co">-- our values into a monoid. In our case every individual element is simply of length &#39;1&#39;</span></span>
<span id="cb2-17"><a href="#cb2-17" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Measured</span> (<span class="dt">Sum</span> <span class="dt">Int</span>) (<span class="dt">Size</span> a) <span class="kw">where</span></span>
<span id="cb2-18"><a href="#cb2-18" aria-hidden="true" tabindex="-1"></a>  measure _ <span class="ot">=</span> <span class="dt">Sum</span> <span class="dv">1</span></span>
<span id="cb2-19"><a href="#cb2-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-20"><a href="#cb2-20" aria-hidden="true" tabindex="-1"></a><span class="co">-- We wrap our values in the &#39;Size&#39; wrapper and build a Finger Tree</span></span>
<span id="cb2-21"><a href="#cb2-21" aria-hidden="true" tabindex="-1"></a><span class="ot">alphabet ::</span> <span class="dt">FingerTree</span> (<span class="dt">Sum</span> <span class="dt">Int</span>) (<span class="dt">Size</span> <span class="dt">Char</span>)</span>
<span id="cb2-22"><a href="#cb2-22" aria-hidden="true" tabindex="-1"></a>alphabet <span class="ot">=</span> fromList (<span class="fu">fmap</span> <span class="dt">Size</span> <span class="st">&quot;abcdefghijklmnopqrstuvwxyz&quot;</span>)</span>
<span id="cb2-23"><a href="#cb2-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-24"><a href="#cb2-24" aria-hidden="true" tabindex="-1"></a><span class="co">-- Get a given index from the tree if it exists</span></span>
<span id="cb2-25"><a href="#cb2-25" aria-hidden="true" tabindex="-1"></a><span class="ot">atIndex ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">FingerTree</span> (<span class="dt">Sum</span> <span class="dt">Int</span>) (<span class="dt">Size</span> a) <span class="ot">-&gt;</span> <span class="dt">Maybe</span> a</span>
<span id="cb2-26"><a href="#cb2-26" aria-hidden="true" tabindex="-1"></a>atIndex n t <span class="ot">=</span></span>
<span id="cb2-27"><a href="#cb2-27" aria-hidden="true" tabindex="-1"></a>  <span class="kw">case</span> viewl <span class="op">.</span> <span class="fu">snd</span> <span class="op">$</span> split (<span class="op">&gt;</span> <span class="dt">Sum</span> n) t <span class="kw">of</span></span>
<span id="cb2-28"><a href="#cb2-28" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Size</span> c <span class="op">:&lt;</span> _ <span class="ot">-&gt;</span> <span class="dt">Just</span> c</span>
<span id="cb2-29"><a href="#cb2-29" aria-hidden="true" tabindex="-1"></a>    _ <span class="ot">-&gt;</span> <span class="dt">Nothing</span></span></code></pre></div>
<p>Hopefully the first bits are pretty self explanatory, we set up our
datatypes so the tree knows how to measure our elements, and it already
knows how to combine measures via Sum's Monoid instance. Lastly in
<code>atIndex</code> we tell the tree to split open at the point where
the length of the measured subsequence would surpass the index we've
provided. Then we simply check if there's an element to the right of
that split. This operation doesn't quite get us the <code>O(1)</code>
time complexity we know and love from traditional arrays, but for an
immutable, general data structure which we could build ourselves without
ANY special compiler support, getting logarithmic performance isn't too
bad. In fact the actual performance is <code>O(log(min(i,n-i)))</code>
where <code>i</code> is the index we wish to access and <code>n</code>
is the length of the sequence. If we're often accessing the first or
last elements then we're down to pretty much constant time!</p>
<p>There we go! We've used 'Sum' as a measure within a finger tree to
get efficient indexing into a sequence! We can also notice that the
length of the whole sequence is computed in <code>O(1)</code> if we use
<code>length = measure</code>; and that we can concat two sequences
relatively efficiently using <code>(&gt;&lt;)</code>; listed in
<code>Data.FingerTree</code> as time complexity
<code>O(log(min(n1, n2)))</code> where n1 and n2 are the length of each
sequence respectively.</p>
<p><code>Sum</code> is probably the simplest monoid we can use; take a
minute to think about how other monoids you know of might behave; the
majority of monoids will create SOME sort of useful structure when used
with a Finger Tree!</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Postman API Explorer: You&#39;ve got mail!</title>
      <link href="https://chrispenner.ca/posts/postman"/>
      <id>https://chrispenner.ca/posts/postman</id>
      <updated>2018-06-03T00:00:00Z</updated>
      <summary>A guide to using Postman for API exploration and testing</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/postman/mail.jpg" alt="Postman API Explorer: You&#39;ve got mail!">
              <p>For those who haven't heard of it, postman is a tool for interacting
with and exploring API's. Effectively it's a pretty UI on top of curl;
but it makes a big difference when figuring out how exactly to structure
an API call, or testing what the response from an api might look
like.</p>
<p>Let's get started, first go ahead and <a
href="https://www.getpostman.com/">GET POSTMAN</a>;</p>
<p>Here's roughly what you'll see when you start it up:</p>
<p><img src="/images/postman/overview.png" alt="Overview" /></p>
<h1 id="requests">Requests</h1>
<p>Let's walk through the Request interface (in order of importance,
stop when you get bored)</p>
<p><img src="/images/postman/request.png" alt="Requests" /></p>
<ol>
<li>URL
<ul>
<li>This bit's pretty important, put a URL in here, click the SEND
button. Now you can use Postman.</li>
</ul></li>
<li>HTTP VERB
<ul>
<li>Here you can choose what type of request to make; GET, POST, PATCH,
DELETE, etc.</li>
<li>This choice effects which other options are available; for instance
you can't set a BODY on a GET request.</li>
</ul></li>
<li>SEND
<ul>
<li>Hit this button to make the magic happen and actually send off your
request.</li>
</ul></li>
<li>Params
<ul>
<li>This gives you a nice interface for editing GET parameters as keys
and values. Don't get it confused with the idea of sending keys and
values with a POST request.</li>
</ul></li>
<li>Body
<ul>
<li>Only available on non-GET requests</li>
<li>Can choose your body type and it'll encode it for you</li>
<li>Use 'raw' and use the dropdown on the right to set the content-type
to JSON for most APIs</li>
<li>Use form-data if you're simulating an old-school form submission or
some older-style APIs</li>
</ul></li>
<li>Headers
<ul>
<li>Set any HTTP headers you need here;</li>
<li>Typically just used for Authentication headers; You can put a jwt
auth header in here for instance.</li>
</ul></li>
<li>Authorization
<ul>
<li>Sometimes helpful for interacting with 3rd party APIs</li>
<li>Choosing Basic Auth will encode a username and password into the
request for you.</li>
</ul></li>
</ol>
<h1 id="responses">Responses</h1>
<p><img src="/images/postman/response.png" alt="Responses" /></p>
<p>Cool stuff; we can set up our request. Now let's say we hit the big
blue SEND button and we have a response!</p>
<ol>
<li>Body
<ul>
<li>We're probably most interested in the Body of the response</li>
</ul></li>
<li>Headers
<ul>
<li>If you want to check the headers of the response this's where you'll
find'em</li>
</ul></li>
<li>Response Type
<ul>
<li>Postman can pretty print the response if we tell it to; set this to
JSON and it'll nicely format the response for you.</li>
</ul></li>
<li>Utilities
<ul>
<li>First one is "Copy to Clipboard"; handy for sharing with your
helpful co-workers</li>
<li>Second opens a search in the response</li>
<li>Third let's you save it for later</li>
</ul></li>
<li>Stats
<ul>
<li>Here we can see Response Time, Status Code and response size.</li>
</ul></li>
</ol>
<p>So that's pretty much it for making simple requests, but I've missed
a few of the more useful things about postman; you can save collections
of requests to share with people; and also save lists of environment
variables which can be interpolated into requests.</p>
<h2 id="history">History</h2>
<p><img src="/images/postman/history.png" alt="History" /></p>
<p>You can see your request history via the tab at the top and load up
any past requests, which is handy if you've edited a request and want to
get back to a previous version of it; or you're like me and you can't
remember anything that happened more than 15 minutes ago.</p>
<h2 id="collections">Collections</h2>
<p><img src="/images/postman/collections.png" alt="Collections" /></p>
<p>This panel on the left will probably have nothing in it when you
start. At any time you can hit the 'save' button to the right of the URL
bar to save a request for later.</p>
<p>I keep collections of requests around when I'm testing, and I often
make collections to share with my team.</p>
<h1 id="environments">Environments</h1>
<p><img src="/images/postman/environments.png" alt="Environments" /></p>
<p>Here we can set a context to execute our requests in. An environment
can contain a set of key-value settings which we can use anywhere in our
request. This is great if you're testing api's as different users, or if
you have to test the same calls against several different hosts.</p>
<p>If you set up some environment variables you can interpolate them
into your requests using double curly braces. For example you might make
a request to
<code>example.com/my-endpoint?apiKey={{apiKey}}&amp;apiUser={{apiUser}}</code>,
now if you have postman environments set up for each user and key you
can switch between them easily. You can use <code>{{}}</code> anywhere
it would make sense; e.g. urls, params, POST bodies, etc.</p>
<h1 id="need-a-session-with-the-site-use-interceptor">Need a session
with the site? Use Interceptor</h1>
<p>Interceptor is one of Postman's cooler features; it allows the
Postman app to route the requests through your chrome instance; this
means they'll include any cookies (and therefore sessions) you have in
chrome.</p>
<p><img src="/images/postman/interceptor.png" alt="Interceptor" /></p>
<p>NOTE! Interceptor is currently only available in the chrome Postman
plugin, NOT the desktop app; so if you don't see this icon, you're
probably using the desktop app and will need to switch over to <a
href="https://chrome.google.com/webstore/detail/postman/fhbjgbiflinjbdggehcddcbncdddomop">Postman
chrome app</a> to use it. You'll also need to install the <a
href="https://chrome.google.com/webstore/detail/postman-interceptor/aicmkgpgakddgnaphhhpliifpcfhicfo?hl=en">Postman
Interceptor Chrome Extension</a>.</p>
<p>Now if we click to enable the chrome interceptor plugin, all our
requests will pick up any cookies that exist in our chrome session!
Handy! You can also flip a switch in the browser extension and have it
track requests happening in your browser through Postman's history.</p>
<h1 id="importingexporting">Importing/Exporting</h1>
<p>Postman has the ability to import curl requests using the "import"
button on the top left, but you can also export code for each request in
a language of your choice using the "code" button on the right. You can
export as Python, HTTP, curl, Go, Java, Node, etc.</p>
<p>That's pretty much it for Postman. Tip your
<em><em>servers</em></em>, I'm here all week.</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANkAAAAzCAYAAAAaYa2SAAAABGdBTUEAALGPC/xhBQAAC8VJREFUeAHtXQmwFMUZ/npmFpHzcQgBRSFcAnIfcimICEFEEFAEj5SlUMYkVTEKJpgQSSmSUGWMFimJUEQTFa8UEdAkGENEi0MBBQQMgiCX3Icc8t7MdP6/Z2d2dt/bdd/bHdis/Vc9tqePv3u+7r//ayzF2XvHSmjSCGgEIkPAiIyzZqwR0AgoBLSQ6YOgEYgYAS1kEQOs2WsEtJDpM6ARiBgBLWQRA6zZawS0kOkzoBGIGAEtZBEDrNlrBLSQ6TOgEYgYAS1kEQOs2WsEtJDpM6ARiBgBLWQRA6zZawS0kOkzoBGIGAEtZBEDrNlrBLSQ6TOgEYgYAS1kEQOs2WsErFwhKFlxKmAx+eIYHr60WvAcFBo3hXn1UBjtOgIlDYCyMsj9e+CuWwX3vbfpuTToqgsagWJDIGchs90EJE6iGJTMEeNgDL0JwjSDOlwIiDp1YbRuDzlkJOy5v4PctiXRrksagSJCIFJz0Rw/Eeb1Y5MFLAU8UVIf1k+mQbRql9KiHzUCxYFAZEImuvYmE3FIVigJKwbrnvuBC6pn1f+cd2rYGIK0LupfRCpYZJ6e3kU0awHRvFXhvk/mN/j/bi1A/HM2F9PtiDXilnRNFdaLuvVgkFC6S9+osD1TpfXwLBiXNE/qItnPO3yQ/L6VcP6xEDj7NdCoCapNfyqpX/jBWbEMzvOzvSrDhDl8LIxBwyGqk30bJ3nkEJxFL8Nducyv8n7rNYQ1YSJE+84QNJZJSgm5/b9wXpwDuXeX14/+Da9XOg7KptwNnE74tubNd8EcdH3Q3573JNwP36/c+oPRyQVz+M0wb/D2Rp46ibKfTQRsO7lTypPxvdGwRo5PqpUuOQeHDsD9dAOcxa8CJ44F7enmEC1aIzZlRtAvXaH0wbtgXDWk/JyEFY4egvv5VjhLaM79exMsqoi/vfAFuHw+4mQMHQVr1G3qqfQ+won2MFeKRpNRoEM0aVbptRldrqz0mPAA3nh5aD/kscMQsWoQ37kY5rAxsO68L9xNlaVjQ5Lghf9gl3n9DAPWA9M9U5cETLou5NdnVJuoT8L0/R/CuGZYwFM0vRSxaU/AuKKbEjB58ivI40dJ6QkYLdvC+vlvINp1CvqHC+yrGh27h6vKPSc1xh8yrr+iAfE6o8/AoFXUrAWjU8/gOZsCC6b86jhpdAOCLi2ThCE25TGgRs1geK5zBIziBcaS9xW0D4KsCrNnf8Qeehxo0Ej1yAV/ky4Q0AUfJUWiyfhwV4WqOi6Y6/gxlP3yR94jbUaMNBxrIdG5F2Amv6q77O9wXnsuGBouGAOHwfhuW1XlrF5OmuiPKgIqOnSBNfEBJcDm6DvgkuYDCZ85YZKah7WS86enPa1Do8XlHWFNehDiwhqk5Sah7Nc/TYqk8mEVtSkA1KUX3FXvqvlEk0sgLmoMeYLaKDiUjjKtP90YNnkFHUx1Ga1fo+Y1+lwDd+2KdEPK1duzZ0CSJgGt27r1Hhjdeiueis+/FiuzOt0ccuc2lE4mrR2n2CO/Bws6ayb7DzP9aoAEOUz2nFnenHRxmjfeCnPwCIWp2W8QnDcWVBl/noPPhzn6djjznw5PmddyJJqMfawqkZUsCFXi4Q86fAA4c1o9STYrSHNlSyaZiEwsBM5fnvFMTdZmG9YqYZBnTkHu3K6EQVzWUmkr7u+u+k8gYGr8lg1w6eAx8Q2cqrHUYeW29l0AOkCqX1yryR10kPNMLAhMPK+zOi7U7UnD1imp/EyMTchk5ouBKeMchCFOnkj8+aYY7024Pt1qyAVwN65NtNaohZzw/3KP4mX2uhoifqkmmOevlMdTnViUPHIw8VCZEvk7ORFpDPOm28npoeBD2ysg6jWA8qFenV+OrdGha7nD5S57C3LPFxTgaKj6q7RCSg7PeWkunBfmBPyM3gODsty8Pij7BZcEzfeBRFMyoUNaw6WbnQ8J+6NsTsr1H5L51kMNdT9ZF5R9XuHftOsnH7BCoqASax0md80KyI3rlKksuP7KAeQL/63CYWkra9WB2XdQ0Cz37laBnrzO4XOnfQULFGl5k9JBPrmbPkpySyqN/56dEHQBG517whx3N+yZD/ms8/objZDt2Ab2S0St2pVaLB+sXEipfsq7hYk3Ihx08NuUv5Zi1soNayApAMG+FJPyPfwB/i87/GGKCyRXVdQ/qS7UV7Ggm9wlwTKvuk5ttLPtU4gWbSBLz1JAYWN4lnLltOtPI2QGRXtZoDgYo8xD1go8N/k3Jvlp2QqZdS8dRNY8fDGQ78okSSNwIMjo1icvc6S+bOzHv0itgrP8n5CfkJBRoMKnJKzjlUl1KfgLCNivP48YuQHGpS1g9Bvss8rrbyRCRkY/nHeWwCL7OVuSFHRwSJPkQuzHsM/AxBqCE+Fm/8EUkOiKsqk/SGLNX5s47y1NqpO7d3qmYbxW1KWvU1KJ0wwc5fKDJOyQx4lzfqmxKNZSPinn3X+I/7off+AJGWkwuXWTOris/VBK0dEMlHb9acYYfT1Tkc0yX/uKmGfWKz/wslZkAn+WZnSoujq9P5t9ZDK7FL2VW9ZDRW/pYsjbHKHpuOiy6Ux4GG06qBbPT37W65Uj/jj4Jdy3F4EDIOaN4+C+m3wmvEly+zcaIaM1cSje7dQdRvPWWa3QWfiiCgln1TldJ44YfrFdtfKv4M+5rr0Bgj7lEi0vp2DCsWAkm7Ry08fBc7ggj1J0kkxN0aa9MlNw+mTQbI65kw7TIDIrd8JZMA9yXyI0L9ifigcw/AFhP6wijSopBM6RS0Hml+/PuOT7fRNlWn+5sQ0bBcl+DrRYoyaU68IRQScLIbOfnO4FIVI55HGOVNbOK/PVnNb9jyhB40CRU7c+cPxIzvjzXM5bf6WLZ4A6J0afAanT5/zs6fuc2VTAgG56e/ZMuN/wuRSbLzZFiPwAQQWcqlZFiWOO7iUoVcckWlJLzr/fVFVsfqokOQkcKChjdO+rtACH3dlcYwGTu3ZAaR4awSaZ0f86UqOeuSlIOxkDhipebFJx4KQcUY7KF3b/pnY3rinXLZcKk/xGNoE5FWGTP2k/Nzv4C9beo596x6rOcy7m4Pwkk6h2AVkpt6hyzvgzF9LCzut/VvwEf3CQZ4pMk6l1kmliP/ErsnWvhUl5pXDujM1DdlSdJa9lZ6Zk8+J1SxB7nIISdKDCZppLWk1u3wrQbesTJ5nDuS6ul+QH2U89CvedN+H26O/Z6RSQqDbjGUj6qNk3r7iv89KzKnzPZXvBXMQmP0rh6NqwbpsEOeYOleD1fVJOjNucBkgT4XTXf5AISuz6HDh2BKDkaibKtP7UcXxLM3EgR32QHerAkVKDLiM/Z1aZcH6IjdIEUc8hP9usLjRer9K8ZOaBLq9c8ed1c7LfpY8h+HvafFO0QqZW78JdvlT9KWeZv8K3SyHpawH1FUYe30h9aUF+ERPnrEBhfJdMQmfxK4RicsBCBTeEmTS7pASrIhIGe9ZUstHHk2YarHIyvoBxOoC/EpAfrU6MpTrOgXHeSHSkhDRpQCaVj9q62ROwA/sS/VNKbB5yX16/DIeoU/qFHzOuP9RRkB/DeSsmd+3KUItX5OCBMldpzSrXFYp+luucpuJczOFP7Sxa4F0KhJU1cgI4h8ZffuSCf8D75XkQU3+r9sGvy8evyPV/nVTr/cTnQFOaxTCtov/UJR8rPZ882PQsqQdJjj7o64OMRBE39gXZvJT7KA/jB0gyDtKNeUOgAPGPXpPlDb3zyIiDJNnm/jhpvW/3eVzst3zqAsQ/usDHt3yv9etrBHwEtJD5SOhfjUBECORsLp7sVzOipWm2GoHiQEBrsuLYR/0WBYyAFrIC3hy9tOJAQAtZceyjfosCRkALWQFvjl5acSCghaw49lG/RQEjoIWsgDdHL604ENBCVhz7qN+igBHQQlbAm6OXVhwIaCErjn3Ub1HACGghK+DN0UsrDgS0kBXHPuq3KGAEtJAV8ObopRUHAlrIimMf9VsUMAJayAp4c/TSigMBLWTFsY/6LQoYgf8BIVTf3IgGuLEAAAAASUVORK5CYII=" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Query a Google Sheets Spreadsheet from BigQuery</title>
      <link href="https://chrispenner.ca/posts/bigquery-sheets"/>
      <id>https://chrispenner.ca/posts/bigquery-sheets</id>
      <updated>2018-06-02T00:00:00Z</updated>
      <summary>A guide to using a google sheets spreadsheet as a BigQuery datasource</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/postman/mail.jpg" alt="Query a Google Sheets Spreadsheet from BigQuery">
              <p>In line with google's goal to have the whole world running inside a
google-doc by 2050 they've added a new feature to Big Query which allows
you query directly from a Google Spreadsheet! That's right, it reads
directly from the sheet so you don't need to worry about keeping your
bigquery tables up to date.</p>
<p>First I want to stress that we should AVOID USING GOOGLE SHEETS AS A
PRIMARY DATASTORE whenever possible, but sometimes you've just got a
bunch of data that you'd like to run some queries on; this was the case
for me earlier; and this is a great solution for how to do that.</p>
<h2 id="prepping-the-sheet">Prepping The Sheet</h2>
<p>BQ has a few quirks, it can (currently) ONLY query the FIRST SHEET of
a google sheet, and doesn't do any special handling of the header row of
your spreadsheet. There's a trick you can do to mitigate this though.
Either make a new sheet as the first sheet and read from the 'real'
sheet and drop the headers. If your other sheet is named MYDATA then you
could use something like
<code>=FILTER(MYDATA!A2:A, NOT(ISBLANK(MYDATA!A2:A)))</code> which
imports every non-blank row from the MYDATA sheet after dropping the
first row.</p>
<p>If you don't want to edit a sheet directly, you can make a new google
sheet and use the <a
href="https://support.google.com/docs/answer/3093340">IMPORTRANGE</a>
command to import the data from a different spreadsheet.</p>
<h2 id="creating-a-dataset">Creating a Dataset</h2>
<p>First step is to create a new bigquery dataset; go to bigquery,
select your google cloud project on the left (or create one if you need
to); then create a new 'dataset' in that project we'll set up to sync
with our spreadsheet.</p>
<p><img src="/images/bigquery-sheets/new_table_screen.png"
alt="BQ UI" /></p>
<p>Now we'll see this screen:</p>
<p><img src="/images/bigquery-sheets/new_bq_table.png"
alt="Create BQ Table" /></p>
<ol>
<li>Choose 'Google Drive' as your Location</li>
<li>Paste the url of your spreadsheet in the box (just copy it from the
url bar when you're at the spreadsheet)</li>
<li>Set File Format to Google Sheets</li>
<li>Add a table name like you normally would</li>
</ol>
<h2 id="schema">Schema</h2>
<p>In regards to adding a schema, BigQuery does NOT infer this for you,
so you'll have to add one yourself. Each field of the schema corresponds
to a column of the spreadsheet. For small spreadsheets you can enter it
by hand, for bigger spreadsheets you can just generate a schema
definition by copying the headers row from your spreadsheet and running
it through this script: <a
href="https://gist.github.com/ChrisPenner/2525b29f49cdb6613175cda8c85cb585">HERE</a>,
then click 'Edit as Text' by the schema definiton and paste in the
result</p>
<p>Lastly, hit 'Create Table'</p>
<h2 id="querying">Querying</h2>
<p>You're good to go now, query away! Note that you won't have the
'Preview' button like other data tables, this is because no data is
actually located in BQ, it streams data from sheets whenever you make a
query. This means the data will always be kept up to date!</p>
<h2 id="breaking-changes">Breaking Changes</h2>
<p>BQ queries the spreadsheet directly so the data will always be up to
date, but this also means that if someone shuffles around columns that
the schema will be out of date with the data. Just note that if the
column ordering changes you'll have to update your schema to match.</p>
<p>Hope that helps, cheers!</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>ASTs with Fix and Free</title>
      <link href="https://chrispenner.ca/posts/asts-with-fix-and-free"/>
      <id>https://chrispenner.ca/posts/asts-with-fix-and-free</id>
      <updated>2018-02-24T00:00:00Z</updated>
      <summary>Using Fix and Free datatypes to represent compiler ASTs</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/tree.jpg" alt="ASTs with Fix and Free">
              <p>I've been working on a <a
href="https://github.com/ChrisPenner/Candor">toy compiler</a> lately so
I've been thinking about <a
href="https://en.wikipedia.org/wiki/Abstract_syntax_tree">ASTs</a>! It's
a new thing for me and I've gotten a bit obsessed with the idea of
simplifying both the representation of the tree itself as well as the
code to interpret it.</p>
<p>ASTs are (typically) <strong>recursive</strong> data-types; this
means that within the data-type they have an embedded instance of the
same type! The simplest version of a recursive tree we can look at is
actually a simple list! A list is a recursive (degenerate) tree where
every node has 0 or 1 branches. Here's how the definition of a simple
List AST might look 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">data</span> <span class="dt">List</span> a <span class="ot">=</span> <span class="dt">Cons</span> a (<span class="dt">List</span> a) <span class="op">|</span> <span class="dt">End</span></span></code></pre></div>
<p>Contrary to what your kindergarten teacher taught you, this is one
case where it's okay to use the term in its own definition!</p>
<p>A slightly more complex AST for a toy calculator program might look
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="kw">data</span> <span class="dt">Op</span> <span class="ot">=</span> <span class="dt">Add</span> <span class="op">|</span> <span class="dt">Mult</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">AST</span> <span class="ot">=</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>  <span class="dt">BinOp</span> <span class="dt">Op</span> <span class="dt">AST</span> <span class="dt">AST</span> </span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">Num</span> <span class="dt">Int</span></span></code></pre></div>
<p>In this case we've defined a recursive tree of math operations where
you can add or multiply numbers together. Here's how we'd represent this
simple math expression <code>(1 + 2) * 3</code>:</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">simpleExpr ::</span> <span class="dt">AST</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>simpleExpr <span class="ot">=</span> <span class="dt">BinOp</span> <span class="dt">Mult</span> (<span class="dt">BinOp</span> <span class="dt">Add</span> (<span class="dt">Num</span> <span class="dv">1</span>) (<span class="dt">Num</span> <span class="dv">2</span>)) (<span class="dt">Num</span> <span class="dv">3</span>)</span></code></pre></div>
<p>Maybe not the easiest for a human to read, but it's easy for the
computer to figure out! We won't bother writing a parser in this post,
instead we'll look at other possible ways we can represent these ASTs
with data structures that give us tools to work with them.</p>
<h2 id="recursion-schemes">Recursion Schemes</h2>
<p>Recursion schemes are a pretty complex subject peppered with <a
href="https://www.reddit.com/r/programming/comments/6ml1y/a_pretty_useful_haskell_snippet/c04ako5/">zygohistomorphic
prepromorphisms</a> and things; but don't fret, we won't go too deep
into the topic, instead we'll just touch on how we can use the general
recursion folding function <code>cata</code> to interpret generic ASTs
in a really clean fashion!</p>
<p>The core notion of the <a
href="https://hackage.haskell.org/package/recursion-schemes">recursion-schemes
library</a> is to factor out the recursion from data-types so that the
library can handle any complicated recursive cases and make it easy for
you to express how the recursion should behave.</p>
<p>There's a bit of a catch though, we don't get all that for free, we
first need to refactor our data-type to <strong>factor out the
recursion</strong>. What's that mean? Well basically we need to make our
<strong>concrete</strong> data-type into a <strong>Functor</strong> over
its recursive bits. It's easier to understand with a concrete example;
let's start with our <code>List</code> example from earlier:</p>
<div class="sourceCode" id="cb4"><pre
class="sourceCode diff"><code class="sourceCode diff"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="st">- data List a    = Cons a (List a) | End</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="va">+ data ListF a r = Cons a r        | End</span></span></code></pre></div>
<p>See the difference? We've replaced any of slots where the type
<strong>recursed</strong> with a new type parameter <code>r</code> (for
<code>*r*ecursion</code>). We've also renamed our new type to
<code>ListF</code> as is the convention with recursion schemes. The
<code>F</code> stands for <code>Functor</code>, representing that this
is the version of our data-type with a Functor over the recursive
bits.</p>
<p>How's our AST look if we do the same thing? Let's take a look:</p>
<div class="sourceCode" id="cb5"><pre
class="sourceCode diff"><code class="sourceCode diff"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>data Op = Add | Mult</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="st">- data AST =</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="st">-   BinOp Op AST AST </span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="st">-   | Num Int</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="va">+ data ASTF r =</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a><span class="va">+   BinOpF Op r r </span></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a><span class="va">+   | NumF Int</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>    deriving (Show, Functor)</span></code></pre></div>
<p>Pretty similar overall! Let's move on to representing some
calculations with our new type!</p>
<h2 id="avoiding-infinity-using-fix">Avoiding Infinity using Fix</h2>
<p>If you're a bit of a keener you may have already tried re-writing our
previous math formula using our new AST type, and if so probably ran
into a bit of a problem! Let's give it a try together using the same
math problem <code>(1 + 2) * 3</code>:</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">simpleExpr ::</span> <span class="op">?</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>simpleExpr <span class="ot">=</span> <span class="dt">BinOpF</span> <span class="dt">Mult</span> (<span class="dt">BinOpF</span> <span class="dt">Add</span> (<span class="dt">Num</span> <span class="dv">1</span>) (<span class="dt">Num</span> <span class="dv">2</span>)) (<span class="dt">Num</span> <span class="dv">3</span>)</span></code></pre></div>
<p>We can write the expression out without too much trouble, but what
type is it?</p>
<p>The type of the outer layer is <code>ASTF r</code> where
<code>_</code> represents the recursive portion of the AST; if we fill
it in we get <code>ASTF (ASTF r)</code>, but the <code>r</code> ALSO
represents <code>ASTF r</code>; if we try to keep writing this in we end
up with: <code>ASTF (ASTF (ASTF (ASTF (ASTF (ASTF ...)))))</code> which
repeats ad nauseum.</p>
<p>We really need some way to tell GHC that the type parameter
represents infinite recursion! Luckily we have that available to us in
the form of the <code>Fix</code> newtype!</p>
<p>We'll start out with the short but confusing definition of
<code>Fix</code> lifted straight from the <a
href="https://hackage.haskell.org/package/recursion-schemes-5.0.2/docs/Data-Functor-Foldable.html#t:Fix">recursion-schemes</a>
library</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="kw">newtype</span> <span class="dt">Fix</span> f <span class="ot">=</span> <span class="dt">Fix</span> (f (<span class="dt">Fix</span> f))</span></code></pre></div>
<p>Short and sweet, but confusing as all hell. What's going on? Well
basically we're just 'cheating' the type system by deferring the
definition of our type signature into a lazily evaluated recursive type.
We do this by inserting a new layer of the <code>Fix</code> data-type in
between each layer of recursion, this satisfies the typechecker and
saves us from manually writing out an infinite type. There are <a
href="https://stackoverflow.com/a/45916939/3907685">better
explanations</a> of <code>Fix</code> out there, so if you're really set
on understanding it I encourage you to go dig in! That said, we really
don't need to fully understand how it works in order to use it here, so
we're going to move on to the fun part.</p>
<p>Here's our expression written out using the <code>Fix</code> type,
notice how we have a <code>Fix</code> wrapper in between each layer of
our recursive type:</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">simpleExprFix ::</span> <span class="dt">Fix</span> <span class="dt">ASTF</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>simpleExprFix <span class="ot">=</span> <span class="dt">Fix</span> (<span class="dt">BinOpF</span> <span class="dt">Mult</span> (<span class="dt">Fix</span> (<span class="dt">BinOpF</span> <span class="dt">Add</span> (<span class="dt">Fix</span> (<span class="dt">Num</span> <span class="dv">1</span>)) (<span class="dt">Fix</span> (<span class="dt">Num</span> <span class="dv">2</span>)))) (<span class="dt">Fix</span> (<span class="dt">Num</span> <span class="dv">3</span>)))</span></code></pre></div>
<p>At this point it probably just seems like we've made this whole thing
a lot more complicated, but hold in there! Now that we've factored out
the recursion and are able to represent our trees using <code>Fix</code>
we can finally reap the benefits that <code>recursion-schemes</code> can
provide!</p>
<h2 id="using-cata">Using <code>cata</code></h2>
<p>The recursion-schemes library provides combinators and tools for
working with recursive datatypes like the <code>ASTF</code> type we've
just defined. Usually we need to tell the library about how to convert
between our original recursive type (<code>AST</code>) and the version
with recursion factored out (<code>ASTF</code>) by implementing a few
typeclasses, namely the <code>Recursive</code> type and the
<code>Base</code> type family; but as it turns out any
<code>Functor</code> wrapped in <code>Fix</code> gets an implementation
of these typeclasses for free! That means we can go ahead and use the
<code>recursion-schemes</code> tools right away!</p>
<p>There are all sorts of functions in <code>recursion-schemes</code>,
but the one we'll be primarily looking at is the <code>cata</code>
combinator (short for <code>catamorphism</code>). It's a cryptic name,
but basically its a fold function which lets us collapse our recursive
data-types down to a single value using simple functions.</p>
<p>Here's how we can use it:</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">interpret ::</span> <span class="dt">Fix</span> <span class="dt">ASTF</span> <span class="ot">-&gt;</span> <span class="dt">Int</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>interpret <span class="ot">=</span> cata algebra</span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a><span class="ot">    algebra ::</span> <span class="dt">ASTF</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Int</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>    algebra (<span class="dt">Num</span> n) <span class="ot">=</span> n</span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a>    algebra (<span class="dt">BinOpF</span> <span class="dt">Add</span> a b) <span class="ot">=</span> a <span class="op">+</span> b</span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a>    algebra (<span class="dt">BinOpF</span> <span class="dt">Mult</span> a b) <span class="ot">=</span> a <span class="op">*</span> b</span></code></pre></div>
<p>Okay so what's this magic? Basically <code>cata</code> knows how to
traverse through a datatype wrapped in <code>Fix</code> and "unfix" it
by running a function on each level of the recursive structure! All we
need to do is give it an <code>algebra</code> (a function matching the
general type <code>Functor f =&gt; f a -&gt; a</code>).</p>
<p>Notice how we never need to worry about evaluating the subtrees in
our AST? <code>cata</code> will automatically dive down to the bottom of
the tree and evaluate it from the bottom up, replacing the recursive
portions of each level with the <strong>result</strong> of evaluating
each subtree. It was a lot of setup to get here, but the simplicity of
our algebra makes it worth it!</p>
<h2 id="using-free-in-place-of-fix">Using Free in place of Fix</h2>
<p>Using <code>Fix</code> and <code>recursion-schemes</code> is one way
to represent our AST, but there's another that I'd like to dig into:
Free Monads!</p>
<p>Free monads are often used to represent DSLs or to represent a set of
commands which we plan to interpret or run <strong>later on</strong>. I
see a few parallels to an AST in there! While not inherently related to
recursion we can pretty easily leverage Free to represent recursion in
our AST. I won't be going into much detail about how Free works, so you
may want to read up on that first before preceeding if it's new to
you.</p>
<p>Let's start by defining a new version of our AST type:</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">data</span> <span class="dt">Op</span> <span class="ot">=</span> <span class="dt">Add</span> <span class="op">|</span> <span class="dt">Mult</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">deriving</span> <span class="dt">Show</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="kw">data</span> <span class="dt">ASTFree</span> a <span class="ot">=</span></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>  <span class="dt">BinOpFree</span> <span class="dt">Op</span> a a</span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Functor</span>)</span></code></pre></div>
<p>Notice that in this case we've removed our <code>Num Int</code>
branch, that means that the base <code>ASTFree</code> type would recurse
forever if we wrapped it in <code>Fix</code>, but as it happens
<code>Free</code> provides a termination branch via <code>Pure</code>
that we can use as a replacement for <code>Num Int</code> as our
Functor's fixed point (i.e. termination point).</p>
<p>Here's our original expression written using Free:</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">simpleExprFree ::</span> <span class="dt">Free</span> <span class="dt">ASTFree</span> <span class="dt">Int</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>simpleExprFree <span class="ot">=</span> <span class="dt">Free</span> (<span class="dt">BinOpFree</span> <span class="dt">Mult</span> (<span class="dt">Free</span> (<span class="dt">BinOpFree</span> <span class="dt">Add</span> (<span class="dt">Pure</span> <span class="dv">1</span>) (<span class="dt">Pure</span> <span class="dv">2</span>))) (<span class="dt">Pure</span> <span class="dv">3</span>))</span></code></pre></div>
<p>Notice how in this case we've also extracted the type of our terminal
expression (<code>Int</code>) into the outer type rather than embedding
it in the <code>AST</code> type. This means we can now easily write
expressions over Strings, or Floats or whatever you like, we'll just
have to make sure that our interpreter can handle it.</p>
<p>Speaking of the interpreter, we can leverage <code>iter</code> from
<code>Control.Monad.Free</code> to fill the role that <code>cata</code>
did with our <code>Fix</code> datatype:</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">interpFree ::</span> <span class="dt">Free</span> <span class="dt">ASTFree</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Int</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>interpFree <span class="ot">=</span> iter alg</span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>    alg (<span class="dt">BinOpFree</span> <span class="dt">Add</span> a b) <span class="ot">=</span> a <span class="op">+</span> b</span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a>    alg (<span class="dt">BinOpFree</span> <span class="dt">Mult</span> a b) <span class="ot">=</span> a <span class="op">*</span> b</span></code></pre></div>
<p>Not so tough! This may be a bit of an abuse of the Free Monad, but it
works pretty well! Try it out:</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> interpFree simpleExprFree</span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="dv">9</span></span></code></pre></div>
<p>You can of course employ these techniques with more complex ASTs and
transformations!</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>MonadIO Considered Harmful</title>
      <link href="https://chrispenner.ca/posts/monadio-considered-harmful"/>
      <id>https://chrispenner.ca/posts/monadio-considered-harmful</id>
      <updated>2017-09-11T00:00:00Z</updated>
      <summary>Avoid using IO or MonadIO directly</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/cables.jpg" alt="MonadIO Considered Harmful">
              <p>Now that we've got the click-bait out of the way (sorry about that)
we can have a nice chat! Here's my point: MonadIO, and of course IO, are
too general. This isn't news really, it's has been addressed in many
ways by many people. Options presented in the past include using Free or
Free-er monads (e.g. the <a
href="https://leanpub.com/purescript/read#leanpub-auto-the-eff-monad">Eff
Monad</a>), and these tend to work pretty well, but they're
all-encompassing and intrusive, they can be pretty tough to work into
legacy projects; converting all uses of a given effect into a Free monad
can be tricky and time consuming (though certainly can be
worthwhile!).</p>
<p>What I'm going to talk about here is an alternative which provides
most of the benefits with a very low barrier to entry: splitting up IO
into granular monad type classes. First a quick recap:</p>
<h2 id="monad-classes"><code>Monad*</code> classes</h2>
<p>I'm going to assume that most readers are at least passively familiar
with <a href="http://hackage.haskell.org/package/mtl">mtl</a>; if not
then maybe come back to this post later on. <a
href="http://hackage.haskell.org/package/mtl">mtl</a> popularized the
idea of the <code>Monad*</code> typeclasses e.g.
<code>MonadReader</code>, <code>MonadState</code>, and of course
<code>MonadIO</code>. This pattern has been adopted by most modern
monad-based libraries because it allows abstracting away the concrete
monad which is used in a function to allow greater portability and
re-usability.</p>
<p>Here's an example of an action written using type signatures using
both concrete monad types and abstract monad typeclasses:</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">concreteUserIncrement ::</span> <span class="dt">StateT</span> <span class="dt">Int</span> <span class="dt">IO</span> <span class="dt">Int</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>concreteUserIncrement <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>  incAmount <span class="ot">&lt;-</span> liftIO <span class="fu">readLn</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>  modify (<span class="op">+</span>incAmount)</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>  <span class="fu">return</span> incAmount</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="ot">classUserIncrement ::</span> (<span class="dt">MonadState</span> <span class="dt">Int</span> m, <span class="dt">MonadIO</span> m) <span class="ot">=&gt;</span> m <span class="dt">Int</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>classUserIncrement <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>  incAmount <span class="ot">&lt;-</span> liftIO <span class="fu">readLn</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>  modify (<span class="op">+</span>incAmount)</span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>  <span class="fu">return</span> incAmount</span></code></pre></div>
<p>The actions do the same thing, but I'd recommend the class-based
approach for a few reasons.</p>
<p>Firstly, it allows us to re-use this function with other monad
stacks, for instance later on let's say we realize that we'll need to
have access to the options configured for our program in a few spots. To
accomodate this we add <code>ReaderT Options</code> to our stack and end
up with: <code>ReaderT Options (StateT Int IO)</code>. In the first case
we'd need to rewrite all signatures which use the old concrete type and
replace them with the new concrete type. We could use a type alias of
course, but I'm making a point here, so give me a sec. The class-based
signature is already good to go in the new monad since it still unifies
with the given requirements!</p>
<p>A second and perhaps more important benefit to class-based signatures
is that they make it clear which effects a function plans to use. Let's
take a look at another example:</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">concreteReset ::</span> <span class="dt">ReaderT</span> <span class="dt">Options</span> (<span class="dt">StateT</span> <span class="dt">Int</span> <span class="dt">IO</span>) ()</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>concreteReset <span class="ot">=</span> put <span class="dv">0</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="ot">classbasedReset ::</span> <span class="dt">MonadState</span> <span class="dt">Int</span> m <span class="ot">=&gt;</span> m ()</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>classbasedReset <span class="ot">=</span> put <span class="dv">0</span></span></code></pre></div>
<p>Again, both implementations are the same, but what do the types tell
us? Well, the class-based approach tells us clearly that
<code>classbasedReset</code> intends to (and in fact can only) interact
with the Int which we've got stored in <code>StateT</code>. We're not
allowed to do IO or check Options in there without adding it to the
signature. In the concrete case we're not given any hints. We know which
monad the action is intended to be used in; but for all we know the
implementation could take advantage of the <code>IO</code> at the base
and alter the file-system or do logging, or read from stdIn, who
knows?</p>
<p>Okay, so I think I've made my case that <code>Monad*</code> classes
improve both code re-usability and code clarity, but if I'm not supposed
to use <code>IO</code> or even <code>MonadIO</code> then how am I
supposed to get anything done? Good question, glad you asked!</p>
<h2 id="breaking-up-monadio">Breaking up MonadIO</h2>
<p>Having a <code>MonadState Int m</code> in the signature was great
because it limited the scope of what the monad could do, allowing us to
see the action's intent. <code>MonadIO m</code> is a <code>Monad*</code>
class, but what does it tell us? Unfortunately it's so general it tells
us pretty much zilch. It says that we need access to IO, but are we
printing something? Reading from the filesystem? Writing to a database?
Launching nuclear missiles? Who knows!? It's making my head spin!
<code>MonadIO</code> is too general, its only method is
<code>liftIO</code> which has absolutely zero semantic meaning. Compare
this to <code>ask</code> from <code>MonadReader</code> or
<code>modify</code> from <code>MonadState</code>. We can tell that these
transformers have a clear scope because they have meaningful function
names.</p>
<p>Let's bring some semantic meaning into our MonadIO by defining a new,
more meaningful class:</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">MonadFiles</span> m <span class="kw">where</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="ot">  readAFile ::</span> <span class="dt">FilePath</span> <span class="ot">-&gt;</span> m <span class="dt">String</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="ot">  writeAFile ::</span> <span class="dt">FilePath</span> <span class="ot">-&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> m ()</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="kw">instance</span> <span class="dt">MonadFiles</span> <span class="dt">IO</span> <span class="kw">where</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>  readAFile <span class="ot">=</span> <span class="fu">readFile</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>  writeAFile <span class="ot">=</span> <span class="fu">writeFile</span></span></code></pre></div>
<p>Now instead of tossing around a <code>MonadIO</code> everywhere we
can clearly specify that all we really need is to work with the file
system. We've implemented the interface in the IO monad so we can still
use it just like we did before.</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">getDiary ::</span> <span class="dt">MonadFiles</span> m <span class="ot">=&gt;</span> m <span class="dt">String</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>getDiary <span class="ot">=</span> readAFile <span class="st">&quot;my-diary.txt&quot;</span></span></code></pre></div>
<p>Now no-one can launch those pesky nukes when all I want to do is read
my diary! As a bonus this lets us choose a different underlying
<code>MonadFiles</code> whenever we like! For instance we probably don't
need our tests to be writing files all over our system:</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="kw">instance</span> <span class="dt">MonadFiles</span> (<span class="dt">State</span> (<span class="dt">M.Map</span> <span class="dt">String</span> <span class="dt">String</span>)) <span class="kw">where</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>  readAFile fileName <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>    files <span class="ot">&lt;-</span> get</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> contents <span class="ot">=</span> fromMaybe <span class="st">&quot;&quot;</span> (M.lookup fileName files)</span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>    <span class="fu">return</span> contents</span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>  writeAFile fileName contents <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>    modify (M.insert fileName contents)</span></code></pre></div>
<p>Now we can substitute a <code>State (M.Map String String)</code> for
<code>IO</code> in our tests to substitute out the filesystem for a
simple Map. Our actions don't care where they run so long as the
interface has files can be read and written somewhere!</p>
<p>I'd probably go a bit further and split this up even more granularly,
separating reading and writing files.</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="kw">class</span> <span class="dt">MonadFileReader</span> m <span class="kw">where</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="ot">  readAFile ::</span> <span class="dt">FilePath</span> <span class="ot">-&gt;</span> m <span class="dt">String</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">MonadFileWriter</span> m <span class="kw">where</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a><span class="ot">  writeAFile ::</span> <span class="dt">FilePath</span> <span class="ot">-&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> m ()</span></code></pre></div>
<p>We can get back our <code>MonadFiles</code> type class pretty easily
using the <a
href="https://kseo.github.io/posts/2017-01-13-constraint-kinds.html"><code>ConstraintKinds</code></a>
GHC extension:</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">{-# language ConstraintKinds #-}</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">MonadFiles</span> m <span class="ot">=</span> (<span class="dt">MonadFileReader</span> m, <span class="dt">MonadFileWriter</span> m)</span></code></pre></div>
<p>As an aside, feel free to implement an instance of your interfaces
for your Free Algebras too!</p>
<p>Anyways, that's pretty much it, the next time you find yourself using
IO or MonadIO consider breaking it up into smaller chunks; having a
separate <code>MonadDB</code>, <code>MonadFiles</code> and
<code>MonadHttp</code>, will improve your code clarity and
versatility.</p>
<p>Cheers!</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Type Tac Toe: Advanced Type Safety</title>
      <link href="https://chrispenner.ca/posts/type-tac-toe"/>
      <id>https://chrispenner.ca/posts/type-tac-toe</id>
      <updated>2017-08-25T00:00:00Z</updated>
      <summary>Upgrading your type programming game</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/tictactoe.png" alt="Type Tac Toe: Advanced Type Safety">
              <p>Today we'll be looking at type programming in Haskell. Programming in
type-land allows us to teach the compiler a few new tricks and to verify
additional constraints at compile-time rather than run-time. The
canonical example is that you can encode the length of a list as a type
so that you can verify that appending an element to a list of
<code>n</code> elements yields a list of <code>n + 1</code> elements. If
you haven't read about or experimented with an example like that before
I'd say to check out <a
href="http://www.parsonsmatt.org/2017/04/26/basic_type_level_programming_in_haskell.html">Matt
Parson's post on type programming</a> first. We're going to go a step
further and we'll actually encode the rules of a game of Tic Tac Toe
into types so that we can statically guarantee that nobody cheats! If
you're into spoilers you can see the finished code at the <a
href="https://github.com/ChrisPenner/Type-Tac-Toe">git repo
here</a>.</p>
<p>Type programming is a newly popularized idea, so the tools for it are
still a bit rough (in Haskell at least), check out <a
href="https://www.idris-lang.org/">Idris</a> if you'd like to see
something a bit more polished.</p>
<p>There are some libraries popping up in the Haskell ecosystem which
are making the ideas presented here easier to work with, most notably
the <a
href="http://hackage.haskell.org/package/singletons">singletons</a>
library which can generate a lot of the type-level primitives we write
here. Check it out if you like, but I find it's a bit confusing for
people new to this stuff, so I'll be spelling most things out in
long-hand.</p>
<p>Let's get moving!</p>
<p>Here's a representation of the de-facto 3x3 Tic Tac Toe board:</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="co">-- | Either X, O, or Nothing</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">PieceT</span> <span class="ot">=</span> <span class="dt">X</span> <span class="op">|</span> <span class="dt">O</span> <span class="op">|</span> <span class="dt">N</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</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="kw">data</span> <span class="dt">Trip</span> a <span class="ot">=</span> <span class="dt">Trip</span> a a a</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>, <span class="dt">Functor</span>)</span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">Board</span> a <span class="ot">=</span> <span class="dt">Board</span> (<span class="dt">Trip</span> (<span class="dt">Trip</span> a))</span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>, <span class="dt">Functor</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="ot">newBoard ::</span> <span class="dt">Board</span> <span class="dt">PieceT</span></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a>newBoard <span class="ot">=</span> <span class="dt">Board</span> <span class="op">$</span> <span class="dt">Trip</span> (<span class="dt">Trip</span> <span class="dt">N</span> <span class="dt">N</span> <span class="dt">N</span>)</span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a>                        (<span class="dt">Trip</span> <span class="dt">N</span> <span class="dt">N</span> <span class="dt">N</span>)</span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a>                        (<span class="dt">Trip</span> <span class="dt">N</span> <span class="dt">N</span> <span class="dt">N</span>)</span></code></pre></div>
<p>Note that we'll need the <code>{-# language DeriveFunctor #-}</code>
pragma for this.</p>
<p>We'll need a way to refer to individual squares in the grid so our
player can say where they'd like to move. Let's just use simple
<code>(x, y)</code> coordinates. We'll use a custom datatype rather than
<code>Int</code> so that we know the coordinates are in bounds.</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">data</span> <span class="dt">CoordT</span> <span class="ot">=</span> <span class="dt">A</span> <span class="op">|</span> <span class="dt">B</span> <span class="op">|</span> <span class="dt">C</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>)</span></code></pre></div>
<p>Here's a quick function which lets us change a slot inside a
Triple:</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="co">-- | Utility function to alter a value inside a triple</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- Can set values using `const x`</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="ot">overTrip ::</span> <span class="dt">CoordT</span> <span class="ot">-&gt;</span> (a <span class="ot">-&gt;</span> a) <span class="ot">-&gt;</span> <span class="dt">Trip</span> a <span class="ot">-&gt;</span> <span class="dt">Trip</span> a</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>overTrip <span class="dt">A</span> f (<span class="dt">Trip</span> a b c) <span class="ot">=</span> <span class="dt">Trip</span> (f a) b c</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>overTrip <span class="dt">B</span> f (<span class="dt">Trip</span> a b c) <span class="ot">=</span> <span class="dt">Trip</span> a (f b) c</span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>overTrip <span class="dt">C</span> f (<span class="dt">Trip</span> a b c) <span class="ot">=</span> <span class="dt">Trip</span> a b (f c)</span></code></pre></div>
<p>And that gives us everything we need to place pieces on the
board:</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">play ::</span> <span class="dt">PieceT</span> <span class="ot">-&gt;</span> (<span class="dt">CoordT</span>, <span class="dt">CoordT</span>) <span class="ot">-&gt;</span> <span class="dt">Board</span> <span class="dt">PieceT</span> <span class="ot">-&gt;</span> <span class="dt">Board</span> <span class="dt">PieceT</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>play p (x, y) (<span class="dt">Board</span> b) <span class="ot">=</span> <span class="dt">Board</span> <span class="op">$</span> overTrip y (overTrip x (<span class="fu">const</span> p)) b</span></code></pre></div>
<p>Looking good! But wait, there's really no validation going on here!
Players could play on the same square over and over again! Or maybe
player <code>X</code> just keeps on playing without giving
<code>O</code> a turn! We could do error handling at runtime inside the
function, but that would mean throwing runtime exceptions (Yikes!),
running things inside an error monad, or returning an Either. But those
are all boring and involve runtime checks so lets see how types can help
do this work at compile-time!</p>
<h2 id="alternating-turns">Alternating Turns</h2>
<p>To start simple and see if there's a way we could make <code>X</code>
and <code>O</code> alternate turns! In order to do that we're going to
need types which represent <code>X</code> and <code>O</code>!</p>
<p>Here's a first attempt:</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="kw">data</span> <span class="dt">X</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">O</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">N</span></span></code></pre></div>
<p>Now we'd have types for each, but we get a conflict! We have
duplicate definitions of <code>X</code>, <code>O</code> and
<code>N</code> because of <code>PieceT</code>! Let's introduce our next
GHC extension: <code>{-# language DataKinds #-}</code>! DataKinds takes
a bit of fiddling with to understand, don't worry if you have a hard
time understanding where the boundaries are. I still have to shake my
head and think it through most of the time.</p>
<p>DataKinds let's you use constructors from any datatypes (defined with
<code>data</code> or <code>newtype</code>) as types! To reference the
'type' version of a data constructor you prefix it with an apostrophe.
Since we already defined <code>PieceT</code>, by enabling DataKinds we
now have <code>'X</code>, <code>'O</code>, <code>'N</code> in scope at
the type level! Technically you can leave off the <code>'</code> if it's
clear to the compiler that you're referring to a type, but I like to be
explicit about it for readability.</p>
<p>There's one more bonus that DataKinds gives us, it creates a new
<code>Kind</code> for each family of constructors. Kinds are kind of
like types for types, most Haskell types are of Kind <code>*</code>, and
higher order kinds are <code>* -&gt; *</code>, you can check it in
ghci:</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="op">&gt;</span> <span class="op">:</span>k <span class="dt">Int</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Int</span><span class="ot"> ::</span> <span class="op">*</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> <span class="op">:</span>k <span class="dt">Maybe</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Maybe</span><span class="ot"> ::</span> <span class="op">*</span> <span class="ot">-&gt;</span> <span class="op">*</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> <span class="op">:</span>k <span class="dt">Maybe</span> <span class="dt">Int</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a><span class="dt">Maybe</span> <span class="dt">Int</span><span class="ot"> ::</span> <span class="op">*</span></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> <span class="op">:</span>k <span class="dt">&#39;X</span></span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a><span class="dt">&#39;X</span><span class="ot"> ::</span> <span class="dt">PieceT</span></span></code></pre></div>
<p>That last one is interesting! GHC notices that <code>'X</code> isn't
quite like other types, but that it was defined as part of the PieceT
data group. This means that when we're writing functions on types we can
actually specify what Kind of types we want to allow.</p>
<p>The first and easiest thing we could require of our game is that
<code>X</code> and <code>O</code> always alternate turns. In order to
that we'll need to store who's turn it is as part of the type of our
board. Let's edit our <code>Board</code> type to have an additional
parameter called <code>t</code> for <code>turn</code>, we don't actually
have to have the type in our data-structure though, the compiler will do
the check at compile-time so we won't need to store this info at the
value level. A type which is used only on the left side of a data
definition is called a "Phantom type". They're useful for specifying
type constraints.</p>
<p>We'll also edit the signature of <code>newBoard</code> to show that
<code>X</code> goes first; we don't need to change the definition at all
though!</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="kw">newtype</span> <span class="dt">Board</span> t a <span class="ot">=</span> <span class="dt">Board</span> (<span class="dt">Trip</span> (<span class="dt">Trip</span> a))</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>, <span class="dt">Functor</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="co">-- | New empty board</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a><span class="ot">newBoard ::</span> <span class="dt">Board</span> <span class="dt">&#39;X</span> <span class="dt">PieceT</span></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>newBoard <span class="ot">=</span> <span class="co">-- Unchanged</span></span></code></pre></div>
<p>When we do this we'll get a compiler error that GHC was expecting a
type, but we gave it something of Kind <code>PieceT</code>. GHC usually
expects basic types of kind <code>*</code>, so if we do anything fancy
we need to let it know what we're thinking. In this case we can add a
type annotation to the <code>Board</code> type:</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="co">-- Add this new pragma at the top:</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# language KindSignatures #-}</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">Board</span> (<span class="ot">t ::</span> <span class="dt">PieceT</span>) a <span class="ot">=</span> <span class="dt">Board</span> (<span class="dt">Trip</span> (<span class="dt">Trip</span> a))</span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>, <span class="dt">Functor</span>)</span></code></pre></div>
<p>The KindSignatures pragma lets say what 'kind' we want all our types
to be. This makes GHC happy, and helps us too by allowing us to specify
that the 't' parameter should always be one of our pieces rather than
some arbitrary type.</p>
<p>Unfortunately, changing the type of <code>Board</code> has broken our
<code>play</code> function. We need to put something in as a 'turn'
parameter there too. For now it's easiest to split it up into a
<code>playX</code> and <code>playY</code> function which can specify
their types more concretely.</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">playX ::</span> (<span class="dt">CoordT</span>, <span class="dt">CoordT</span>) <span class="ot">-&gt;</span> <span class="dt">Board</span> <span class="dt">&#39;X</span> <span class="dt">PieceT</span> <span class="ot">-&gt;</span> <span class="dt">Board</span> <span class="dt">&#39;O</span> <span class="dt">PieceT</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>playX (x, y) (<span class="dt">Board</span> b) <span class="ot">=</span> <span class="dt">Board</span> <span class="op">$</span> overTrip y (overTrip x (<span class="fu">const</span> <span class="dt">X</span>)) b</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="ot">playO ::</span> (<span class="dt">CoordT</span>, <span class="dt">CoordT</span>) <span class="ot">-&gt;</span> <span class="dt">Board</span> <span class="dt">&#39;O</span> <span class="dt">PieceT</span> <span class="ot">-&gt;</span> <span class="dt">Board</span> <span class="dt">&#39;X</span> <span class="dt">PieceT</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>playO (x, y) (<span class="dt">Board</span> b) <span class="ot">=</span> <span class="dt">Board</span> <span class="op">$</span> overTrip y (overTrip x (<span class="fu">const</span> <span class="dt">O</span>)) b</span></code></pre></div>
<p>Don't worry about the duplication, we'll clean that up later. Now you
can only <code>playX</code> on a board when it's X's turn! Huzzah! If
you try it the wrong way around GHC will complain:</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="op">&gt;</span> playO (<span class="dt">A</span>, <span class="dt">B</span>) newBoard</span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="fu">error</span><span class="op">:</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>    • <span class="dt">Couldn&#39;t</span> match <span class="kw">type</span> ‘<span class="dt">&#39;X</span>’ with ‘<span class="dt">&#39;O</span>’</span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Expected</span> <span class="kw">type</span><span class="op">:</span> <span class="dt">Board</span> <span class="dt">&#39;O</span> <span class="dt">PieceT</span></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Actual</span> <span class="kw">type</span><span class="op">:</span> <span class="dt">Board</span> <span class="dt">&#39;X</span> <span class="dt">PieceT</span></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a>    • <span class="dt">In</span> the second argument <span class="kw">of</span> ‘playO’, namely ‘newBoard’</span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a>      <span class="dt">In</span> the expression<span class="op">:</span> playO (<span class="dt">A</span>, <span class="dt">B</span>) newBoard</span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a>      <span class="dt">In</span> an equation for ‘it’<span class="op">:</span> it <span class="ot">=</span> playO (<span class="dt">A</span>, <span class="dt">B</span>) Prog.newBoard</span></code></pre></div>
<p>Pretty cool!</p>
<h2 id="preventing-replays">Preventing Replays</h2>
<p>Now the real fun starts! Let's see if we can ensure that people don't
play on a space that's already been played!</p>
<p>A simple <code>X</code> or <code>O</code> in our type isn't going to
cut it anymore, let's bulk up our representation of the board state.
Let's keep track of each place someone has played! We can do this by
writing a type level list of coordinates and piece types:</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="co">-- | Keep a list of each Piece played and its location</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">BoardRep</span> <span class="ot">=</span> <span class="dt">Empty</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>              <span class="op">|</span> <span class="dt">Cons</span> <span class="dt">CoordT</span> <span class="dt">CoordT</span> <span class="dt">PieceT</span> <span class="dt">BoardRep</span></span></code></pre></div>
<p>Remember that we're using DataKinds, so now <code>BoardRep</code> is
a kind and <code>Empty</code> is a type and so is <code>Cons</code> when
it's applied to two Coordinates, a Piece type and another
<code>BoardRep</code>. It'll keep recursing until we hit an
<code>'Empty</code>.</p>
<p>Now that we have a board representation, let's replace the
<code>t</code> in our datatype with the type level representation of the
board:</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">newtype</span> <span class="dt">Board</span> (<span class="ot">b ::</span> <span class="dt">BoardRep</span>) a <span class="ot">=</span> <span class="dt">Board</span> (<span class="dt">Trip</span> (<span class="dt">Trip</span> a))</span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>, <span class="dt">Functor</span>)</span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a><span class="co">-- New boards are &#39;Empty now</span></span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a><span class="ot">newBoard ::</span> <span class="dt">Board</span> <span class="dt">&#39;Empty</span> <span class="dt">PieceT</span></span></code></pre></div>
<p>Now every time we play a piece we'll also represent the change at the
type level, in order to do that we need to be able to get the "type" of
the coordinates of each move. This is a bit tricky, since the coordinate
values themselves are all of the same type <code>CoordT</code> and
<em>NOTHING</em> is a member of the <em>types</em> A, B, or C.</p>
<p>This is where we start to introduce some <em>hacks</em> to get things
to work. Say hello to GADTs!</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="co">-- New pragma for the top</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# language GADTs #-}</span></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a><span class="co">-- | A proxy type which represents a coordinate</span></span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Coord</span> (<span class="ot">a ::</span> <span class="dt">CoordT</span>) <span class="kw">where</span></span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a>  <span class="dt">A&#39;</span><span class="ot"> ::</span> <span class="dt">Coord</span> <span class="dt">&#39;A</span></span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a>  <span class="dt">B&#39;</span><span class="ot"> ::</span> <span class="dt">Coord</span> <span class="dt">&#39;B</span></span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a>  <span class="dt">C&#39;</span><span class="ot"> ::</span> <span class="dt">Coord</span> <span class="dt">&#39;C</span></span>
<span id="cb13-9"><a href="#cb13-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-10"><a href="#cb13-10" aria-hidden="true" tabindex="-1"></a><span class="co">-- | Get the coord&#39;s actual value from a wrapper type</span></span>
<span id="cb13-11"><a href="#cb13-11" aria-hidden="true" tabindex="-1"></a><span class="ot">coordVal ::</span> <span class="dt">Coord</span> a <span class="ot">-&gt;</span> <span class="dt">CoordT</span></span>
<span id="cb13-12"><a href="#cb13-12" aria-hidden="true" tabindex="-1"></a>coordVal <span class="dt">A&#39;</span> <span class="ot">=</span> <span class="dt">A</span></span>
<span id="cb13-13"><a href="#cb13-13" aria-hidden="true" tabindex="-1"></a>coordVal <span class="dt">B&#39;</span> <span class="ot">=</span> <span class="dt">B</span></span>
<span id="cb13-14"><a href="#cb13-14" aria-hidden="true" tabindex="-1"></a>coordVal <span class="dt">C&#39;</span> <span class="ot">=</span> <span class="dt">C</span></span></code></pre></div>
<p>This is going to look weird and strangely verbose to most of you;
it's unfortunate that we need to do things this way, maybe someday we'll
find a better way. You can also look into using the <code>Proxy</code>
type from <code>Data.Proxy</code>, but it suffers similar verbosity
issues.</p>
<p>Let me explain how this works, we've written a new type
<code>Coord</code> which has a constructor for each of our Coordinate
values, but each constructur also sets the phantom type parameter of the
<code>Coord</code> to the appropriate type-level version of the
coordinate. We've also written a function <code>coordVal</code> which
translates from our wrapper type into the matching <code>CoordT</code>
value.</p>
<p>Bleh, a little ugly, but now we can write some well-typed
<code>play</code> functions:</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">-- View patterns help us clean up our definitions a lot:</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# language ViewPatterns #-}</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="ot">playX ::</span> (<span class="dt">Coord</span> x, <span class="dt">Coord</span> y) <span class="ot">-&gt;</span> <span class="dt">Board</span> b <span class="dt">PieceT</span> <span class="ot">-&gt;</span> <span class="dt">Board</span> (<span class="dt">&#39;Cons</span> x y <span class="dt">&#39;X</span> b) <span class="dt">PieceT</span></span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a>playX (coordVal <span class="ot">-&gt;</span> x, coordVal <span class="ot">-&gt;</span> y) (<span class="dt">Board</span> b) </span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a>        <span class="ot">=</span> <span class="dt">Board</span> <span class="op">$</span> overTrip y (overTrip x (<span class="fu">const</span> <span class="dt">X</span>)) b</span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a><span class="ot">playO ::</span> (<span class="dt">Coord</span> x, <span class="dt">Coord</span> y) <span class="ot">-&gt;</span> <span class="dt">Board</span> b <span class="dt">PieceT</span> <span class="ot">-&gt;</span> <span class="dt">Board</span> (<span class="dt">&#39;Cons</span> x y <span class="dt">&#39;O</span> b) <span class="dt">PieceT</span></span>
<span id="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a>playO (coordVal <span class="ot">-&gt;</span> x, coordVal <span class="ot">-&gt;</span> y) (<span class="dt">Board</span> b) </span>
<span id="cb14-10"><a href="#cb14-10" aria-hidden="true" tabindex="-1"></a>        <span class="ot">=</span> <span class="dt">Board</span> <span class="op">$</span> overTrip y (overTrip x (<span class="fu">const</span> <span class="dt">O</span>)) b</span></code></pre></div>
<p>If ViewPatterns are new to you, check out <a
href="https://ocharles.org.uk/blog/posts/2014-12-02-view-patterns.html">Oliver
Charles' post</a> to learn more.</p>
<p>Now we get both the type level coordinates AND the value level
coordinates! Awesome. We're storing the played pieces in the type list
now, but we still need to check that it's an unplayed square! We
wouldn't be type programming without type functions, let's dive in! In
Haskell type functions are called Type Families, but really they're just
functions on types:</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">-- Another pragma &gt;_&gt;</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# language TypeFamilies #-}</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="co">-- | Has a square been played already?</span></span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="kw">family</span> <span class="dt">Played</span> (<span class="ot">x ::</span> <span class="dt">CoordT</span>) (<span class="ot">y ::</span> <span class="dt">CoordT</span>) (<span class="ot">b ::</span> <span class="dt">BoardRep</span>)<span class="ot"> ::</span> <span class="dt">Bool</span> <span class="kw">where</span></span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a>   <span class="co">--  Nothing is played on the &#39;Empty board</span></span>
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Played</span> _ _ <span class="dt">&#39;Empty</span> <span class="ot">=</span> <span class="dt">&#39;False</span></span>
<span id="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a>   <span class="co">--  We found a match, so the square has already been played</span></span>
<span id="cb15-9"><a href="#cb15-9" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Played</span> x y (<span class="dt">&#39;Cons</span> x y _ _) <span class="ot">=</span> <span class="dt">&#39;True</span></span>
<span id="cb15-10"><a href="#cb15-10" aria-hidden="true" tabindex="-1"></a>   <span class="co">--  No match yet, but there might be one in the rest of the list</span></span>
<span id="cb15-11"><a href="#cb15-11" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Played</span> x y (<span class="dt">&#39;Cons</span> _ _ _ rest) <span class="ot">=</span> <span class="dt">Played</span> x y rest</span></code></pre></div>
<p>This is implemented as a linear search through the list looking for a
match. If we ever find a matching set of coordinates in the list then we
know we've played there already. Notice that type families also return a
type, so we specify the Kind of that return value, in this case
<code>Bool</code>, so the returned type will be either
<code>'True</code> or <code>'False</code>.</p>
<p>Let's use this to write constraints for our play functions:</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">playX ::</span> (<span class="dt">Played</span> x y b <span class="op">~</span> <span class="dt">&#39;False</span>) </span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a>      <span class="ot">=&gt;</span> (<span class="dt">Coord</span> x, <span class="dt">Coord</span> y) <span class="ot">-&gt;</span> <span class="dt">Board</span> b <span class="dt">PieceT</span> <span class="ot">-&gt;</span> <span class="dt">Board</span> (<span class="dt">&#39;Cons</span> x y <span class="dt">&#39;X</span> b) <span class="dt">PieceT</span></span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a><span class="ot">playO ::</span> (<span class="dt">Played</span> x y b <span class="op">~</span> <span class="dt">&#39;False</span>) </span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a>      <span class="ot">=&gt;</span> (<span class="dt">Coord</span> x, <span class="dt">Coord</span> y) <span class="ot">-&gt;</span> <span class="dt">Board</span> b <span class="dt">PieceT</span> <span class="ot">-&gt;</span> <span class="dt">Board</span> (<span class="dt">&#39;Cons</span> x y <span class="dt">&#39;O</span> b) <span class="dt">PieceT</span></span></code></pre></div>
<p>Now we're asserting that in order to call this function the board
must not have played on those coordinates yet! If you haven't seen it
before, <code>~</code> does an equality check on two types and creates a
constraint which requires them to be equal.</p>
<p>We're close to done, but unfortunately in our upgrade we forgot to
ensure that <code>X</code> and <code>O</code> always alternate!</p>
<h2 id="rechecking-alterating-turns">Rechecking Alterating Turns</h2>
<p>Checking whose turn it is with our new representation is easier than
you might think; if the last play was <code>X</code> then it's
<code>O</code>s turn, and in all other cases it's <code>X</code>s
turn!</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="kw">type</span> <span class="kw">family</span> <span class="dt">Turn</span> (<span class="ot">b ::</span> <span class="dt">BoardRep</span>)<span class="ot"> ::</span> <span class="dt">PieceT</span> <span class="kw">where</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Turn</span> (<span class="dt">&#39;Cons</span> _ _ <span class="dt">&#39;X</span> _) <span class="ot">=</span> <span class="dt">&#39;O</span></span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Turn</span> _ <span class="ot">=</span> <span class="dt">&#39;X</span></span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a><span class="ot">playX ::</span> (<span class="dt">Played</span> x y b <span class="op">~</span> <span class="dt">&#39;False</span>, <span class="dt">Turn</span> b <span class="op">~</span> <span class="dt">&#39;X</span>) <span class="ot">=&gt;</span></span>
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a>         (<span class="dt">Coord</span> x, <span class="dt">Coord</span> y) <span class="ot">-&gt;</span> <span class="dt">Board</span> b <span class="dt">PieceT</span> <span class="ot">-&gt;</span> <span class="dt">Board</span> (<span class="dt">&#39;Cons</span> x y <span class="dt">&#39;X</span> b) <span class="dt">PieceT</span></span>
<span id="cb17-7"><a href="#cb17-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-8"><a href="#cb17-8" aria-hidden="true" tabindex="-1"></a><span class="ot">playO ::</span> (<span class="dt">Played</span> x y b <span class="op">~</span> <span class="dt">&#39;False</span>, <span class="dt">Turn</span> b <span class="op">~</span> <span class="dt">&#39;O</span>) <span class="ot">=&gt;</span> </span>
<span id="cb17-9"><a href="#cb17-9" aria-hidden="true" tabindex="-1"></a>         (<span class="dt">Coord</span> x, <span class="dt">Coord</span> y) <span class="ot">-&gt;</span> <span class="dt">Board</span> b <span class="dt">PieceT</span> <span class="ot">-&gt;</span> <span class="dt">Board</span> (<span class="dt">&#39;Cons</span> x y <span class="dt">&#39;O</span> b) <span class="dt">PieceT</span></span></code></pre></div>
<p>We also altered the constraints of playX and playO to reflect the
requirement!</p>
<p>We're in good shape now! We can play a game!</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="op">&gt;</span> <span class="kw">import</span> <span class="dt">Data.Function</span> ((&amp;))</span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> newBoard</span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a>    <span class="op">&amp;</span> playX (<span class="dt">A&#39;</span>, <span class="dt">B&#39;</span>)</span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">&amp;</span> playO (<span class="dt">C&#39;</span>, <span class="dt">C&#39;</span>)</span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">&amp;</span> playX (<span class="dt">A&#39;</span>, <span class="dt">A&#39;</span>)</span>
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a><span class="dt">Board</span> (<span class="dt">Trip</span> (<span class="dt">Trip</span> <span class="dt">X</span> <span class="dt">N</span> <span class="dt">N</span>) (<span class="dt">Trip</span> <span class="dt">X</span> <span class="dt">N</span> <span class="dt">N</span>) (<span class="dt">Trip</span> <span class="dt">N</span> <span class="dt">N</span> <span class="dt">O</span>))</span>
<span id="cb18-7"><a href="#cb18-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-8"><a href="#cb18-8" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> newBoard</span>
<span id="cb18-9"><a href="#cb18-9" aria-hidden="true" tabindex="-1"></a>    <span class="op">&amp;</span> playX (<span class="dt">A&#39;</span>, <span class="dt">B&#39;</span>)</span>
<span id="cb18-10"><a href="#cb18-10" aria-hidden="true" tabindex="-1"></a>    <span class="op">&amp;</span> playX (<span class="dt">C&#39;</span>, <span class="dt">C&#39;</span>)</span>
<span id="cb18-11"><a href="#cb18-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-12"><a href="#cb18-12" aria-hidden="true" tabindex="-1"></a><span class="fu">error</span><span class="op">:</span></span>
<span id="cb18-13"><a href="#cb18-13" aria-hidden="true" tabindex="-1"></a>    • <span class="dt">Couldn&#39;t</span> match <span class="kw">type</span> ‘<span class="dt">&#39;O</span>’ with ‘<span class="dt">&#39;X</span>’ arising from a use <span class="kw">of</span> ‘playX’</span>
<span id="cb18-14"><a href="#cb18-14" aria-hidden="true" tabindex="-1"></a>    • <span class="dt">In</span> the second argument <span class="kw">of</span> ‘(<span class="op">&amp;</span>)’, namely ‘playX (<span class="dt">C&#39;</span>, <span class="dt">C&#39;</span>)’</span>
<span id="cb18-15"><a href="#cb18-15" aria-hidden="true" tabindex="-1"></a>      <span class="dt">In</span> the expression<span class="op">:</span> newBoard <span class="op">&amp;</span> playX (<span class="dt">A&#39;</span>, <span class="dt">B&#39;</span>) <span class="op">&amp;</span> playX (<span class="dt">C&#39;</span>, <span class="dt">C&#39;</span>)</span>
<span id="cb18-16"><a href="#cb18-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-17"><a href="#cb18-17" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> newBoard</span>
<span id="cb18-18"><a href="#cb18-18" aria-hidden="true" tabindex="-1"></a>    <span class="op">&amp;</span> playX (<span class="dt">A&#39;</span>, <span class="dt">B&#39;</span>)</span>
<span id="cb18-19"><a href="#cb18-19" aria-hidden="true" tabindex="-1"></a>    <span class="op">&amp;</span> playO (<span class="dt">A&#39;</span>, <span class="dt">B&#39;</span>)</span>
<span id="cb18-20"><a href="#cb18-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-21"><a href="#cb18-21" aria-hidden="true" tabindex="-1"></a><span class="fu">error</span><span class="op">:</span></span>
<span id="cb18-22"><a href="#cb18-22" aria-hidden="true" tabindex="-1"></a>    • <span class="dt">Couldn&#39;t</span> match <span class="kw">type</span> ‘<span class="dt">&#39;True</span>’ with ‘<span class="dt">&#39;False</span>’</span>
<span id="cb18-23"><a href="#cb18-23" aria-hidden="true" tabindex="-1"></a>        arising from a use <span class="kw">of</span> ‘playO’</span>
<span id="cb18-24"><a href="#cb18-24" aria-hidden="true" tabindex="-1"></a>    • <span class="dt">In</span> the second argument <span class="kw">of</span> ‘(<span class="op">&amp;</span>)’, namely ‘playO (<span class="dt">A&#39;</span>, <span class="dt">B&#39;</span>)’</span>
<span id="cb18-25"><a href="#cb18-25" aria-hidden="true" tabindex="-1"></a>      <span class="dt">In</span> the expression<span class="op">:</span> newBoard <span class="op">&amp;</span> playX (<span class="dt">A&#39;</span>, <span class="dt">B&#39;</span>) <span class="op">&amp;</span> playO (<span class="dt">A&#39;</span>, <span class="dt">B&#39;</span>)</span></code></pre></div>
<p>Looks good to me! As an exercise try combining <code>playX</code> and
<code>playO</code> into a more general <code>play</code>! Here's a hint,
you'll want to make another wrapper type like we did with
<code>Coord</code>!</p>
<p>Here's the finished product all at once, it's also available as a
stack project in a <a
href="https://github.com/ChrisPenner/Type-Tac-Toe">git repo
here</a>.:</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="ot">{-# language DeriveFunctor #-}</span></span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# language KindSignatures #-}</span></span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# language DataKinds #-}</span></span>
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# language ViewPatterns #-}</span></span>
<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# language GADTs #-}</span></span>
<span id="cb19-6"><a href="#cb19-6" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# language TypeFamilies #-}</span></span>
<span id="cb19-7"><a href="#cb19-7" aria-hidden="true" tabindex="-1"></a><span class="kw">module</span> <span class="dt">TypeTacToe</span> <span class="kw">where</span></span>
<span id="cb19-8"><a href="#cb19-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-9"><a href="#cb19-9" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Function</span> ((&amp;))</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="co">-- | Either X, O, or Nothing</span></span>
<span id="cb19-12"><a href="#cb19-12" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">PieceT</span> <span class="ot">=</span> <span class="dt">X</span> <span class="op">|</span> <span class="dt">O</span> <span class="op">|</span> <span class="dt">N</span></span>
<span id="cb19-13"><a href="#cb19-13" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>)</span>
<span id="cb19-14"><a href="#cb19-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-15"><a href="#cb19-15" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">CoordT</span> <span class="ot">=</span> <span class="dt">A</span> <span class="op">|</span> <span class="dt">B</span> <span class="op">|</span> <span class="dt">C</span></span>
<span id="cb19-16"><a href="#cb19-16" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>)</span>
<span id="cb19-17"><a href="#cb19-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-18"><a href="#cb19-18" aria-hidden="true" tabindex="-1"></a><span class="co">-- | A proxy type which represents a coordinate</span></span>
<span id="cb19-19"><a href="#cb19-19" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Coord</span> (<span class="ot">a ::</span> <span class="dt">CoordT</span>) <span class="kw">where</span></span>
<span id="cb19-20"><a href="#cb19-20" aria-hidden="true" tabindex="-1"></a>  <span class="dt">A&#39;</span><span class="ot"> ::</span> <span class="dt">Coord</span> <span class="dt">&#39;A</span></span>
<span id="cb19-21"><a href="#cb19-21" aria-hidden="true" tabindex="-1"></a>  <span class="dt">B&#39;</span><span class="ot"> ::</span> <span class="dt">Coord</span> <span class="dt">&#39;B</span></span>
<span id="cb19-22"><a href="#cb19-22" aria-hidden="true" tabindex="-1"></a>  <span class="dt">C&#39;</span><span class="ot"> ::</span> <span class="dt">Coord</span> <span class="dt">&#39;C</span></span>
<span id="cb19-23"><a href="#cb19-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-24"><a href="#cb19-24" aria-hidden="true" tabindex="-1"></a><span class="co">-- | Get the coord&#39;s actual value from a wrapper type</span></span>
<span id="cb19-25"><a href="#cb19-25" aria-hidden="true" tabindex="-1"></a><span class="ot">coordVal ::</span> <span class="dt">Coord</span> a <span class="ot">-&gt;</span> <span class="dt">CoordT</span></span>
<span id="cb19-26"><a href="#cb19-26" aria-hidden="true" tabindex="-1"></a>coordVal <span class="dt">A&#39;</span> <span class="ot">=</span> <span class="dt">A</span></span>
<span id="cb19-27"><a href="#cb19-27" aria-hidden="true" tabindex="-1"></a>coordVal <span class="dt">B&#39;</span> <span class="ot">=</span> <span class="dt">B</span></span>
<span id="cb19-28"><a href="#cb19-28" aria-hidden="true" tabindex="-1"></a>coordVal <span class="dt">C&#39;</span> <span class="ot">=</span> <span class="dt">C</span></span>
<span id="cb19-29"><a href="#cb19-29" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-30"><a href="#cb19-30" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Trip</span> a <span class="ot">=</span> <span class="dt">Trip</span> a a a</span>
<span id="cb19-31"><a href="#cb19-31" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>, <span class="dt">Functor</span>)</span>
<span id="cb19-32"><a href="#cb19-32" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-33"><a href="#cb19-33" aria-hidden="true" tabindex="-1"></a><span class="co">-- | Utility function to alter a value inside a triple</span></span>
<span id="cb19-34"><a href="#cb19-34" aria-hidden="true" tabindex="-1"></a><span class="co">-- Can build get / set using `flip const ()` and `const x` respectively</span></span>
<span id="cb19-35"><a href="#cb19-35" aria-hidden="true" tabindex="-1"></a><span class="ot">overTrip ::</span> <span class="dt">CoordT</span> <span class="ot">-&gt;</span> (a <span class="ot">-&gt;</span> a) <span class="ot">-&gt;</span> <span class="dt">Trip</span> a <span class="ot">-&gt;</span> <span class="dt">Trip</span> a</span>
<span id="cb19-36"><a href="#cb19-36" aria-hidden="true" tabindex="-1"></a>overTrip <span class="dt">A</span> f (<span class="dt">Trip</span> a b c) <span class="ot">=</span> <span class="dt">Trip</span> (f a) b c</span>
<span id="cb19-37"><a href="#cb19-37" aria-hidden="true" tabindex="-1"></a>overTrip <span class="dt">B</span> f (<span class="dt">Trip</span> a b c) <span class="ot">=</span> <span class="dt">Trip</span> a (f b) c</span>
<span id="cb19-38"><a href="#cb19-38" aria-hidden="true" tabindex="-1"></a>overTrip <span class="dt">C</span> f (<span class="dt">Trip</span> a b c) <span class="ot">=</span> <span class="dt">Trip</span> a b (f c)</span>
<span id="cb19-39"><a href="#cb19-39" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-40"><a href="#cb19-40" aria-hidden="true" tabindex="-1"></a><span class="co">-- | Keep a list of each Piece played and its location</span></span>
<span id="cb19-41"><a href="#cb19-41" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">BoardRep</span> <span class="ot">=</span> <span class="dt">Empty</span></span>
<span id="cb19-42"><a href="#cb19-42" aria-hidden="true" tabindex="-1"></a>              <span class="op">|</span> <span class="dt">Cons</span> <span class="dt">CoordT</span> <span class="dt">CoordT</span> <span class="dt">PieceT</span> <span class="dt">BoardRep</span></span>
<span id="cb19-43"><a href="#cb19-43" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-44"><a href="#cb19-44" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-45"><a href="#cb19-45" aria-hidden="true" tabindex="-1"></a><span class="co">-- A board is a 3x3 grid alongside its type representation</span></span>
<span id="cb19-46"><a href="#cb19-46" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">Board</span> (<span class="ot">b ::</span> <span class="dt">BoardRep</span>) a <span class="ot">=</span> <span class="dt">Board</span> (<span class="dt">Trip</span> (<span class="dt">Trip</span> a))</span>
<span id="cb19-47"><a href="#cb19-47" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>, <span class="dt">Functor</span>)</span>
<span id="cb19-48"><a href="#cb19-48" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-49"><a href="#cb19-49" aria-hidden="true" tabindex="-1"></a><span class="co">-- | New empty board</span></span>
<span id="cb19-50"><a href="#cb19-50" aria-hidden="true" tabindex="-1"></a><span class="ot">newBoard ::</span> <span class="dt">Board</span> <span class="dt">&#39;Empty</span> <span class="dt">PieceT</span></span>
<span id="cb19-51"><a href="#cb19-51" aria-hidden="true" tabindex="-1"></a>newBoard <span class="ot">=</span> <span class="dt">Board</span> <span class="op">$</span> <span class="dt">Trip</span> (<span class="dt">Trip</span> <span class="dt">N</span> <span class="dt">N</span> <span class="dt">N</span>)</span>
<span id="cb19-52"><a href="#cb19-52" aria-hidden="true" tabindex="-1"></a>                        (<span class="dt">Trip</span> <span class="dt">N</span> <span class="dt">N</span> <span class="dt">N</span>)</span>
<span id="cb19-53"><a href="#cb19-53" aria-hidden="true" tabindex="-1"></a>                        (<span class="dt">Trip</span> <span class="dt">N</span> <span class="dt">N</span> <span class="dt">N</span>)</span>
<span id="cb19-54"><a href="#cb19-54" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-55"><a href="#cb19-55" aria-hidden="true" tabindex="-1"></a><span class="co">-- | Has a square been played already?</span></span>
<span id="cb19-56"><a href="#cb19-56" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="kw">family</span> <span class="dt">Played</span> (<span class="ot">x ::</span> <span class="dt">CoordT</span>) (<span class="ot">y ::</span> <span class="dt">CoordT</span>) (<span class="ot">b ::</span> <span class="dt">BoardRep</span>)<span class="ot"> ::</span> <span class="dt">Bool</span> <span class="kw">where</span></span>
<span id="cb19-57"><a href="#cb19-57" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Played</span> _ _ <span class="dt">&#39;Empty</span> <span class="ot">=</span> <span class="dt">&#39;False</span></span>
<span id="cb19-58"><a href="#cb19-58" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Played</span> x y (<span class="dt">&#39;Cons</span> x y _ _) <span class="ot">=</span> <span class="dt">&#39;True</span></span>
<span id="cb19-59"><a href="#cb19-59" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Played</span> x y (<span class="dt">&#39;Cons</span> _ _ _ rest) <span class="ot">=</span> <span class="dt">Played</span> x y rest</span>
<span id="cb19-60"><a href="#cb19-60" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-61"><a href="#cb19-61" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-62"><a href="#cb19-62" aria-hidden="true" tabindex="-1"></a><span class="co">-- | Get who&#39;s turn it is</span></span>
<span id="cb19-63"><a href="#cb19-63" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="kw">family</span> <span class="dt">Turn</span> (<span class="ot">b ::</span> <span class="dt">BoardRep</span>)<span class="ot"> ::</span> <span class="dt">PieceT</span> <span class="kw">where</span></span>
<span id="cb19-64"><a href="#cb19-64" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Turn</span> (<span class="dt">&#39;Cons</span> _ _ <span class="dt">&#39;X</span> _) <span class="ot">=</span> <span class="dt">&#39;O</span></span>
<span id="cb19-65"><a href="#cb19-65" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Turn</span> _ <span class="ot">=</span> <span class="dt">&#39;X</span></span>
<span id="cb19-66"><a href="#cb19-66" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-67"><a href="#cb19-67" aria-hidden="true" tabindex="-1"></a><span class="co">-- | Play a piece on square (x, y) if it&#39;s valid to do so</span></span>
<span id="cb19-68"><a href="#cb19-68" aria-hidden="true" tabindex="-1"></a><span class="ot">playX ::</span> (<span class="dt">Played</span> x y b <span class="op">~</span> <span class="dt">&#39;False</span>, <span class="dt">Turn</span> b <span class="op">~</span> <span class="dt">&#39;X</span>)</span>
<span id="cb19-69"><a href="#cb19-69" aria-hidden="true" tabindex="-1"></a>      <span class="ot">=&gt;</span> (<span class="dt">Coord</span> x, <span class="dt">Coord</span> y) <span class="ot">-&gt;</span> <span class="dt">Board</span> b <span class="dt">PieceT</span> <span class="ot">-&gt;</span> <span class="dt">Board</span> (<span class="dt">&#39;Cons</span> x y <span class="dt">&#39;X</span> b) <span class="dt">PieceT</span></span>
<span id="cb19-70"><a href="#cb19-70" aria-hidden="true" tabindex="-1"></a>playX (coordVal <span class="ot">-&gt;</span> x, coordVal <span class="ot">-&gt;</span> y) (<span class="dt">Board</span> b) </span>
<span id="cb19-71"><a href="#cb19-71" aria-hidden="true" tabindex="-1"></a>      <span class="ot">=</span> <span class="dt">Board</span> <span class="op">$</span> overTrip y (overTrip x (<span class="fu">const</span> <span class="dt">X</span>)) b</span>
<span id="cb19-72"><a href="#cb19-72" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-73"><a href="#cb19-73" aria-hidden="true" tabindex="-1"></a><span class="ot">playO ::</span> (<span class="dt">Played</span> x y b <span class="op">~</span> <span class="dt">&#39;False</span>, <span class="dt">Turn</span> b <span class="op">~</span> <span class="dt">&#39;O</span>)</span>
<span id="cb19-74"><a href="#cb19-74" aria-hidden="true" tabindex="-1"></a>      <span class="ot">=&gt;</span> (<span class="dt">Coord</span> x, <span class="dt">Coord</span> y) <span class="ot">-&gt;</span> <span class="dt">Board</span> b <span class="dt">PieceT</span> <span class="ot">-&gt;</span> <span class="dt">Board</span> (<span class="dt">&#39;Cons</span> x y <span class="dt">&#39;O</span> b) <span class="dt">PieceT</span></span>
<span id="cb19-75"><a href="#cb19-75" aria-hidden="true" tabindex="-1"></a>playO (coordVal <span class="ot">-&gt;</span> x, coordVal <span class="ot">-&gt;</span> y) (<span class="dt">Board</span> b) </span>
<span id="cb19-76"><a href="#cb19-76" aria-hidden="true" tabindex="-1"></a>      <span class="ot">=</span> <span class="dt">Board</span> <span class="op">$</span> overTrip y (overTrip x (<span class="fu">const</span> <span class="dt">O</span>)) b</span>
<span id="cb19-77"><a href="#cb19-77" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-78"><a href="#cb19-78" aria-hidden="true" tabindex="-1"></a><span class="ot">game ::</span> <span class="dt">Board</span> (<span class="dt">&#39;Cons</span> <span class="dt">&#39;A</span> <span class="dt">&#39;A</span> <span class="dt">&#39;O</span> (<span class="dt">&#39;Cons</span> <span class="dt">&#39;A</span> <span class="dt">&#39;B</span> <span class="dt">&#39;X</span> <span class="dt">&#39;Empty</span>)) <span class="dt">PieceT</span></span>
<span id="cb19-79"><a href="#cb19-79" aria-hidden="true" tabindex="-1"></a>game <span class="ot">=</span> newBoard</span>
<span id="cb19-80"><a href="#cb19-80" aria-hidden="true" tabindex="-1"></a>     <span class="op">&amp;</span> playX (<span class="dt">A&#39;</span>, <span class="dt">B&#39;</span>)</span>
<span id="cb19-81"><a href="#cb19-81" aria-hidden="true" tabindex="-1"></a>     <span class="op">&amp;</span> playO (<span class="dt">A&#39;</span>, <span class="dt">A&#39;</span>)</span></code></pre></div>
<p>That last type there is a doozy! The type actually includes the
entire game board, and it'll only grow as we add moves! This exposes
some issues with using this approach for a real-life tic-tac-toe game.
Not only are the types unwieldy if you ever need to specify them, but
the type is actually so well defined that we can't really write a
function to use user input!</p>
<p>Give it a try if you don't believe me, we'd want something along the
lines of:</p>
<pre><code>String -&gt; Board b PieceT -&gt; Board ? PieceT</code></pre>
<p>We'd parse the string into the coords for a move. It's really tough
to decide what would go into the <code>?</code> though, we can't give it
a type because we don't know what the Coords will be until after we've
already parsed the string! This is the sort of thing that's sometimes
possible in Idris' dependent types, but is pretty tricky in Haskell. You
can see Brian McKenna show how to build a <a
href="https://www.youtube.com/watch?v=fVBck2Zngjo">type-safe
<code>printf</code></a> in Idris if you're interested.</p>
<p>Thanks for joining me, let me know if you found anything confusing;
hope you learned something!</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Conway&#39;s Game of Life using Representable and Comonads</title>
      <link href="https://chrispenner.ca/posts/conways-game-of-life"/>
      <id>https://chrispenner.ca/posts/conways-game-of-life</id>
      <updated>2017-08-08T00:00:00Z</updated>
      <summary>Quick ~100 line implementation of Conway&#39;s game of life in Haskell</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/conway.png" alt="Conway&#39;s Game of Life using Representable and Comonads">
              <p>Just a quick post today, I had some time free this weekend and
figured I'd take a crack at an old classic: "<a
href="https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life">Conway's
Game of Life</a>".</p>
<p>This is an interesting puzzle because it centers around context-based
computations, each cell determines whether it lives or dies in the next
generation based on its nearby neighbours. This is typically considered
one of the trickier things to do in a functional language and solutions
often end up being a bit clunky at best. I think clunkiness usually
results when attempting to port a solution from an imperative language
over to a functional language. To do so you need to figure out some way
to iterate over your grid in 2 dimensions at once doing complicated
indexing to compute your neighbours and attempting to store your results
somewhere as you go. It definitely can be done, you can fake loops using
folds and traversable, but I feel like there are better approaches.
Allow me to present my take on it.</p>
<p>If you like to load up code and follow along you can find the source
<a href="https://github.com/ChrisPenner/conway">here</a>!</p>
<p>We'll be using some pretty standard language extensions, and we'll be
using Representable and Comonads, so let's import a few things to get
started:</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">{-# language GeneralizedNewtypeDeriving #-}</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# language TypeFamilies #-}</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="kw">module</span> <span class="dt">Conway</span> <span class="kw">where</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="kw">import</span> <span class="dt">Data.Functor.Compose</span> (<span class="dt">Compose</span>(..))</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Data.Vector</span> <span class="kw">as</span> <span class="dt">V</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Bool</span> (bool)</span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Distributive</span> (<span class="dt">Distributive</span>(..))</span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Functor.Rep</span> (<span class="dt">Representable</span>(..), distributeRep)</span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Functor.Identity</span> (<span class="dt">Identity</span>(..))</span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Arrow</span> ((***))</span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Comonad.Representable.Store</span> (<span class="dt">Store</span>(..), <span class="dt">StoreT</span>(..), store, experiment)</span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Comonad</span> (<span class="dt">Comonad</span>(..))</span></code></pre></div>
<p>Conway's game of life runs on a grid, so we'll need to think up some
way to represent that. We'll need to be able to index into that grid and
be able to compute neighbours of a given location, so we can let that
guide our representation.</p>
<p>I've often seen people try to represent grids in Haskell as List
Zippers generalized to higher dimensions, i.e. if we have a structure
like <code>data Zipper a = Zipper [a] a [a]</code>, you might try
representing a grid as <code>Zipper (Zipper a)</code>.</p>
<p>While this is a totally valid representation, indexing into it and
defining comonad's <code>extend</code> becomes prohibitively difficult
to reason about. I propose we try something a little different by
extracting the 'index' from the data structure and holding them together
side by side. We'll represent our grid as a Vector of Vectors just as
you'd expect, but then we'll pair that with a set of <code>(x, y)</code>
coordinates and set up some indexing logic to take care of our Comonad
instance for us!</p>
<p>If your Category Theory senses are tingling you may recognize this as
the <a
href="http://hackage.haskell.org/package/comonad-5.0.2/docs/Control-Comonad-Store.html">Store
Comonad</a>. <code>Store</code> is typically represented as a tuple of
<code>(s -&gt; a, s)</code>. This means that you have some index type
<code>s</code> and you know how to look up an <code>a</code> from it. We
can model our grid as <code>(Vector (Vector a), (Int, Int))</code> then
our <code>s -&gt; a</code> is simply a partially applied Vector lookup!
I tried setting this up, but the default Store comonad does no
optimization or memoization over the underling function so for each
progressive step in Conway's game of life it had to compute all previous
steps again! That's clearly pretty inefficient, we can do better!</p>
<p>Enter <code>Control.Comonad.Representable.Store</code>! As we just
noticed, a Store is just an indexing function alongside an index, since
Representable Functors are indexable by nature, they make a great
companion for the Store comonad. Now instead of partially applying our
index function we can actually just keep the Representable functor
around and do operations over that, so the Store is going to look
something like this: <code>(Vector (Vector a), (Int, Int))</code>.</p>
<p>Unfortunately there isn't a Representable instance defined for
Vectors (since they can vary in size), so we'll need to take care of
that first. For simplicity we'll deal with a fixed grid-size of
<code>20x20</code>, meaning we can enforce that each vector is of
exactly length 20 which lets us write a representable instance for it!.
We'll wrap the Vectors in a <code>VBounded</code> newtype to keep things
straight:</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">VBounded</span> a <span class="ot">=</span> <span class="dt">VBounded</span> (<span class="dt">V.Vector</span> a)</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Eq</span>, <span class="dt">Show</span>, <span class="dt">Functor</span>, <span class="dt">Foldable</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="kw">instance</span> <span class="dt">Distributive</span> <span class="dt">VBounded</span> <span class="kw">where</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>  distribute <span class="ot">=</span> distributeRep</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a><span class="ot">gridSize ::</span> <span class="dt">Int</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>gridSize <span class="ot">=</span> <span class="dv">20</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Representable</span> <span class="dt">VBounded</span> <span class="kw">where</span></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a>  <span class="kw">type</span> <span class="dt">Rep</span> <span class="dt">VBounded</span> <span class="ot">=</span> <span class="dt">Int</span></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a>  <span class="fu">index</span> (<span class="dt">VBounded</span> v) i <span class="ot">=</span> v <span class="op">V.!</span> (i <span class="ot">`mod`</span> gridSize)</span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a>  tabulate desc <span class="ot">=</span> <span class="dt">VBounded</span> <span class="op">$</span> V.generate gridSize desc</span></code></pre></div>
<p>There's the heavy lifting done! Notice that in the Representable
instance for VBounded we're doing pac-man 'wrap-around' logic by taking
the modulus of indices by grid size before indexing.</p>
<p>Now let's wrap it up in a Store, we're using <code>store</code>
provided by <code>Control.ComonadRepresentable.Store</code> takes a
tabulation function and a starting index and builds up a representable
instace for us. For our starting position we'll take a list of
coordinates which are 'alive'. That means that our tabulation function
can just compute whether the index it's passed is part of the 'living'
list!</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">type</span> <span class="dt">Grid</span> a <span class="ot">=</span> <span class="dt">Store</span> (<span class="dt">Compose</span> <span class="dt">VBounded</span> <span class="dt">VBounded</span>) a</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">Coord</span> <span class="ot">=</span> (<span class="dt">Int</span>, <span class="dt">Int</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">mkGrid ::</span> [<span class="dt">Coord</span>] <span class="ot">-&gt;</span> <span class="dt">Grid</span> <span class="dt">Bool</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>mkGrid xs <span class="ot">=</span> store <span class="fu">lookup</span> (<span class="dv">0</span>, <span class="dv">0</span>)</span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>    <span class="fu">lookup</span> crd <span class="ot">=</span> crd <span class="ot">`elem`</span> xs</span></code></pre></div>
<p>Now for the meat and potatoes, we need to compute the successive
iterations of the grid over time. We may want to switch the set of life
rules later, so let's make it generic. We need to know the neighbours of
each cell in order to know how it will change, which means we need to
somehow get each cell, find its neighbours, compute its liveness, then
slot that into the grid as the next iteration. That sounds like a lot of
work! If we think about it though, contextual computations are a
comonad's specialty! Our Representable Store is a comonad, which means
it implements
<code>extend :: (Grid a -&gt; b) -&gt; Grid a -&gt; Grid b</code>. Each
Grid passed to the function is focused on one of the slots in the grid,
and whatever the function returns will be put into that slot! This makes
it pretty easy to write our rule!</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">type</span> <span class="dt">Rule</span> <span class="ot">=</span> <span class="dt">Grid</span> <span class="dt">Bool</span> <span class="ot">-&gt;</span> <span class="dt">Bool</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">-- Offsets for the neighbouring 8 tiles, avoiding (0, 0) which is the cell itself</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="ot">neighbourCoords ::</span> [(<span class="dt">Int</span>, <span class="dt">Int</span>)]</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>neighbourCoords <span class="ot">=</span> [(x, y) <span class="op">|</span> x <span class="ot">&lt;-</span> [<span class="op">-</span><span class="dv">1</span>, <span class="dv">0</span>, <span class="dv">1</span>], y <span class="ot">&lt;-</span> [<span class="op">-</span><span class="dv">1</span>, <span class="dv">0</span>, <span class="dv">1</span>], (x, y) <span class="op">/=</span> (<span class="dv">0</span>, <span class="dv">0</span>)]</span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a><span class="ot">basicRule ::</span> <span class="dt">Rule</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>basicRule g <span class="ot">=</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>  (alive <span class="op">&amp;&amp;</span> numNeighboursAlive <span class="ot">`elem`</span> [<span class="dv">2</span>, <span class="dv">3</span>]) <span class="op">||</span> (<span class="fu">not</span> alive <span class="op">&amp;&amp;</span> numNeighboursAlive <span class="op">==</span> <span class="dv">3</span>)</span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a>    alive <span class="ot">=</span> extract g</span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a>    addCoords (x, y) (x&#39;, y&#39;) <span class="ot">=</span> (x <span class="op">+</span> x&#39;, y <span class="op">+</span> y&#39;)</span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a>    neighbours <span class="ot">=</span> experiment (\s <span class="ot">-&gt;</span> addCoords s <span class="op">&lt;$&gt;</span> neighbourCoords) g</span>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a>    numNeighboursAlive <span class="ot">=</span> <span class="fu">length</span> (<span class="fu">filter</span> <span class="fu">id</span> neighbours)</span>
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-16"><a href="#cb4-16" aria-hidden="true" tabindex="-1"></a><span class="ot">step ::</span> <span class="dt">Rule</span> <span class="ot">-&gt;</span> <span class="dt">Grid</span> <span class="dt">Bool</span> <span class="ot">-&gt;</span> <span class="dt">Grid</span> <span class="dt">Bool</span></span>
<span id="cb4-17"><a href="#cb4-17" aria-hidden="true" tabindex="-1"></a>step <span class="ot">=</span> extend</span></code></pre></div>
<p>Two things here, we've defined <code>step = extend</code> which we
can partially apply with a rule for our game, turning it into just
<code>Grid Bool -&gt; Grid Bool</code> which is perfect for iterating
through cycles! The other interesting thing is the use of
<code>experiment</code> which is provided by the
<code>ComonadStore</code> typeclass. Here's the generalized signature
alongside our specialized version:</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">experiment ::</span> (<span class="dt">Functor</span> f, <span class="dt">ComonadStore</span> s w) <span class="ot">=&gt;</span> (s <span class="ot">-&gt;</span> f s) <span class="ot">-&gt;</span> w a <span class="ot">-&gt;</span> f a</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="ot">experiment ::</span> (<span class="dt">Coord</span> <span class="ot">-&gt;</span> [<span class="dt">Coord</span>]) <span class="ot">-&gt;</span> <span class="dt">Grid</span> a <span class="ot">-&gt;</span> [a]</span></code></pre></div>
<p>Experiment uses a function which turns an index into a functor of
indexes, then runs it on the index in a store and extracts a value for
each index using fmap to replace each index with its value from the
store! A bit confusing perhaps, but it fits our use case perfectly!</p>
<p>Now we need a way to render our board to text!</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">render ::</span> <span class="dt">Grid</span> <span class="dt">Bool</span> <span class="ot">-&gt;</span> <span class="dt">String</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>render (<span class="dt">StoreT</span> (<span class="dt">Identity</span> (<span class="dt">Compose</span> g)) _) <span class="ot">=</span> <span class="fu">foldMap</span> ((<span class="op">++</span> <span class="st">&quot;\n&quot;</span>) <span class="op">.</span> <span class="fu">foldMap</span> (bool <span class="st">&quot;.&quot;</span> <span class="st">&quot;#&quot;</span>)) g</span></code></pre></div>
<p>First we're unpacking the underlying
<code>VBounded (VBounded a)</code>, then we convert each bool to a
representative string, fold those strings into lines, then fold those
lines into a single string by packing newlines in between.</p>
<p>We cleverly defined <code>mkGrid</code> earlier to take a list of
coords which were alive to define a board; if we make up some
interesting combinators we can make a little DSL for setting up a
starting grid!</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">at ::</span> [<span class="dt">Coord</span>] <span class="ot">-&gt;</span> <span class="dt">Coord</span> <span class="ot">-&gt;</span> [<span class="dt">Coord</span>]</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>at xs (x, y) <span class="ot">=</span> <span class="fu">fmap</span> ((<span class="op">+</span>x) <span class="op">***</span> (<span class="op">+</span>y)) xs</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>glider, blinker,<span class="ot"> beacon ::</span> [<span class="dt">Coord</span>]</span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>glider <span class="ot">=</span> [(<span class="dv">1</span>, <span class="dv">0</span>), (<span class="dv">2</span>, <span class="dv">1</span>), (<span class="dv">0</span>, <span class="dv">2</span>), (<span class="dv">1</span>, <span class="dv">2</span>), (<span class="dv">2</span>, <span class="dv">2</span>)]</span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>blinker <span class="ot">=</span> [(<span class="dv">0</span>, <span class="dv">0</span>), (<span class="dv">1</span>, <span class="dv">0</span>), (<span class="dv">2</span>, <span class="dv">0</span>)]</span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a>beacon <span class="ot">=</span> [(<span class="dv">0</span>, <span class="dv">0</span>), (<span class="dv">1</span>, <span class="dv">0</span>), (<span class="dv">0</span>, <span class="dv">1</span>), (<span class="dv">3</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>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a><span class="ot">start ::</span> <span class="dt">Grid</span> <span class="dt">Bool</span></span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a>start <span class="ot">=</span> mkGrid <span class="op">$</span></span>
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a>     glider <span class="ot">`at`</span> (<span class="dv">0</span>, <span class="dv">0</span>)</span>
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true" tabindex="-1"></a>  <span class="op">++</span> beacon <span class="ot">`at`</span> (<span class="dv">15</span>, <span class="dv">5</span>)</span>
<span id="cb7-13"><a href="#cb7-13" aria-hidden="true" tabindex="-1"></a>  <span class="op">++</span> blinker <span class="ot">`at`</span> (<span class="dv">16</span>, <span class="dv">4</span>)</span></code></pre></div>
<p>That's pretty slick if you ask me!</p>
<p>It's not terribly important, but here's the actual game loop if
you're interested:</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">import</span> <span class="dt">Conway</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Concurrent</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="ot">tickTime ::</span> <span class="dt">Int</span></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a>tickTime <span class="ot">=</span> <span class="dv">200000</span></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="ot">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> loop (step basicRule) start</span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a><span class="ot">loop ::</span> (<span class="dt">Grid</span> <span class="dt">Bool</span> <span class="ot">-&gt;</span> <span class="dt">Grid</span> <span class="dt">Bool</span>) <span class="ot">-&gt;</span> <span class="dt">Grid</span> <span class="dt">Bool</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> ()</span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a>loop stepper g <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb8-12"><a href="#cb8-12" aria-hidden="true" tabindex="-1"></a>  <span class="fu">putStr</span> <span class="st">&quot;\ESC[2J&quot;</span> <span class="co">-- Clear terminal screen</span></span>
<span id="cb8-13"><a href="#cb8-13" aria-hidden="true" tabindex="-1"></a>  <span class="fu">putStrLn</span> (render g)</span>
<span id="cb8-14"><a href="#cb8-14" aria-hidden="true" tabindex="-1"></a>  threadDelay tickTime</span>
<span id="cb8-15"><a href="#cb8-15" aria-hidden="true" tabindex="-1"></a>  loop stepper (stepper g)</span></code></pre></div>
<p>That's about it, hope you found something interesting!</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANkAAAAzCAYAAAAaYa2SAAAABGdBTUEAALGPC/xhBQAAC8VJREFUeAHtXQmwFMUZ/npmFpHzcQgBRSFcAnIfcimICEFEEFAEj5SlUMYkVTEKJpgQSSmSUGWMFimJUEQTFa8UEdAkGENEi0MBBQQMgiCX3Icc8t7MdP6/Z2d2dt/bdd/bHdis/Vc9tqePv3u+7r//ayzF2XvHSmjSCGgEIkPAiIyzZqwR0AgoBLSQ6YOgEYgYAS1kEQOs2WsEtJDpM6ARiBgBLWQRA6zZawS0kOkzoBGIGAEtZBEDrNlrBLSQ6TOgEYgYAS1kEQOs2WsEtJDpM6ARiBgBLWQRA6zZawS0kOkzoBGIGAEtZBEDrNlrBLSQ6TOgEYgYAS1kEQOs2WsErFwhKFlxKmAx+eIYHr60WvAcFBo3hXn1UBjtOgIlDYCyMsj9e+CuWwX3vbfpuTToqgsagWJDIGchs90EJE6iGJTMEeNgDL0JwjSDOlwIiDp1YbRuDzlkJOy5v4PctiXRrksagSJCIFJz0Rw/Eeb1Y5MFLAU8UVIf1k+mQbRql9KiHzUCxYFAZEImuvYmE3FIVigJKwbrnvuBC6pn1f+cd2rYGIK0LupfRCpYZJ6e3kU0awHRvFXhvk/mN/j/bi1A/HM2F9PtiDXilnRNFdaLuvVgkFC6S9+osD1TpfXwLBiXNE/qItnPO3yQ/L6VcP6xEDj7NdCoCapNfyqpX/jBWbEMzvOzvSrDhDl8LIxBwyGqk30bJ3nkEJxFL8Nducyv8n7rNYQ1YSJE+84QNJZJSgm5/b9wXpwDuXeX14/+Da9XOg7KptwNnE74tubNd8EcdH3Q3573JNwP36/c+oPRyQVz+M0wb/D2Rp46ibKfTQRsO7lTypPxvdGwRo5PqpUuOQeHDsD9dAOcxa8CJ44F7enmEC1aIzZlRtAvXaH0wbtgXDWk/JyEFY4egvv5VjhLaM79exMsqoi/vfAFuHw+4mQMHQVr1G3qqfQ+won2MFeKRpNRoEM0aVbptRldrqz0mPAA3nh5aD/kscMQsWoQ37kY5rAxsO68L9xNlaVjQ5Lghf9gl3n9DAPWA9M9U5cETLou5NdnVJuoT8L0/R/CuGZYwFM0vRSxaU/AuKKbEjB58ivI40dJ6QkYLdvC+vlvINp1CvqHC+yrGh27h6vKPSc1xh8yrr+iAfE6o8/AoFXUrAWjU8/gOZsCC6b86jhpdAOCLi2ThCE25TGgRs1geK5zBIziBcaS9xW0D4KsCrNnf8Qeehxo0Ej1yAV/ky4Q0AUfJUWiyfhwV4WqOi6Y6/gxlP3yR94jbUaMNBxrIdG5F2Amv6q77O9wXnsuGBouGAOHwfhuW1XlrF5OmuiPKgIqOnSBNfEBJcDm6DvgkuYDCZ85YZKah7WS86enPa1Do8XlHWFNehDiwhqk5Sah7Nc/TYqk8mEVtSkA1KUX3FXvqvlEk0sgLmoMeYLaKDiUjjKtP90YNnkFHUx1Ga1fo+Y1+lwDd+2KdEPK1duzZ0CSJgGt27r1Hhjdeiueis+/FiuzOt0ccuc2lE4mrR2n2CO/Bws6ayb7DzP9aoAEOUz2nFnenHRxmjfeCnPwCIWp2W8QnDcWVBl/noPPhzn6djjznw5PmddyJJqMfawqkZUsCFXi4Q86fAA4c1o9STYrSHNlSyaZiEwsBM5fnvFMTdZmG9YqYZBnTkHu3K6EQVzWUmkr7u+u+k8gYGr8lg1w6eAx8Q2cqrHUYeW29l0AOkCqX1yryR10kPNMLAhMPK+zOi7U7UnD1imp/EyMTchk5ouBKeMchCFOnkj8+aYY7024Pt1qyAVwN65NtNaohZzw/3KP4mX2uhoifqkmmOevlMdTnViUPHIw8VCZEvk7ORFpDPOm28npoeBD2ysg6jWA8qFenV+OrdGha7nD5S57C3LPFxTgaKj6q7RCSg7PeWkunBfmBPyM3gODsty8Pij7BZcEzfeBRFMyoUNaw6WbnQ8J+6NsTsr1H5L51kMNdT9ZF5R9XuHftOsnH7BCoqASax0md80KyI3rlKksuP7KAeQL/63CYWkra9WB2XdQ0Cz37laBnrzO4XOnfQULFGl5k9JBPrmbPkpySyqN/56dEHQBG517whx3N+yZD/ms8/objZDt2Ab2S0St2pVaLB+sXEipfsq7hYk3Ihx08NuUv5Zi1soNayApAMG+FJPyPfwB/i87/GGKCyRXVdQ/qS7UV7Ggm9wlwTKvuk5ttLPtU4gWbSBLz1JAYWN4lnLltOtPI2QGRXtZoDgYo8xD1go8N/k3Jvlp2QqZdS8dRNY8fDGQ78okSSNwIMjo1icvc6S+bOzHv0itgrP8n5CfkJBRoMKnJKzjlUl1KfgLCNivP48YuQHGpS1g9Bvss8rrbyRCRkY/nHeWwCL7OVuSFHRwSJPkQuzHsM/AxBqCE+Fm/8EUkOiKsqk/SGLNX5s47y1NqpO7d3qmYbxW1KWvU1KJ0wwc5fKDJOyQx4lzfqmxKNZSPinn3X+I/7off+AJGWkwuXWTOris/VBK0dEMlHb9acYYfT1Tkc0yX/uKmGfWKz/wslZkAn+WZnSoujq9P5t9ZDK7FL2VW9ZDRW/pYsjbHKHpuOiy6Ux4GG06qBbPT37W65Uj/jj4Jdy3F4EDIOaN4+C+m3wmvEly+zcaIaM1cSje7dQdRvPWWa3QWfiiCgln1TldJ44YfrFdtfKv4M+5rr0Bgj7lEi0vp2DCsWAkm7Ry08fBc7ggj1J0kkxN0aa9MlNw+mTQbI65kw7TIDIrd8JZMA9yXyI0L9ifigcw/AFhP6wijSopBM6RS0Hml+/PuOT7fRNlWn+5sQ0bBcl+DrRYoyaU68IRQScLIbOfnO4FIVI55HGOVNbOK/PVnNb9jyhB40CRU7c+cPxIzvjzXM5bf6WLZ4A6J0afAanT5/zs6fuc2VTAgG56e/ZMuN/wuRSbLzZFiPwAQQWcqlZFiWOO7iUoVcckWlJLzr/fVFVsfqokOQkcKChjdO+rtACH3dlcYwGTu3ZAaR4awSaZ0f86UqOeuSlIOxkDhipebFJx4KQcUY7KF3b/pnY3rinXLZcKk/xGNoE5FWGTP2k/Nzv4C9beo596x6rOcy7m4Pwkk6h2AVkpt6hyzvgzF9LCzut/VvwEf3CQZ4pMk6l1kmliP/ErsnWvhUl5pXDujM1DdlSdJa9lZ6Zk8+J1SxB7nIISdKDCZppLWk1u3wrQbesTJ5nDuS6ul+QH2U89CvedN+H26O/Z6RSQqDbjGUj6qNk3r7iv89KzKnzPZXvBXMQmP0rh6NqwbpsEOeYOleD1fVJOjNucBkgT4XTXf5AISuz6HDh2BKDkaibKtP7UcXxLM3EgR32QHerAkVKDLiM/Z1aZcH6IjdIEUc8hP9usLjRer9K8ZOaBLq9c8ed1c7LfpY8h+HvafFO0QqZW78JdvlT9KWeZv8K3SyHpawH1FUYe30h9aUF+ERPnrEBhfJdMQmfxK4RicsBCBTeEmTS7pASrIhIGe9ZUstHHk2YarHIyvoBxOoC/EpAfrU6MpTrOgXHeSHSkhDRpQCaVj9q62ROwA/sS/VNKbB5yX16/DIeoU/qFHzOuP9RRkB/DeSsmd+3KUItX5OCBMldpzSrXFYp+luucpuJczOFP7Sxa4F0KhJU1cgI4h8ZffuSCf8D75XkQU3+r9sGvy8evyPV/nVTr/cTnQFOaxTCtov/UJR8rPZ882PQsqQdJjj7o64OMRBE39gXZvJT7KA/jB0gyDtKNeUOgAPGPXpPlDb3zyIiDJNnm/jhpvW/3eVzst3zqAsQ/usDHt3yv9etrBHwEtJD5SOhfjUBECORsLp7sVzOipWm2GoHiQEBrsuLYR/0WBYyAFrIC3hy9tOJAQAtZceyjfosCRkALWQFvjl5acSCghaw49lG/RQEjoIWsgDdHL604ENBCVhz7qN+igBHQQlbAm6OXVhwIaCErjn3Ub1HACGghK+DN0UsrDgS0kBXHPuq3KGAEtJAV8ObopRUHAlrIimMf9VsUMAJayAp4c/TSigMBLWTFsY/6LQoYgf8BIVTf3IgGuLEAAAAASUVORK5CYII=" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Radix Sort, Trie Trees, and Maps from Representable Functors</title>
      <link href="https://chrispenner.ca/posts/representable-discrimination"/>
      <id>https://chrispenner.ca/posts/representable-discrimination</id>
      <updated>2017-07-23T00:00:00Z</updated>
      <summary>Representable Functors can be used to create Map-like data structures or
perform Radix-like sorts.</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/containers.jpg" alt="Radix Sort, Trie Trees, and Maps from Representable Functors">
              <p>I recommend you follow along in ghci and experiment with things as
you go; There's a Literate Haskell version of this post <a
href="https://gist.github.com/ChrisPenner/eb6a4efa0d57f39dc5f3c7bb2d31c2d7">here</a>,
you can load it straight into ghci!</p>
<p>Looking at my recent posts it's clear I've been on a bit of a
Representable kick lately; turns out there's a lot of cool things you
can do with it! We'll be adding 'sorting' to that list of things today.
Representable Functors bring with them an intrinsic notion of sorting;
not in the traditional 'ordered' sense, but rather a sense of
'structural' sorting. Since every 'slot' in a Representable Functor
<code>r</code> can be uniquely identified by some <code>Rep r</code> we
can talk about sorting items into some named slot in <code>r</code>. If
we like we can also define <code>Ord (Rep r)</code> to get a total
ordering over the slots, but it's not required.</p>
<p>I'll preface this post by saying I'm more interested in exploring the
structural 'form' of representable sorting than the performance of the
functions we'll define, in fact the performance of some of them as
they're written here is going to be quite poor as I'm sacrificing speed
to gain simplicity for the sake of pedagogy. The intent is to observe
the system from a high-level to see some interesting new patterns and
shapes we gain from using Representable to do our sorting. Most of the
structures we build could quite easily be optimized to perform
reasonably if one was so inclined.</p>
<h2 id="building-up-sorting-over-representable">Building up Sorting over
Representable</h2>
<p>I'll step through my thought process on this one:</p>
<p>We've got a Representable Functor <code>r</code>; If we have a
<code>Rep r</code> for some <code>a</code> we know which slot to put it
into in an <code>r a</code>. We can get a <code>Rep r</code> for every
<code>a</code> by using a function <code>a -&gt; Rep r</code>. Now we
want to embed the <code>a</code> into an <code>r a</code> using the
<code>Rep r</code>, the tool we have for this is <code>tabulate</code>,
in order to know which index is which and put it into the right slot
we'll need to require <code>Eq (Rep r)</code>. We know which slot our
one element goes to, but we need something to put into all the other
slots. If <code>a</code> were a Monoid we could use <code>mempty</code>
for the other slots; then if we map that function over every element in
an input list we could build something 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="dt">Representable</span> r, <span class="dt">Monoid</span> a, <span class="dt">Eq</span> (<span class="dt">Rep</span> r)) <span class="ot">=&gt;</span> (a <span class="ot">-&gt;</span> <span class="dt">Rep</span> r) <span class="ot">-&gt;</span> [a] <span class="ot">-&gt;</span> [r a]</span></code></pre></div>
<p>We want a single <code>r a</code> as a result rather than a list, so
we need to collapse <code>[r a]</code>. We could use
<code>mconcat</code> if <code>r a</code> was a Monoid! We can actually
write a monoid instance for any representable if the inner
<code>a</code> type also has a Monoid instance, later we'll define a
custom newtype wrapper with that instance! This gives:</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="dt">Representable</span> r, <span class="dt">Monoid</span> a, <span class="dt">Eq</span> (<span class="dt">Rep</span> r)) <span class="ot">=&gt;</span> (a <span class="ot">-&gt;</span> <span class="dt">Rep</span> r) <span class="ot">-&gt;</span> [a] <span class="ot">-&gt;</span> r a</span></code></pre></div>
<p>We can generalize the list to any foldable by just calling
<code>Data.Foldable.toList</code> on it, and we get:</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="dt">Representable</span> r, <span class="dt">Monoid</span> a, <span class="dt">Foldable</span> f, <span class="dt">Eq</span> (<span class="dt">Rep</span> r)) <span class="ot">=&gt;</span> (a <span class="ot">-&gt;</span> <span class="dt">Rep</span> r) <span class="ot">-&gt;</span> f a <span class="ot">-&gt;</span> r a</span></code></pre></div>
<p>Nifty! But this requires that every <code>a</code> type we want to
work is also a Monoid, that's going to seriously limit the usecases for
this. We can increase the utility by allowing the caller to specifying a
way to build a Monoid from an <code>a</code>:</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="dt">Representable</span> r, <span class="dt">Monoid</span> m, <span class="dt">Foldable</span> f, <span class="dt">Eq</span> (<span class="dt">Rep</span> r)) <span class="ot">=&gt;</span> (a <span class="ot">-&gt;</span> <span class="dt">Rep</span> r) <span class="ot">-&gt;</span> (a <span class="ot">-&gt;</span> m) <span class="ot">-&gt;</span> f a <span class="ot">-&gt;</span> r m</span></code></pre></div>
<p>And that's our final fully generalized type signature!</p>
<p>We're going to need a bunch of imports before we start implementing
things, prepare yourself:</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">{-# language DeriveFunctor #-}</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# language TypeFamilies #-}</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# language MultiParamTypeClasses #-}</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# language FlexibleInstances #-}</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# language ScopedTypeVariables #-}</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# language FlexibleContexts #-}</span></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# OPTIONS_GHC -fno-warn-orphans #-}</span></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a><span class="kw">module</span> <span class="dt">RepSort</span> <span class="kw">where</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="kw">import</span> <span class="dt">Data.Distributive</span> (<span class="dt">Distributive</span>(..))</span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Functor.Rep</span> (<span class="dt">Representable</span>(..), <span class="dt">Co</span>(..), distributeRep)</span>
<span id="cb5-14"><a href="#cb5-14" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Monoid</span> (<span class="dt">Sum</span>(..))</span>
<span id="cb5-15"><a href="#cb5-15" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Data.Stream.Infinite</span> <span class="kw">as</span> <span class="dt">S</span> (<span class="dt">Stream</span>, iterate)</span>
<span id="cb5-16"><a href="#cb5-16" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Comonad.Cofree</span> (<span class="dt">Cofree</span>)</span>
<span id="cb5-17"><a href="#cb5-17" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Data.Sequence</span> <span class="kw">as</span> <span class="dt">Seq</span> (<span class="dt">Seq</span>, fromList)</span></code></pre></div>
<p>So here's my implementation for <code>repSort</code>:</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="co">-- Firstly, the signature we came up with:</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="ot">repSort ::</span> (<span class="dt">Representable</span> r, <span class="dt">Monoid</span> m, <span class="dt">Foldable</span> f, <span class="dt">Eq</span> (<span class="dt">Rep</span> r)) <span class="ot">=&gt;</span> (a <span class="ot">-&gt;</span> <span class="dt">Rep</span> r) <span class="ot">-&gt;</span> (a <span class="ot">-&gt;</span> m) <span class="ot">-&gt;</span> f a <span class="ot">-&gt;</span> r m</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>repSort indOf toM <span class="ot">=</span> unMRep <span class="op">.</span> <span class="fu">foldMap</span> (<span class="dt">MRep</span> <span class="op">.</span> tabulate <span class="op">.</span> desc)</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- desc takes an &#39;a&#39; from the foldable and returns a descriptor function which can be passed to &#39;tabulate&#39;,</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- The descriptor just returns mempty unless we&#39;re on the slot where the &#39;a&#39;s result is supposed to end up.</span></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a>    desc a i</span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a>      <span class="op">|</span> i <span class="op">==</span> indOf a <span class="ot">=</span> toM a</span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a>      <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="fu">mempty</span></span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a><span class="co">-- Here&#39;s our newtype with a Monoid over Representables</span></span>
<span id="cb6-13"><a href="#cb6-13" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">MRep</span> r a <span class="ot">=</span> <span class="dt">MRep</span> {<span class="ot">unMRep ::</span>r a}</span>
<span id="cb6-14"><a href="#cb6-14" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>, <span class="dt">Functor</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">instance</span> (<span class="dt">Monoid</span> a, <span class="dt">Representable</span> r) <span class="ot">=&gt;</span> <span class="dt">Monoid</span> (<span class="dt">MRep</span> r a) <span class="kw">where</span></span>
<span id="cb6-17"><a href="#cb6-17" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- The empty Representable is filled with mempty</span></span>
<span id="cb6-18"><a href="#cb6-18" aria-hidden="true" tabindex="-1"></a>  <span class="fu">mempty</span> <span class="ot">=</span> <span class="dt">MRep</span> <span class="op">$</span> tabulate (<span class="fu">const</span> <span class="fu">mempty</span>)</span>
<span id="cb6-19"><a href="#cb6-19" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- We can just tabulate a new representable where the value is the `mappend` of</span></span>
<span id="cb6-20"><a href="#cb6-20" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- the other two representables. BTW (index a `mappend` index b) depends on</span></span>
<span id="cb6-21"><a href="#cb6-21" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- the monoid instance for functions, so go check that out if you haven&#39;t seen it!</span></span>
<span id="cb6-22"><a href="#cb6-22" aria-hidden="true" tabindex="-1"></a>  (<span class="dt">MRep</span> a) <span class="ot">`mappend`</span> (<span class="dt">MRep</span> b) <span class="ot">=</span> <span class="dt">MRep</span> <span class="op">.</span> tabulate <span class="op">$</span> <span class="fu">index</span> a <span class="ot">`mappend`</span> <span class="fu">index</span> b</span></code></pre></div>
<h2 id="using-repsort">Using <code>repSort</code></h2>
<p>Great! Let's see some examples so we can get a handle on what this
does! First I'll set up a super simple but useful Representable for
Pair:</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="kw">data</span> <span class="dt">Pair</span> a <span class="ot">=</span> <span class="dt">Pair</span> a a</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>, <span class="dt">Functor</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="co">-- This instance is required, but we can just lean on our Representable instance</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a><span class="co">-- `Data.Functor.Rep` provides all sorts of these helpers.</span></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Distributive</span> <span class="dt">Pair</span> <span class="kw">where</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a>  distribute <span class="ot">=</span> distributeRep</span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Representable</span> <span class="dt">Pair</span> <span class="kw">where</span></span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- Bool is a great index for this!</span></span>
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a>  <span class="kw">type</span> <span class="dt">Rep</span> <span class="dt">Pair</span> <span class="ot">=</span> <span class="dt">Bool</span></span>
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true" tabindex="-1"></a>  <span class="fu">index</span> (<span class="dt">Pair</span> a _) <span class="dt">True</span> <span class="ot">=</span> a</span>
<span id="cb7-13"><a href="#cb7-13" aria-hidden="true" tabindex="-1"></a>  <span class="fu">index</span> (<span class="dt">Pair</span> _ b) <span class="dt">False</span> <span class="ot">=</span> b</span>
<span id="cb7-14"><a href="#cb7-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-15"><a href="#cb7-15" aria-hidden="true" tabindex="-1"></a>  tabulate desc <span class="ot">=</span> <span class="dt">Pair</span> (desc <span class="dt">True</span>) (desc <span class="dt">False</span>)</span></code></pre></div>
<p>So since Pair is indexed by a <code>Bool</code> the
<code>a -&gt; Rep Pair</code> is actually just a predicate
<code>a -&gt; Bool</code>! Let's try sorting out some odd and even
integers!</p>
<p>Remember that <code>repSort</code> needs a function from
<code>a -&gt; Rep r</code>, in this case <code>Rep r ~ Bool</code>
(<code>~</code> means 'is equal to' when we're talking about types), so
we can use <code>odd</code> to split the odd and even integers up! Next
it needs a function which transforms an <code>a</code> into a monoid!
The simplest one of these is <code>(:[])</code> which just puts the
element into a list! Let's see what we get!</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">sortedInts ::</span> <span class="dt">Pair</span> [<span class="dt">Int</span>]</span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>sortedInts <span class="ot">=</span> repSort <span class="fu">odd</span> (<span class="op">:</span>[]) [<span class="dv">1</span><span class="op">..</span><span class="dv">10</span>]</span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> sortedInts</span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Pair</span> [<span class="dv">1</span>,<span class="dv">3</span>,<span class="dv">5</span>,<span class="dv">7</span>,<span class="dv">9</span>] [<span class="dv">2</span>,<span class="dv">4</span>,<span class="dv">6</span>,<span class="dv">8</span>,<span class="dv">10</span>]</span></code></pre></div>
<p>We used lists in the last example, but remember that the function is
generalized over that parameter so we can actually choose any Monoid we
like! Let's say we wanted the sums of all odd and even ints respectively
between 1 and 10:</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">oddEvenSums ::</span> <span class="dt">Pair</span> (<span class="dt">Sum</span> <span class="dt">Int</span>)</span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>oddEvenSums <span class="ot">=</span> repSort <span class="fu">odd</span> <span class="dt">Sum</span> [<span class="dv">1</span><span class="op">..</span><span class="dv">10</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="op">&gt;</span> oddEvenSums</span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Pair</span> (<span class="dt">Sum</span> {getSum <span class="ot">=</span> <span class="dv">25</span>}) (<span class="dt">Sum</span> {getSum <span class="ot">=</span> <span class="dv">30</span>})</span></code></pre></div>
<p>Choosing our own monoid and index function gives us a lot of
flexibility and power!</p>
<p>This pattern generalizes to any Representable you can think of, and
most Representables which have an interesting <code>Rep r</code> will
have some sort of cool structure or use-case! Think about some other
Representables and see what you can come up with!</p>
<h2 id="indexing-by-integers-using-stream">Indexing by Integers using
Stream</h2>
<p>Let's try another Functor and see what happens, here we'll go with an
infinite <code>Stream</code> from <a
href="http://hackage.haskell.org/package/streams-3.3/docs/Data-Stream-Infinite.html">Data.Stream.Infinite</a>
in the <a href="http://hackage.haskell.org/package/streams">streams
package</a>, whose representation is <code>Int</code>, that is;
<code>Rep Stream ~ Int</code>.</p>
<p>With a representation type of <code>Int</code> we could do all sorts
of things! Note here how the Functor (<code>Stream</code>) is infinite,
but the representable is actually bounded by the size of Int. This is
fine as long as we don't try fold the result or get every value out of
it in some way, we'll primarily be using the <code>index</code> function
from <code>Representable</code> so it should work out okay.</p>
<p>The streams are infinite, but Haskell's inherent laziness helps us
out in handling this, not only can we represent infinite things without
a problem, Haskell won't actually calculate the values stored in any
slots where we don't look, and since the whole thing is a data structure
any computations that do occur are automatically memoized! This also
means that you don't pay the cost for any value transformation or
monoidal append unless you actually look inside the bucket. Only the
initial <code>a -&gt; Rep r</code> must be computed for each
element.</p>
<p>Let's sort some stuff! See if you can figure this one out:</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">byLength ::</span> <span class="dt">S.Stream</span> [<span class="dt">String</span>]</span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>byLength <span class="ot">=</span> repSort <span class="fu">length</span> (<span class="op">:</span>[]) [<span class="st">&quot;javascript&quot;</span>, <span class="st">&quot;purescript&quot;</span>, <span class="st">&quot;haskell&quot;</span>, <span class="st">&quot;python&quot;</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="op">&gt;</span> <span class="fu">index</span> byLength <span class="dv">10</span></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>[<span class="st">&quot;javascript&quot;</span>,<span class="st">&quot;purescript&quot;</span>]</span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> <span class="fu">index</span> byLength <span class="dv">7</span></span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a>[<span class="st">&quot;haskell&quot;</span>]</span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> <span class="fu">index</span> byLength <span class="dv">3</span></span>
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a>[]</span></code></pre></div>
<p>We didn't have to change our implementation of repSort at all!
<code>index</code> knows how to find values in a <code>Stream</code>
from an <code>Int</code> and all of that complexity is taken care of for
us in the instance of <code>Representable</code>.</p>
<p>The fact that <code>Int</code> is the <code>Rep</code> for Stream
provides us with a few quick wins, any Enumerable type can be injected
into <code>Int</code> via <code>fromEnum</code> from the Prelude:
<code>fromEnum: (Enum e) =&gt; e -&gt; Int</code>. This means we can
turn any Enumerable type into an index into <code>Stream</code> without
much trouble and we gain a whole new set of possibilities:</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">byFirstChar ::</span> <span class="dt">S.Stream</span> [<span class="dt">String</span>]</span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- We get the Int value from the first char of a string and use that as the index!</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>byFirstChar <span class="ot">=</span> repSort (<span class="fu">fromEnum</span> <span class="op">.</span> <span class="fu">head</span>) (<span class="op">:</span>[]) [<span class="st">&quot;cats&quot;</span>, <span class="st">&quot;antelope&quot;</span>, <span class="st">&quot;crabs&quot;</span>, <span class="st">&quot;aardvarks&quot;</span>]</span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> <span class="fu">index</span> byFirstChar <span class="op">.</span> <span class="fu">fromEnum</span> <span class="op">$</span> <span class="ch">&#39;c&#39;</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>[<span class="st">&quot;cats&quot;</span>,<span class="st">&quot;crabs&quot;</span>]</span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> <span class="fu">index</span> byFirstChar <span class="op">.</span> <span class="fu">fromEnum</span> <span class="op">$</span> <span class="ch">&#39;a&#39;</span></span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a>[<span class="st">&quot;antelope&quot;</span>,<span class="st">&quot;aardvarks&quot;</span>]</span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> <span class="fu">index</span> byFirstChar <span class="op">.</span> <span class="fu">fromEnum</span> <span class="op">$</span> <span class="ch">&#39;z&#39;</span></span>
<span id="cb11-10"><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a>[]</span></code></pre></div>
<p>So that's all pretty cool, but working with a single infinite stream
gets unwieldy quickly when we start dealing with indexes in the
thousands! <code>Stream</code> is effectively a linked list, so we need
to step along the nodes until we reach our index every time we look
something up! Maybe we can do better on that somehow...</p>
<p>Straying a bit from sorting into the idea of data storage let's say
we wanted to store values in a structure where they're keyed by a
<code>String</code>. The first step would be to find a Representable
whose index type could be a <code>String</code>. Hrmm, our
<code>Stream</code> representation can index by <code>Char</code>, which
is close; what if we nested further representables and used a 'path' to
the value as the index? Something like
<code>Stream (Stream (Stream ...))</code>. This looks like an infinite
tree of trees at this point; but has the issue that we never actually
make it to any <code>a</code>s! Whenever I think of tagging a tree-like
structure with values I go straight to Cofree, let's see how it can
help.</p>
<h2 id="diving-into-tries-using-cofree">Diving into Tries using
Cofree</h2>
<p>One way you could think of Cofree is as a Tree where every branch and
node has an annotation <code>a</code> and the branching structure is
determined by some Functor! For example, a simple Rose tree is
isomorphic to <code>Cofree [] a</code>, <code>Cofree Maybe a</code>
makes a degenerate tree with only single branches, etc.</p>
<p>We want a tree where the branching structure is indexed by a
<code>String</code>, so let's give <code>Cofree Stream a</code> a try!
Effectively this creates an infinite number of branches at every level
of the tree, but in practice we'll only actually follow paths which are
represented by some string that we're indexing with, the rest of the
structure will be never be evaluated!</p>
<p>As it turns out, we made a good choice! <code>Cofree r a</code> is
Representable whenever <code>r</code> is Representable, but which type
indexes into it? The Representable instance for Cofree (defined in <a
href="http://hackage.haskell.org/package/free-4.12.4/docs/Control-Comonad-Cofree.html">Control.Comonad.Cofree</a>
from the <a href="http://hackage.haskell.org/package/free">free</a>
package) It relies on the underlying Representable Index, but since the
tree could have multiple layers it needs a sequence of those indexes!
That's why the index type for <code>Cofree</code> of a Representable is
<code>Seq (Rep r)</code>, when we index into a <code>Cofree</code> we
follow one index at a time from the Sequence of indexes until we reach
the end, then we return the value stored at that position in the tree!
Under the hood the <code>Rep</code> for our structure is going to be
specialized to <code>Seq Int</code>, but we can easily write
<code>mkInd :: String -&gt; Seq Int</code> to index by Strings!</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">mkInd ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Seq.Seq</span> <span class="dt">Int</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>mkInd <span class="ot">=</span> Seq.fromList <span class="op">.</span> <span class="fu">fmap</span> <span class="fu">fromEnum</span></span></code></pre></div>
<p>Great! Now we can 'sort' values by strings and index into a tree
structure (pseudo) performantly! If this whole sort of structure is
looking a bit familiar you've probably seen it by the name of a <a
href="https://en.wikipedia.org/wiki/Trie">"Trie Tree"</a>, a
datastructure often used in <a
href="https://en.wikipedia.org/wiki/Radix_sort">Radix sorts</a> and
search problems. Its advantage is that it gives <code>O(m)</code>
lookups where <code>m</code> is the length of the key string, in our
case it will be slightly slower than the traditional method since we
don't have <code>O(1)</code> random memory access, and have to move
through each child tree to the appropriate place before diving deeper,
but you could fix that pretty easily by using a proper
<code>Vector</code> as the underlying representation rather than
<code>Stream</code>. I'll leave that one as an exercise for the
reader.</p>
<h2 id="building-maps-from-tries">Building Maps from Tries</h2>
<p>That's a whole lot of explaining without any practical examples, so I
bet you're itching to try out our new Trie-based Sorter/Map! With a few
helpers we can build something quickly!</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="co">-- I&#39;m going to specialize the signature to `Cofree Stream` to make it a bit more</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- readable, but you could re-generalize this idea if you wanted to.</span></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a><span class="ot">trieSort ::</span> (<span class="dt">Monoid</span> m, <span class="dt">Foldable</span> f) <span class="ot">=&gt;</span> (a <span class="ot">-&gt;</span> <span class="dt">String</span>) <span class="ot">-&gt;</span> (a <span class="ot">-&gt;</span> m) <span class="ot">-&gt;</span> f a <span class="ot">-&gt;</span> <span class="dt">Cofree</span> <span class="dt">S.Stream</span> m</span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>trieSort getInd <span class="ot">=</span> repSort (mkInd <span class="op">.</span> getInd)</span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a><span class="co">-- Build a map out of some key and a Monoidal value!</span></span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a><span class="ot">trieMap ::</span> <span class="dt">Monoid</span> m <span class="ot">=&gt;</span> [(<span class="dt">String</span>, m)] <span class="ot">-&gt;</span> <span class="dt">Cofree</span> <span class="dt">S.Stream</span> m</span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a>trieMap <span class="ot">=</span> trieSort <span class="fu">fst</span> <span class="fu">snd</span></span>
<span id="cb13-9"><a href="#cb13-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-10"><a href="#cb13-10" aria-hidden="true" tabindex="-1"></a><span class="ot">get ::</span> <span class="dt">Cofree</span> <span class="dt">S.Stream</span> a <span class="ot">-&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> a</span>
<span id="cb13-11"><a href="#cb13-11" aria-hidden="true" tabindex="-1"></a>get r ind <span class="ot">=</span> <span class="fu">index</span> r (mkInd ind)</span>
<span id="cb13-12"><a href="#cb13-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-13"><a href="#cb13-13" aria-hidden="true" tabindex="-1"></a><span class="ot">bankAccounts ::</span> <span class="dt">Cofree</span> <span class="dt">S.Stream</span> (<span class="dt">Sum</span> <span class="dt">Int</span>)</span>
<span id="cb13-14"><a href="#cb13-14" aria-hidden="true" tabindex="-1"></a>bankAccounts <span class="ot">=</span> trieMap [(<span class="st">&quot;Bob&quot;</span>, <span class="dt">Sum</span> <span class="dv">37</span>), (<span class="st">&quot;Sally&quot;</span>, <span class="dv">5</span>)]</span>
<span id="cb13-15"><a href="#cb13-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-16"><a href="#cb13-16" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> get bankAccounts <span class="st">&quot;Bob&quot;</span></span>
<span id="cb13-17"><a href="#cb13-17" aria-hidden="true" tabindex="-1"></a><span class="dt">Sum</span> {getSum <span class="ot">=</span> <span class="dv">37</span>}</span>
<span id="cb13-18"><a href="#cb13-18" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> get bankAccounts <span class="st">&quot;Sally&quot;</span></span>
<span id="cb13-19"><a href="#cb13-19" aria-hidden="true" tabindex="-1"></a><span class="dt">Sum</span> {getSum <span class="ot">=</span> <span class="dv">5</span>}</span>
<span id="cb13-20"><a href="#cb13-20" aria-hidden="true" tabindex="-1"></a><span class="co">-- Empty keys are mempty</span></span>
<span id="cb13-21"><a href="#cb13-21" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> get bankAccounts <span class="st">&quot;Edward&quot;</span></span>
<span id="cb13-22"><a href="#cb13-22" aria-hidden="true" tabindex="-1"></a><span class="dt">Sum</span> {getSum <span class="ot">=</span> <span class="dv">0</span>}</span>
<span id="cb13-23"><a href="#cb13-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-24"><a href="#cb13-24" aria-hidden="true" tabindex="-1"></a><span class="ot">withdrawals ::</span> <span class="dt">Cofree</span> <span class="dt">S.Stream</span> (<span class="dt">Sum</span> <span class="dt">Int</span>)</span>
<span id="cb13-25"><a href="#cb13-25" aria-hidden="true" tabindex="-1"></a>withdrawals <span class="ot">=</span> trieMap [(<span class="st">&quot;Bob&quot;</span>, <span class="dt">Sum</span> (<span class="op">-</span><span class="dv">10</span>))]</span>
<span id="cb13-26"><a href="#cb13-26" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-27"><a href="#cb13-27" aria-hidden="true" tabindex="-1"></a><span class="co">-- And of course we can still make use of our MRep helper to combine maps!</span></span>
<span id="cb13-28"><a href="#cb13-28" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> get (unMRep <span class="op">$</span> <span class="dt">MRep</span> bankAccounts <span class="ot">`mappend`</span> <span class="dt">MRep</span> withdrawals ) <span class="st">&quot;Bob&quot;</span></span>
<span id="cb13-29"><a href="#cb13-29" aria-hidden="true" tabindex="-1"></a><span class="dt">Sum</span> {getSum <span class="ot">=</span> <span class="dv">27</span>}</span></code></pre></div>
<p>There are TONS of other possibilities here, we can swap out the
underlying Representable to get new behaviour and performance, we can
use <code>Data.Functor.Compose</code> to nest multiple
<code>Representable</code>s to build new and interesting structures! We
can sort, store, lookup and search using <code>repSort</code>!</p>
<p>Let me know which interesting ideas you come up with! Either leave a
comment here or find me on Twitter <a
href="https://twitter.com/chrislpenner">\@chrislpenner</a>.</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Free and Forgetful Functors</title>
      <link href="https://chrispenner.ca/posts/free-forgetful-functors"/>
      <id>https://chrispenner.ca/posts/free-forgetful-functors</id>
      <updated>2017-07-20T00:00:00Z</updated>
      <summary>Building adjunctions from Free and Forgetful Functors</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/books.jpg" alt="Free and Forgetful Functors">
              <p>Today I'm going to continue the previous topic of Adjunctions, <a
href="/posts/adjunction-battleship">last time</a> we talked about how
you can build a sensible adjunction from any Representable functor, this
time we're going to talk about a (semantically) different form of
adjunction, one formed by a pair of Free and Forgetful Functors. First
I'll describe the relationship of Free and Forgetful Functors, then
we'll see how an Adjunction can making translating between them slightly
easier.</p>
<p>Let's define our terms, hopefully you already know what a Functor is,
it's any type with a <code>map</code> method (called <code>fmap</code>
in Haskell). A Free Functor is a functor which can embed any element
"for free". So any Functor where we could just 'inject' a value into is
considered a Free Functor. If the functor has an Applicative instance
then <code>inject</code> is called <code>pure</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">inject ::</span> a <span class="ot">-&gt;</span> f a</span></code></pre></div>
<p>To do this maybe it means we make up some of the structure, or have
some default values we use in certain parts. Let's see some contrived
examples of Free Functors.</p>
<p>Simple single slot functors like Identity:</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>inject a <span class="ot">=</span> <span class="dt">Identity</span> a</span></code></pre></div>
<p>Simple structures like List or Maybe or Either:</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>inject a <span class="ot">=</span> [a]</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>inject a <span class="ot">=</span> <span class="dt">Just</span> a</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>inject a <span class="ot">=</span> <span class="dt">Right</span> a</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>inject a <span class="ot">=</span> <span class="dt">Pair</span> a a</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>inject a <span class="ot">=</span> <span class="fu">repeat</span> a</span></code></pre></div>
<p>Or even anything paired with a monoid, since we can 'make up' the
monoid's value using mempty.</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">inject ::</span> <span class="dt">Monoid</span> t <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">Tagged</span> t a</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>inject a <span class="ot">=</span> <span class="dt">Tagged</span> <span class="fu">mempty</span> a</span></code></pre></div>
<p>Note however that some of these Free functors are unsuitable for use
with adjunctions since <em><em>Sum</em></em> types like Maybe, List and
Either aren't Distributive because the number of <code>a</code> slots in
the functor can change between values.</p>
<p>Next we need the forgetful functor, this is a functor which 'loses'
or 'forgets' some data about some other functor when we wrap it. The
idea is that for each pair of Free and Forgetful functors there's a
Natural Transformation to the Identity Functor:
<code>Forget (Free a) ~&gt; Identity a</code>; and since there's an
isomorphism <code>Identity a ≅ a</code> we end up with something like
<code>Forget (Free a) ~&gt; a</code>. This expresses that when we forget
a free functor we end up back where we started.</p>
<p>Let's see what 'forgetting' the info from a Free functor looks like
by implementing <code>forget :: Free a -&gt; a</code> for different Free
functors.</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="co">-- Identity never had any extra info to begin with</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="ot">forget ::</span> <span class="dt">Identity</span> a <span class="ot">-&gt;</span> a</span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>forget (<span class="dt">Identity</span> a) <span class="ot">=</span> a</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="co">-- The extra info in a nonempty list is the extra elements</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a><span class="ot">forget ::</span> <span class="dt">List.NonEmpty</span> a <span class="ot">-&gt;</span> a</span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>forget (a<span class="op">:|</span>_) <span class="ot">=</span> a</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="co">-- The extra info in a &#39;Tagged&#39; is the tag</span></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a><span class="ot">forget ::</span> <span class="dt">Tagged</span> t a <span class="ot">-&gt;</span> a</span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a>forget (<span class="dt">Tagged</span> _ a) <span class="ot">=</span> a</span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a><span class="co">-- The extra info in a Pair is the duplication</span></span>
<span id="cb5-14"><a href="#cb5-14" aria-hidden="true" tabindex="-1"></a><span class="ot">forget ::</span> <span class="dt">Pair</span> a <span class="ot">-&gt;</span> a</span>
<span id="cb5-15"><a href="#cb5-15" aria-hidden="true" tabindex="-1"></a>forget (<span class="dt">Pair</span> a _) <span class="ot">=</span> a</span></code></pre></div>
<p>You can imagine this sort of thing for many types; for any Comonad
type we have <code>forget = extract</code>. Implementations for
<code>Maybe</code> or <code>Either</code> or <code>List</code> are a bit
trickier since it's possible that no value exists, we'd have to require
a Monoid for the inner type <code>a</code> to do these. Notice that
these are the same types for which we can't write a proper instance of
Distributive, so we'll be avoiding them as we move forwards.</p>
<p>Anyways, enough chatting, let's build something! We're going to do a
case study in the <code>Tagged</code> type we showed above.</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 DeriveFunctor #-}</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# language TypeFamilies #-}</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# language MultiParamTypeClasses #-}</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# language FlexibleInstances #-}</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a><span class="kw">module</span> <span class="dt">Tagged</span> <span class="kw">where</span></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Distributive</span></span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Functor.Rep</span></span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Functor.Adjunction</span></span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Char</span></span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-13"><a href="#cb6-13" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">Forget</span> a <span class="ot">=</span> <span class="dt">Forget</span> {<span class="ot"> getForget ::</span> a } <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>, <span class="dt">Functor</span>)</span>
<span id="cb6-14"><a href="#cb6-14" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Tagged</span> t a <span class="ot">=</span> <span class="dt">Tagged</span></span>
<span id="cb6-15"><a href="#cb6-15" aria-hidden="true" tabindex="-1"></a>  {<span class="ot"> getTag ::</span> t</span>
<span id="cb6-16"><a href="#cb6-16" aria-hidden="true" tabindex="-1"></a>  ,<span class="ot"> untag ::</span> a</span>
<span id="cb6-17"><a href="#cb6-17" aria-hidden="true" tabindex="-1"></a>  } <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>, <span class="dt">Functor</span>)</span></code></pre></div>
<p>Okay so we've got our two functors! <code>Tagged</code> promotes an
'a' to a 'a' which is tagged by some tag 't'. We'll need a Representable
instance for Forget, which need Distributive, these are pretty easy to
write for such simple types. Notice that we have a Monoid constraint on
our tag which makes Distributive possible.</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="kw">instance</span> <span class="dt">Distributive</span> <span class="dt">Forget</span> <span class="kw">where</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>  distribute fa <span class="ot">=</span> <span class="dt">Forget</span> (getForget <span class="op">&lt;$&gt;</span> fa)</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="kw">instance</span> <span class="dt">Representable</span> <span class="dt">Forget</span> <span class="kw">where</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">type</span> <span class="dt">Rep</span> <span class="dt">Forget</span> <span class="ot">=</span> ()</span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>  <span class="fu">index</span> (<span class="dt">Forget</span> a) () <span class="ot">=</span> a</span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a>  tabulate describe <span class="ot">=</span> <span class="dt">Forget</span> (describe ())</span></code></pre></div>
<p>Hopefully this is all pretty easy to follow, we've chosen
<code>()</code> as the representation since each data type has only a
single slot.</p>
<p>Now for Adjunction! We'll unfortunately have to choose a concrete
type for our tag here since the definition of Adjunction has functional
dependencies. This means that for a given Left Adjoint there can only be
one Right Adjoint. We can see it in the class constraint here:</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">Functor</span> f, <span class="dt">Representable</span> u) <span class="ot">=&gt;</span> <span class="dt">Adjunction</span> f u <span class="op">|</span> f <span class="ot">-&gt;</span> u, u <span class="ot">-&gt;</span> f <span class="kw">where</span></span></code></pre></div>
<p>It's a shame, but we'll just pick a tag type; how about
<code>Maybe String</code>, a <code>Just</code> means we've tagged the
value and a <code>Nothing</code> means we haven't.
<code>Maybe String</code> is a monoid since <code>String</code> is a
Monoid.</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">type</span> <span class="dt">Tag</span> <span class="ot">=</span> <span class="dt">Maybe</span> <span class="dt">String</span></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="kw">instance</span> <span class="dt">Adjunction</span> (<span class="dt">Tagged</span> <span class="dt">Tag</span>) <span class="dt">Forget</span> <span class="kw">where</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a><span class="ot">  unit ::</span> a <span class="ot">-&gt;</span> <span class="dt">Forget</span> (<span class="dt">Tagged</span> <span class="dt">Tag</span> a)</span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a>  unit a <span class="ot">=</span> <span class="dt">Forget</span> (<span class="dt">Tagged</span> <span class="dt">Nothing</span> a)</span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a><span class="ot">  counit ::</span> <span class="dt">Tagged</span> <span class="dt">Tag</span> (<span class="dt">Forget</span> a) <span class="ot">-&gt;</span> a</span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a>  counit (<span class="dt">Tagged</span> _ (<span class="dt">Forget</span> a)) <span class="ot">=</span> a</span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-10"><a href="#cb9-10" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- leftAdjunct and rightAdjunct have default implementations in terms of unit &amp; counit</span></span>
<span id="cb9-11"><a href="#cb9-11" aria-hidden="true" tabindex="-1"></a><span class="ot">  leftAdjunct ::</span> (<span class="dt">Tagged</span> a <span class="ot">-&gt;</span> b) <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">Forget</span> b</span>
<span id="cb9-12"><a href="#cb9-12" aria-hidden="true" tabindex="-1"></a><span class="ot">  rightAdjunct ::</span> (a <span class="ot">-&gt;</span> <span class="dt">Forget</span> b) <span class="ot">-&gt;</span> <span class="dt">Tagged</span> a <span class="ot">-&gt;</span> b</span></code></pre></div>
<p>There we go! Here we say that Forget is Right Adjoint to Tagged,
which roughly means that we lose information when we move from
<code>Tagged</code> to <code>Forget</code>. <code>unit</code> and
<code>counit</code> correspond to the <code>inject</code> and
<code>forget</code> that we wrote earlier, they've just got that extra
<code>Forget</code> floating around. That's okay though, it's isomorphic
to <code>Identity</code> so anywhere we see a <code>Forget a</code> we
can pull it out into just an <code>a</code> and vice versa if we need to
embed an <code>a</code> to get <code>Forget a</code>.</p>
<p>We now have access to helpers which allow us to promote and demote
functions from one functor into the other; so if we've got a function
which operates over tagged values we can get a function over untagged
values, the same goes for turning functions accepting untagged values
into ones taking tagged values. These helpers are
<code>leftAdjunct</code> and <code>rightAdjunct</code> respectively!
We're going to wrap them up in a small layer to perform the
<code>a ≅ Forget a</code> isomorphism for us so we can clean up the
signatures a little.</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">overUntagged ::</span> (<span class="dt">Tagged</span> <span class="dt">Tag</span> a <span class="ot">-&gt;</span> b) <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> b</span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>overUntagged f <span class="ot">=</span> getForget <span class="op">.</span> leftAdjunct f </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="ot">overTagged ::</span> (a <span class="ot">-&gt;</span> b) <span class="ot">-&gt;</span> <span class="dt">Tagged</span> <span class="dt">Tag</span> a <span class="ot">-&gt;</span> b</span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>overTagged f <span class="ot">=</span> rightAdjunct (<span class="dt">Forget</span> <span class="op">.</span> f)</span></code></pre></div>
<p>To test these out let's write a small function which takes Strings
which are Tagged with a String annotation and appends the tag to the
string:</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">applyTag ::</span> <span class="dt">Tagged</span> <span class="dt">Tag</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">String</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>applyTag (<span class="dt">Tagged</span> <span class="dt">Nothing</span> s) <span class="ot">=</span> s</span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>applyTag (<span class="dt">Tagged</span> (<span class="dt">Just</span> tag) s) <span class="ot">=</span> tag <span class="op">++</span> <span class="st">&quot;: &quot;</span> <span class="op">++</span> s</span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> applyTag (<span class="dt">Tagged</span> (<span class="dt">Just</span> <span class="st">&quot;Book&quot;</span>) <span class="st">&quot;Ender&#39;s Game&quot;</span>)</span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;Book: Ender&#39;s Game&quot;</span></span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> applyTag (<span class="dt">Tagged</span> <span class="dt">Nothing</span> <span class="st">&quot;Steve&quot;</span>)</span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;Steve&quot;</span></span></code></pre></div>
<p>Using our helpers we can call <code>applyTag</code> over untagged
strings too, though the results are expectedly boring:</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">&gt;</span> overUntagged applyTag <span class="st">&quot;Boring&quot;</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;Boring&quot;</span></span></code></pre></div>
<p>Now let's see the other half of our adjunction, we can define a
function over strings and run it over Tagged strings!</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">upperCase ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">String</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>upperCase <span class="ot">=</span> <span class="fu">fmap</span> <span class="fu">toUpper</span></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> upperCase <span class="st">&quot;Steve&quot;</span></span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;STEVE&quot;</span></span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> overTagged upperCase (<span class="dt">Tagged</span> (<span class="dt">Just</span> <span class="st">&quot;Book&quot;</span>) <span class="st">&quot;Ender&#39;s Game&quot;</span>)</span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;ENDER&#39;S GAME&quot;</span></span></code></pre></div>
<p>Notice that we lose the tag when we do this, that's the price we pay
with a lossy Adjunction! The utility of the construct seems pretty
limited here since <code>fmap</code> and <code>extract</code> would
pretty much give us the same options, but the idea is that Adjunctions
represent a structure which we can generalize over in certain cases.
This post was more about understanding adjunctions and Free/Forgetful
functors than it was about programming anyways :)</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Adjunctions and Battleship</title>
      <link href="https://chrispenner.ca/posts/adjunction-battleship"/>
      <id>https://chrispenner.ca/posts/adjunction-battleship</id>
      <updated>2017-07-19T00:00:00Z</updated>
      <summary>Using Adjunctions and Representable to build a Battleship game</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/battleship.jpg" alt="Adjunctions and Battleship">
              <p>Today we'll be looking into Kmett's <a
href="http://hackage.haskell.org/package/adjunctions">adjunctions</a>
library, particularly the meat of the library in
Data.Functor.Adjunction.</p>
<p>This post as a literate haskell file <a
href="https://gist.github.com/ChrisPenner/291038ae1343333fb41523b41181a9d4">here</a>,
so if you prefer to have the code running in ghci as you read along then
go for it! Like any good haskell file we need half a dozen language
pragmas and imports before we get started.</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">{-# language DeriveFunctor #-}</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# language TypeFamilies #-}</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# language MultiParamTypeClasses #-}</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# language InstanceSigs #-}</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# language FlexibleContexts #-}</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="kw">module</span> <span class="dt">Battleship</span> <span class="kw">where</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Functor</span> (void)</span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Functor.Adjunction</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Functor.Rep</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Distributive</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Arrow</span> ((&amp;&amp;&amp;))</span></code></pre></div>
<p>I've been struggling to understand this library for a little while
now and have been poking at it from different angles trying to gain some
intuition. My previous post on <a
href="http://chrispenner.ca/posts/representable-cofree-zippers">Zippers
using Representable and Cofree</a> is part of that adventure so I'd
suggest you read that first if you haven't yet.</p>
<p>Like most higher-level mathematic concepts Adjunctions themselves are
just an abstract collection of types and shapes that fit together in a
certain way. This means that they have little practical meaning on their
own, but provide a useful set of tools to us if we happen to notice that
some problem we're working on matches their shape. The first time I dug
into adjunctions I went straight to the typeclass to check out which
requirements and methods it had. Here are the signatures straight from
the source code in Data.Functor.Adjunction</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">class</span> (<span class="dt">Functor</span> f, <span class="dt">Representable</span> u) <span class="ot">=&gt;</span> <span class="dt">Adjunction</span> f u <span class="op">|</span> f <span class="ot">-&gt;</span> u, u <span class="ot">-&gt;</span> f <span class="kw">where</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="ot">  unit         ::</span> a <span class="ot">-&gt;</span> u (f a)</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="ot">  counit       ::</span> f (u a) <span class="ot">-&gt;</span> a</span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="ot">  leftAdjunct  ::</span> (f a <span class="ot">-&gt;</span> b) <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> u b</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="ot">  rightAdjunct ::</span> (a <span class="ot">-&gt;</span> u b) <span class="ot">-&gt;</span> f a <span class="ot">-&gt;</span> b</span></code></pre></div>
<p>Hrmm... not the most illuminating. Unfortunately there's not much in
the way of documentation to help us out, but that's because the type
signatures pretty much explain how to USE adjunctions, but tragically
they don't tell us WHERE or HOW to use them. For this I think examples
are the most useful, and that's where I'll try to help out.</p>
<p>The first place to look for examples is in the 'instances' section of
the type-class itself, let's see what's in there:</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="dt">Adjunction</span> <span class="dt">Identity</span> <span class="dt">Identity</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Adjunction</span> ((,) e) ((<span class="ot">-&gt;</span>) e)</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Adjunction</span> f g <span class="ot">=&gt;</span> <span class="dt">Adjunction</span> (<span class="dt">IdentityT</span> f) (<span class="dt">IdentityT</span> g)</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Adjunction</span> f u <span class="ot">=&gt;</span> <span class="dt">Adjunction</span> (<span class="dt">Free</span> f) (<span class="dt">Cofree</span> u)</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Adjunction</span> w m <span class="ot">=&gt;</span> <span class="dt">Adjunction</span> (<span class="dt">EnvT</span> e w) (<span class="dt">ReaderT</span> e m)</span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a><span class="dt">Adjunction</span> m w <span class="ot">=&gt;</span> <span class="dt">Adjunction</span> (<span class="dt">WriterT</span> s m) (<span class="dt">TracedT</span> s w)</span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>(<span class="dt">Adjunction</span> f g, <span class="dt">Adjunction</span> f&#39; g&#39;) <span class="ot">=&gt;</span> <span class="dt">Adjunction</span> (<span class="dt">Compose</span> f&#39; f) (<span class="dt">Compose</span> g g&#39;)</span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>(<span class="dt">Adjunction</span> f g, <span class="dt">Adjunction</span> f&#39; g&#39;) <span class="ot">=&gt;</span> <span class="dt">Adjunction</span> (<span class="dt">Sum</span> f f&#39;) (<span class="dt">Product</span> g g&#39;)</span></code></pre></div>
<p>Hrmm, still not the most helpful, most of these instances depend on
some underlying functor ALREADY having an adjunction so those won't tell
us how to implement one. I see one for
<code>Adjunction Identity Identity</code>, but something tells me that's
not going to provide much depth either. Let's dive into the one
remaining example: <code>Adjunction ((,) e) ((-&gt;) e)</code></p>
<p>This one looks a little funny if you're not used to type sigs for
functions and tuples, but it gets a lot easier to read if we substitute
it into the typeclass methods. To specialize for the tuple/function
adjunction we'll replace every <code>f a</code> with <code>(e, a)</code>
and each <code>u a</code> with <code>e -&gt; a</code>:</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="co">-- Tuple/Function adjunction specializations:</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="ot">tfUnit ::</span> a <span class="ot">-&gt;</span> (e <span class="ot">-&gt;</span> (e, a))</span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="ot">tfCounit ::</span> (e, (e <span class="ot">-&gt;</span> a)) <span class="ot">-&gt;</span> a</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>tfLeftAdjunct,<span class="ot"> tfLeftAdjunct&#39;  ::</span> ((e, a) <span class="ot">-&gt;</span> b) <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> (e <span class="ot">-&gt;</span> b)</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>tfRightAdjunct,<span class="ot"> tfRightAdjunct&#39; ::</span> (a <span class="ot">-&gt;</span> (e <span class="ot">-&gt;</span> b)) <span class="ot">-&gt;</span> (e, a) <span class="ot">-&gt;</span> b</span></code></pre></div>
<p>Hrmm, okay! That's a bit confusing but it's something we can work
with. Let's try to implement the functions! We'll implement our
specialized versions so as not to collide with the existing
instance.</p>
<p>Unit and Counit are good starting points for understanding an
adjunction. The minimal definition of an adjunction is (unit AND counit)
OR (leftAdjunct AND rightAdjunct). That lets us know that unit and
counit can themselves represent the entire adjunction (i.e. leftAdjunct
and rightAdjunct can be implemented in terms of unit and counit; or vice
versa).</p>
<p>Starting with <code>unit</code> we see from the type
<code>a -&gt; (e -&gt; (e, a))</code> that we need to take an arbitrary
'a' and embed it into a function which returns a tuple of the same type
as the function. Well, there's pretty much only one way I can think to
make this work!</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>tfUnit a <span class="ot">=</span> \e <span class="ot">-&gt;</span> (e, a)</span></code></pre></div>
<p>Solid! We just converted the type signature into an implementation.
One down, three to go. This may not provide much insight, but don't
worry we'll get there yet. Next is counit which essentially does the
opposite, exactly one implementation seems clear to me:
<code>(e, (e -&gt; a)) -&gt; a</code></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>tfCounit (e, eToA) <span class="ot">=</span> eToA e</span></code></pre></div>
<p>If we stop here for a minute we can notice a few things, we built
this adjunction out of two functors, <code>(e, a)</code> and
<code>e -&gt; a</code>. These functors have a unique relationship to one
another in that they both hold <em>pieces</em> of the whole picture, the
tuple has an 'e' but doesn't know what to do with it, while
<code>e -&gt; a</code> knows what to do with an 'e' but doesn't have one
to work with! Only when we pair the functors together do we have the
full story!</p>
<p>The next thing to notice is that these functors are only readily
useful when nested in a specific ordering, we can write a counit which
takes <code>(e, (e -&gt; a)) -&gt; a</code>, BUT if we tried to put the
function on the outside instead: <code>(e -&gt; (e, a)) -&gt; a</code>;
we have no way to get our 'a' out without having more information since
the 'e' is now hidden inside! This non-symmetric relationship shows us
that the nesting of functors matters. This is why we refer to the
functors in an adjunction as either <code>left adjoint</code> or
<code>right adjoint</code>; (<code>f</code> and <code>u</code>
respectively).</p>
<p>In our case <code>(e,)</code> is left adjoint and
<code>(e -&gt;)</code> is right adjoint. This is probably still a bit
confusing and that's okay! Try to hold on until we get to start playing
Battleship and I promise we'll have a more concrete example! One more
thing first, let's see how leftAdjunct and rightAdjunct play out for our
tuple/function adjunction.</p>
<p>Here's a refresher of the types:</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">tfLeftAdjunct ::</span> ((e, a) <span class="ot">-&gt;</span> b) <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> (e <span class="ot">-&gt;</span> b)</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="ot">tfRightAdjunct ::</span> (a <span class="ot">-&gt;</span> (e <span class="ot">-&gt;</span> b)) <span class="ot">-&gt;</span> (e, a) <span class="ot">-&gt;</span> b</span></code></pre></div>
<p>Now that we've written 'unit' and 'counit' we can implement these
other functions in terms of those. I'll provide two implementations
here; one using unit/counit and one without.</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>tfLeftAdjunct f <span class="ot">=</span> <span class="fu">fmap</span> f <span class="op">.</span> tfUnit</span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>tfRightAdjunct f <span class="ot">=</span> tfCounit <span class="op">.</span> <span class="fu">fmap</span> f</span></code></pre></div>
<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>tfLeftAdjunct&#39; eaToB a <span class="ot">=</span> \e <span class="ot">-&gt;</span> eaToB (e, a)</span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>tfRightAdjunct&#39; aToEToB (e, a) <span class="ot">=</span> aToEToB a e</span></code></pre></div>
<p>We can see from the first set of implementations that
<code>leftAdjunct</code> somehow 'lifts' a function that we give it from
one that operates over the left-hand functor into a result within the
right-hand functor.</p>
<p>Similarly <code>rightAdjunct</code> takes a function which results in
a value in left-hand functor, and when given an argument embedded in the
left-hand functor gives us the result. The first set of implementations
know nothing about the functors in specific, which shows that if we
write unit and counit we can let the default implementations take over
for the rest.</p>
<p>If you're keen you'll notice that this adjunction represents the
curry and uncurry functions! Can you see it?</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>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="ot">tfLeftAdjunct ::</span> ((e, a) <span class="ot">-&gt;</span> b) <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> (e <span class="ot">-&gt;</span> b)</span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a><span class="fu">curry</span><span class="ot"> ::</span> ((a, b) <span class="ot">-&gt;</span> c) <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> b <span class="ot">-&gt;</span> c</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="ot">tfRightAdjunct ::</span> (a <span class="ot">-&gt;</span> (e <span class="ot">-&gt;</span> b)) <span class="ot">-&gt;</span> (e, a) <span class="ot">-&gt;</span> b</span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a><span class="fu">uncurry</span><span class="ot"> ::</span> (a <span class="ot">-&gt;</span> b <span class="ot">-&gt;</span> c) <span class="ot">-&gt;</span> (a, b) <span class="ot">-&gt;</span> c</span></code></pre></div>
<p>I haven't gotten to a point where I can prove it yet, but I believe
all adjunctions are actually isomorphic to this curry/uncurry
adjunction! Maybe someone reading can help me out with the proof.</p>
<p>Again, it's fun to see this play out, but where are the practical
applications?? Let's play a game. It's time to see if we can match these
shapes and patterns to a real(ish) problem. We're going to make a mini
game of Battleship, an old board game where players can guess where
their opponents ships are hiding within a grid and see if they can hit
them! We'll start by setting up some data-types and some pre-requisite
instances, then we'll tie it all together with an Adjunction!</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">data</span> <span class="dt">Row</span> <span class="ot">=</span> <span class="dt">A</span> <span class="op">|</span> <span class="dt">B</span> <span class="op">|</span> <span class="dt">C</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>)</span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Column</span> <span class="ot">=</span> <span class="dt">I</span> <span class="op">|</span> <span class="dt">II</span> <span class="op">|</span> <span class="dt">III</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>)</span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a><span class="co">-- I&#39;m going to define this as a Functor type to save time later, but for now</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a><span class="co">-- we&#39;ll use the alias Coord;</span></span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">CoordF</span> a <span class="ot">=</span> <span class="dt">CoordF</span> <span class="dt">Row</span> <span class="dt">Column</span> a</span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>, <span class="dt">Functor</span>)</span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">Coord</span> <span class="ot">=</span> <span class="dt">CoordF</span> ()</span></code></pre></div>
<p>Each cell can hold a Vessel of some kind, maybe a Ship or Submarine;
It's also possible for a cell to be empty.</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">Vessel</span> <span class="ot">=</span> <span class="dt">Ship</span> <span class="op">|</span> <span class="dt">Sub</span> <span class="op">|</span> <span class="dt">Sunk</span> <span class="op">|</span> <span class="dt">Empty</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>)</span></code></pre></div>
<p>We'll start with a 3x3 board to keep it simple, each row is
represented by a 3-tuple. We've learned by now that making our types
into Functors makes them more usable, so I'm going to define the board
as a functor parameterized over the contents of each cell.</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">data</span> <span class="dt">Board</span> a <span class="ot">=</span> <span class="dt">Board</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>  (a, a, a)</span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a>  (a, a, a)</span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>  (a, a, a)</span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Eq</span>, <span class="dt">Functor</span>)</span></code></pre></div>
<p>I'm going to add a quick Show instance, it's not perfect but it lets
us see the board!</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="kw">instance</span> (<span class="dt">Show</span> a) <span class="ot">=&gt;</span> <span class="dt">Show</span> (<span class="dt">Board</span> a) <span class="kw">where</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a>  <span class="fu">show</span> (<span class="dt">Board</span> top middle bottom) <span class="ot">=</span></span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a>    <span class="st">&quot;       I  |  II | III\n&quot;</span></span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">++</span> <span class="st">&quot;A   &quot;</span> <span class="op">++</span> <span class="fu">show</span> top <span class="op">++</span> <span class="st">&quot;\n&quot;</span></span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">++</span> <span class="st">&quot;B   &quot;</span> <span class="op">++</span> <span class="fu">show</span> middle <span class="op">++</span> <span class="st">&quot;\n&quot;</span></span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">++</span> <span class="st">&quot;C   &quot;</span> <span class="op">++</span> <span class="fu">show</span> bottom <span class="op">++</span> <span class="st">&quot;\n&quot;</span></span></code></pre></div>
<p>Here's a good starting position, the board is completely empty!</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">startBoard ::</span> <span class="dt">Board</span> <span class="dt">Vessel</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>startBoard <span class="ot">=</span> <span class="dt">Board</span></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a>  (<span class="dt">Empty</span>, <span class="dt">Empty</span>, <span class="dt">Empty</span>)</span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a>  (<span class="dt">Empty</span>, <span class="dt">Empty</span>, <span class="dt">Empty</span>)</span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a>  (<span class="dt">Empty</span>, <span class="dt">Empty</span>, <span class="dt">Empty</span>)</span></code></pre></div>
<p>It's at this point we want to start making guesses using a Coord and
seeing what's in each position! How else are we going to sink the
battleship? Well, when we start talking about 'Indexing' into our board
(which is a functor) I think immediately of the Representable typeclass
from <a
href="https://hackage.haskell.org/package/adjunctions-4.3/docs/Data-Functor-Rep.html#t:Representable">Data.Functor.Rep</a>.
Don't let the name scare you, one of the things that Representable gives
you is the notion of <em>indexing</em> into a functor.</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="kw">instance</span> <span class="dt">Representable</span> <span class="dt">Board</span> <span class="kw">where</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- We index into our functor using Coord</span></span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">type</span> <span class="dt">Rep</span> <span class="dt">Board</span> <span class="ot">=</span> <span class="dt">Coord</span></span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- Given an index and a board, pull out the matching cell</span></span>
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a>  <span class="fu">index</span> (<span class="dt">Board</span> (a, _, _) _ _) (<span class="dt">CoordF</span> <span class="dt">A</span> <span class="dt">I</span> _) <span class="ot">=</span> a</span>
<span id="cb16-7"><a href="#cb16-7" aria-hidden="true" tabindex="-1"></a>  <span class="fu">index</span> (<span class="dt">Board</span> (_, a, _) _ _) (<span class="dt">CoordF</span> <span class="dt">A</span> <span class="dt">II</span> _) <span class="ot">=</span> a</span>
<span id="cb16-8"><a href="#cb16-8" aria-hidden="true" tabindex="-1"></a>  <span class="fu">index</span> (<span class="dt">Board</span> (_, _, a) _ _) (<span class="dt">CoordF</span> <span class="dt">A</span> <span class="dt">III</span> _) <span class="ot">=</span> a</span>
<span id="cb16-9"><a href="#cb16-9" aria-hidden="true" tabindex="-1"></a>  <span class="fu">index</span> (<span class="dt">Board</span> _ (a, _, _) _) (<span class="dt">CoordF</span> <span class="dt">B</span> <span class="dt">I</span> _) <span class="ot">=</span> a</span>
<span id="cb16-10"><a href="#cb16-10" aria-hidden="true" tabindex="-1"></a>  <span class="fu">index</span> (<span class="dt">Board</span> _ (_, a, _) _) (<span class="dt">CoordF</span> <span class="dt">B</span> <span class="dt">II</span> _) <span class="ot">=</span> a</span>
<span id="cb16-11"><a href="#cb16-11" aria-hidden="true" tabindex="-1"></a>  <span class="fu">index</span> (<span class="dt">Board</span> _ (_, _, a) _) (<span class="dt">CoordF</span> <span class="dt">B</span> <span class="dt">III</span> _) <span class="ot">=</span> a</span>
<span id="cb16-12"><a href="#cb16-12" aria-hidden="true" tabindex="-1"></a>  <span class="fu">index</span> (<span class="dt">Board</span> _ _ (a, _, _)) (<span class="dt">CoordF</span> <span class="dt">C</span> <span class="dt">I</span> _) <span class="ot">=</span> a</span>
<span id="cb16-13"><a href="#cb16-13" aria-hidden="true" tabindex="-1"></a>  <span class="fu">index</span> (<span class="dt">Board</span> _ _ (_, a, _)) (<span class="dt">CoordF</span> <span class="dt">C</span> <span class="dt">II</span> _) <span class="ot">=</span> a</span>
<span id="cb16-14"><a href="#cb16-14" aria-hidden="true" tabindex="-1"></a>  <span class="fu">index</span> (<span class="dt">Board</span> _ _ (_, _, a)) (<span class="dt">CoordF</span> <span class="dt">C</span> <span class="dt">III</span> _) <span class="ot">=</span> a</span>
<span id="cb16-15"><a href="#cb16-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-16"><a href="#cb16-16" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- Given a function which describes a slot, build a Board</span></span>
<span id="cb16-17"><a href="#cb16-17" aria-hidden="true" tabindex="-1"></a>  tabulate desc <span class="ot">=</span> <span class="dt">Board</span></span>
<span id="cb16-18"><a href="#cb16-18" aria-hidden="true" tabindex="-1"></a>      (desc (<span class="dt">CoordF</span> <span class="dt">A</span> <span class="dt">I</span> ()), desc (<span class="dt">CoordF</span> <span class="dt">A</span> <span class="dt">II</span> ()), desc (<span class="dt">CoordF</span> <span class="dt">A</span> <span class="dt">III</span> ()))</span>
<span id="cb16-19"><a href="#cb16-19" aria-hidden="true" tabindex="-1"></a>      (desc (<span class="dt">CoordF</span> <span class="dt">B</span> <span class="dt">I</span> ()), desc (<span class="dt">CoordF</span> <span class="dt">B</span> <span class="dt">II</span> ()), desc (<span class="dt">CoordF</span> <span class="dt">B</span> <span class="dt">III</span> ()))</span>
<span id="cb16-20"><a href="#cb16-20" aria-hidden="true" tabindex="-1"></a>      (desc (<span class="dt">CoordF</span> <span class="dt">C</span> <span class="dt">I</span> ()), desc (<span class="dt">CoordF</span> <span class="dt">C</span> <span class="dt">II</span> ()), desc (<span class="dt">CoordF</span> <span class="dt">C</span> <span class="dt">III</span> ()))</span></code></pre></div>
<p>If you find it easier to implement unit and counit (which we'll
explore soon) you can implement those and then use
<code>indexAdjunction</code> and <code>tabulateAdjunction</code>
provided by Data.Functor.Adjunction as your implementations for your
Representable instance.</p>
<p>For Representable we also have a prerequisite of Distributive from <a
href="https://hackage.haskell.org/package/distributive-0.5.0.2/docs/Data-Distributive.html#t:Distributive">Data.Distributive</a>,
All Representable functors are also Distributive and this library has
decided to make that an explicit requirement.</p>
<p>No problem though, it turns out that since every Representable is
Distributive that Data.Functor.Rep has a <code>distributeRep</code>
function which provides an appropriate implementation for us for free!
We just need to slot it in:</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="kw">instance</span> <span class="dt">Distributive</span> <span class="dt">Board</span> <span class="kw">where</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a>  distribute <span class="ot">=</span> distributeRep</span></code></pre></div>
<p>Phew! A lot of work there, but now we can do some cool stuff! Let's
say that as a player we want to build a game board with some ships on
it. We now have two choices, we can either define a board and put some
ships on it, or define a function which says what's at a given
coordinate and use that to build a board. Let's do both, for
PEDAGOGY!</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="ot">myBoard1 ::</span> <span class="dt">Board</span> <span class="dt">Vessel</span></span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a>myBoard1 <span class="ot">=</span> <span class="dt">Board</span></span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a>  (<span class="dt">Empty</span>, <span class="dt">Empty</span>, <span class="dt">Ship</span>)</span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a>  (<span class="dt">Sub</span>,   <span class="dt">Empty</span>, <span class="dt">Sub</span>)</span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a>  (<span class="dt">Ship</span>,  <span class="dt">Empty</span>, <span class="dt">Empty</span>)</span>
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-7"><a href="#cb18-7" aria-hidden="true" tabindex="-1"></a><span class="co">-- Now we&#39;ll define the same board using a function</span></span>
<span id="cb18-8"><a href="#cb18-8" aria-hidden="true" tabindex="-1"></a><span class="ot">define ::</span> <span class="dt">Coord</span> <span class="ot">-&gt;</span> <span class="dt">Vessel</span></span>
<span id="cb18-9"><a href="#cb18-9" aria-hidden="true" tabindex="-1"></a>define (<span class="dt">CoordF</span> <span class="dt">A</span> <span class="dt">III</span> _) <span class="ot">=</span> <span class="dt">Ship</span></span>
<span id="cb18-10"><a href="#cb18-10" aria-hidden="true" tabindex="-1"></a>define (<span class="dt">CoordF</span> <span class="dt">B</span> <span class="dt">I</span> _) <span class="ot">=</span> <span class="dt">Sub</span></span>
<span id="cb18-11"><a href="#cb18-11" aria-hidden="true" tabindex="-1"></a>define (<span class="dt">CoordF</span> <span class="dt">B</span> <span class="dt">III</span> _) <span class="ot">=</span> <span class="dt">Sub</span></span>
<span id="cb18-12"><a href="#cb18-12" aria-hidden="true" tabindex="-1"></a>define (<span class="dt">CoordF</span> <span class="dt">C</span> <span class="dt">I</span> _) <span class="ot">=</span> <span class="dt">Ship</span></span>
<span id="cb18-13"><a href="#cb18-13" aria-hidden="true" tabindex="-1"></a><span class="co">-- Otherwise it&#39;s Empty!</span></span>
<span id="cb18-14"><a href="#cb18-14" aria-hidden="true" tabindex="-1"></a>define _ <span class="ot">=</span> <span class="dt">Empty</span></span>
<span id="cb18-15"><a href="#cb18-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-16"><a href="#cb18-16" aria-hidden="true" tabindex="-1"></a><span class="co">-- Now we build up a board using our descriptor function.</span></span>
<span id="cb18-17"><a href="#cb18-17" aria-hidden="true" tabindex="-1"></a><span class="co">-- Notice that (myBoard1 == myBoard2)</span></span>
<span id="cb18-18"><a href="#cb18-18" aria-hidden="true" tabindex="-1"></a><span class="ot">myBoard2 ::</span> <span class="dt">Board</span> <span class="dt">Vessel</span></span>
<span id="cb18-19"><a href="#cb18-19" aria-hidden="true" tabindex="-1"></a>myBoard2 <span class="ot">=</span> tabulate define</span></code></pre></div>
<p>Okay this is already pretty cool; but I <em>DID</em> promise we'd use
an adjunction here somewhere, but for that we need TWO functors.
Remember how CoordF is actually a functor hidden undernath Coord? We can
use that! This functor doesn't make much sense on its own, but the
important bit is that it's a functor which contains part of the
information about our system. Remember that only one of our functors
needs to be Representable in an Adjunction, so we can take it easy and
don't need to worry about Distributive or Representable for CoordF</p>
<p>Now for the good stuff; let's crack out Adjunction and see if we can
write an instance!</p>
<p>I'm lazy, so I'm going to rely on Representable to do the dirty work,
Embedding an a into a Board filled with coordinates and values doesn't
make a ton of sense, but the most sensible way that I can think of to do
that is to put the a in every slot where the Coord represents the index
of the cell its in.</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">instance</span> <span class="dt">Adjunction</span> <span class="dt">CoordF</span> <span class="dt">Board</span> <span class="kw">where</span></span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a><span class="ot">  unit ::</span> a <span class="ot">-&gt;</span> <span class="dt">Board</span> (<span class="dt">CoordF</span> a)</span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a>  unit a <span class="ot">=</span> tabulate (\(<span class="dt">CoordF</span> row col ()) <span class="ot">-&gt;</span> <span class="dt">CoordF</span> row col a)</span></code></pre></div>
<p>Counit actually makes sense in this case! We have our two pieces of
info which form the parts of the adjunction; The board contains the
values in ALL positions and the CoordF contains info which tells us
exactly WHICH position we're currently interested in.</p>
<p>For counit I'm just going to use index to pull the value out of the
underlying board.</p>
<div class="sourceCode" id="cb20"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="ot">  counit ::</span> <span class="dt">CoordF</span> (<span class="dt">Board</span> a) <span class="ot">-&gt;</span> a</span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a>  counit (<span class="dt">CoordF</span> row col board) <span class="ot">=</span> <span class="fu">index</span> board (<span class="dt">CoordF</span> row col ())</span></code></pre></div>
<p>Done! We've written our Adjunction, let's keep building to game to
see how we can use the system! Here're the other type sigs for our
Adjunction:</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">leftAdjunct  ::</span> (<span class="dt">CoordF</span> a <span class="ot">-&gt;</span> b) <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">Board</span> b</span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a><span class="ot">rightAdjunct ::</span> (a <span class="ot">-&gt;</span> <span class="dt">Board</span> b) <span class="ot">-&gt;</span> <span class="dt">CoordF</span> a <span class="ot">-&gt;</span> b</span></code></pre></div>
<p>First let's observe unit and co-unit in action!</p>
<p><code>unit</code> Always does the naive thing, so if we pass it a
Vessel it'll just set the whole board to that value; note that each slot
is also labelled with its index!</p>
<div class="sourceCode" id="cb22"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> unit <span class="dt">Ship</span><span class="ot"> ::</span> <span class="dt">Board</span> (<span class="dt">CoordF</span> <span class="dt">Vessel</span>)</span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a>       <span class="dt">A</span>  <span class="op">|</span>  <span class="dt">B</span>  <span class="op">|</span> <span class="dt">C</span></span>
<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a><span class="dt">I</span>   (<span class="dt">CoordF</span> <span class="dt">A</span> <span class="dt">I</span> <span class="dt">Ship</span>,<span class="dt">CoordF</span> <span class="dt">A</span> <span class="dt">II</span> <span class="dt">Ship</span>,<span class="dt">CoordF</span> <span class="dt">A</span> <span class="dt">III</span> <span class="dt">Ship</span>)</span>
<span id="cb22-4"><a href="#cb22-4" aria-hidden="true" tabindex="-1"></a><span class="dt">II</span>  (<span class="dt">CoordF</span> <span class="dt">B</span> <span class="dt">I</span> <span class="dt">Ship</span>,<span class="dt">CoordF</span> <span class="dt">B</span> <span class="dt">II</span> <span class="dt">Ship</span>,<span class="dt">CoordF</span> <span class="dt">B</span> <span class="dt">III</span> <span class="dt">Ship</span>)</span>
<span id="cb22-5"><a href="#cb22-5" aria-hidden="true" tabindex="-1"></a><span class="dt">III</span> (<span class="dt">CoordF</span> <span class="dt">C</span> <span class="dt">I</span> <span class="dt">Ship</span>,<span class="dt">CoordF</span> <span class="dt">C</span> <span class="dt">II</span> <span class="dt">Ship</span>,<span class="dt">CoordF</span> <span class="dt">C</span> <span class="dt">III</span> <span class="dt">Ship</span>)</span></code></pre></div>
<p>If we already have our game board and also have an index then counit
folds down the structure by choosing the index specified by the outer
CoordF Functor.</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="co">-- Remember our board:</span></span>
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> myBoard1</span>
<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a>       <span class="dt">A</span>  <span class="op">|</span>  <span class="dt">B</span>  <span class="op">|</span> <span class="dt">C</span></span>
<span id="cb23-4"><a href="#cb23-4" aria-hidden="true" tabindex="-1"></a><span class="dt">I</span>   (<span class="dt">Empty</span>,<span class="dt">Empty</span>,<span class="dt">Ship</span>)</span>
<span id="cb23-5"><a href="#cb23-5" aria-hidden="true" tabindex="-1"></a><span class="dt">II</span>  (<span class="dt">Sub</span>,<span class="dt">Empty</span>,<span class="dt">Sub</span>)</span>
<span id="cb23-6"><a href="#cb23-6" aria-hidden="true" tabindex="-1"></a><span class="dt">III</span> (<span class="dt">Ship</span>,<span class="dt">Empty</span>,<span class="dt">Empty</span>)</span>
<span id="cb23-7"><a href="#cb23-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb23-8"><a href="#cb23-8" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> counit <span class="op">.</span> <span class="dt">CoordF</span> <span class="dt">A</span> <span class="dt">III</span> <span class="op">$</span> myBoard1</span>
<span id="cb23-9"><a href="#cb23-9" aria-hidden="true" tabindex="-1"></a><span class="dt">Ship</span></span></code></pre></div>
<p>So what about leftAdjunct and rightAdjunct? Conceptually you can
think of these as functions which let you operate over one piece of
information and the Adjunction will form the other piece of information
for you! For instance leftAdjunct:</p>
<div class="sourceCode" id="cb24"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="ot">leftAdjunct  ::</span> (<span class="dt">CoordF</span> a <span class="ot">-&gt;</span> b) <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">Board</span> b</span></code></pre></div>
<p>lets you build a value in the right adjoint functor by specifying how
to handle each index, this is similar to <code>tabulate</code> from from
Representable. Earlier we used tabulate to generate a game board from a
shoot function, we can do the same thing using leftAdjunct, we could
re-implement our <code>shoot</code> function from above in terms of
leftAdjunct:</p>
<div class="sourceCode" id="cb25"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a><span class="ot">myBoard3 ::</span> <span class="dt">Board</span> <span class="dt">Vessel</span></span>
<span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a>myBoard3 <span class="ot">=</span> leftAdjunct define ()</span></code></pre></div>
<p>Right adjunct works similarly, but in reverse! Given a way to create
a board from a solitary value we can extract a value from the board
matching some CoordF. Just like leftAdjunct lines up with 'tabulate',
rightAdjunct lines up with 'index', but with a smidge of extra
functionality.</p>
<div class="sourceCode" id="cb26"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a><span class="ot">rightAdjunct ::</span> (a <span class="ot">-&gt;</span> <span class="dt">Board</span> b) <span class="ot">-&gt;</span> <span class="dt">CoordF</span> a <span class="ot">-&gt;</span> b</span></code></pre></div>
<p>I don't have any illuminating uses of rightAdjunct for our Battleship
example, but you can use it to reimplement 'index' from Representable if
you like!</p>
<div class="sourceCode" id="cb27"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a><span class="ot">myIndex ::</span> <span class="dt">Board</span> a <span class="ot">-&gt;</span> <span class="dt">CoordF</span> () <span class="ot">-&gt;</span> a</span>
<span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a>myIndex board coord <span class="ot">=</span> rightAdjunct (<span class="fu">const</span> board) coord</span></code></pre></div>
<p>Cool, now let's try and make this game a little more functional!</p>
<p>Already we've got most of the basics for a simple game of battleship,
earlier we defined a game board in terms of a 'firing' function, now
let's write a function which takes a game board and mutates it according
to a player's layout.</p>
<p>War has changed over the years so our version of battleship is going
to be a bit more interesting than the traditional version. In our case
each player places ships OR submarines on each square, and when firing
on a square they may fire either a torpedo (hits ships) OR a depth
charge (hits subs).</p>
<p>This means that we need a way to check not only if a cell is
occupied, but also if the vessel there can be hit by the weapon which
was fired! For this we'll take a look at the useful but vaguely named
<code>zapWithAdjunction</code> function.</p>
<p>This function has its roots in an 'Pairing' typeclass which
eventually was absorbed by Adjunction. The idea of a Functor Pairing is
that there's a relationship between the structure of the two paired
functors regardless of what's inside. Sounds like an adjunction right??
<code>zapWithAdjunction</code> looks like this:</p>
<div class="sourceCode" id="cb28"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb28-1"><a href="#cb28-1" aria-hidden="true" tabindex="-1"></a><span class="ot">zapWithAdjunction ::</span> <span class="dt">Adjunction</span> f u <span class="ot">=&gt;</span> (a <span class="ot">-&gt;</span> b <span class="ot">-&gt;</span> c) <span class="ot">-&gt;</span> u a <span class="ot">-&gt;</span> f b <span class="ot">-&gt;</span> c</span></code></pre></div>
<p>or for our types:</p>
<div class="sourceCode" id="cb29"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb29-1"><a href="#cb29-1" aria-hidden="true" tabindex="-1"></a><span class="ot">zapWithAdjunction ::</span> (a <span class="ot">-&gt;</span> b <span class="ot">-&gt;</span> c) <span class="ot">-&gt;</span> <span class="dt">Board</span> a <span class="ot">-&gt;</span> <span class="dt">CoordF</span> b <span class="ot">-&gt;</span> c</span></code></pre></div>
<p>So it pairs a Board and Coord together, but applies a function
<em>across</em> the values stored there. It uses the adjunction to do
this, so it will automagically choose the 'right' value from the Board
to apply with the value from the CoordF!</p>
<p>First we need weapons!</p>
<div class="sourceCode" id="cb30"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb30-1"><a href="#cb30-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Weapon</span> <span class="ot">=</span> <span class="dt">Torpedo</span> <span class="op">|</span> <span class="dt">DepthCharge</span></span>
<span id="cb30-2"><a href="#cb30-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>)</span></code></pre></div>
<p>Now we can write something like this:</p>
<div class="sourceCode" id="cb31"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb31-1"><a href="#cb31-1" aria-hidden="true" tabindex="-1"></a><span class="ot">checkHit ::</span> <span class="dt">Vessel</span> <span class="ot">-&gt;</span> <span class="dt">Weapon</span> <span class="ot">-&gt;</span> <span class="dt">Bool</span></span>
<span id="cb31-2"><a href="#cb31-2" aria-hidden="true" tabindex="-1"></a>checkHit <span class="dt">Ship</span> <span class="dt">Torpedo</span> <span class="ot">=</span> <span class="dt">True</span></span>
<span id="cb31-3"><a href="#cb31-3" aria-hidden="true" tabindex="-1"></a>checkHit <span class="dt">Sub</span> <span class="dt">DepthCharge</span> <span class="ot">=</span> <span class="dt">True</span></span>
<span id="cb31-4"><a href="#cb31-4" aria-hidden="true" tabindex="-1"></a>checkHit _ _ <span class="ot">=</span> <span class="dt">False</span></span>
<span id="cb31-5"><a href="#cb31-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb31-6"><a href="#cb31-6" aria-hidden="true" tabindex="-1"></a><span class="ot">shoot ::</span> <span class="dt">Board</span> <span class="dt">Vessel</span> <span class="ot">-&gt;</span> <span class="dt">CoordF</span> <span class="dt">Weapon</span> <span class="ot">-&gt;</span> <span class="dt">Bool</span></span>
<span id="cb31-7"><a href="#cb31-7" aria-hidden="true" tabindex="-1"></a>shoot <span class="ot">=</span> zapWithAdjunction checkHit</span></code></pre></div>
<p>And of course we can try that out!</p>
<div class="sourceCode" id="cb32"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb32-1"><a href="#cb32-1" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> myBoard1</span>
<span id="cb32-2"><a href="#cb32-2" aria-hidden="true" tabindex="-1"></a>       <span class="dt">A</span>  <span class="op">|</span>  <span class="dt">B</span>  <span class="op">|</span> <span class="dt">C</span></span>
<span id="cb32-3"><a href="#cb32-3" aria-hidden="true" tabindex="-1"></a><span class="dt">I</span>   (<span class="dt">Empty</span>,<span class="dt">Empty</span>,<span class="dt">Ship</span>)</span>
<span id="cb32-4"><a href="#cb32-4" aria-hidden="true" tabindex="-1"></a><span class="dt">II</span>  (<span class="dt">Sub</span>,<span class="dt">Empty</span>,<span class="dt">Sub</span>)</span>
<span id="cb32-5"><a href="#cb32-5" aria-hidden="true" tabindex="-1"></a><span class="dt">III</span> (<span class="dt">Ship</span>,<span class="dt">Empty</span>,<span class="dt">Empty</span>)</span>
<span id="cb32-6"><a href="#cb32-6" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> shoot myBoard1 (<span class="dt">CoordF</span> <span class="dt">A</span> <span class="dt">III</span> <span class="dt">Torpedo</span>)</span>
<span id="cb32-7"><a href="#cb32-7" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span></span>
<span id="cb32-8"><a href="#cb32-8" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> shoot myBoard1 (<span class="dt">CoordF</span> <span class="dt">A</span> <span class="dt">III</span> <span class="dt">DepthCharge</span>)</span>
<span id="cb32-9"><a href="#cb32-9" aria-hidden="true" tabindex="-1"></a><span class="dt">False</span></span></code></pre></div>
<p>It's really unique how Adjunctions let us specify our data as a
functor like this!</p>
<p>Now what if we want to see what happens at each spot in the board if
we hit it with a Torpedo OR a DepthCharge? No problem;</p>
<div class="sourceCode" id="cb33"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb33-1"><a href="#cb33-1" aria-hidden="true" tabindex="-1"></a><span class="ot">hitMap ::</span> <span class="dt">Board</span> (<span class="dt">Bool</span>, <span class="dt">Bool</span>)</span>
<span id="cb33-2"><a href="#cb33-2" aria-hidden="true" tabindex="-1"></a>hitMap <span class="ot">=</span> <span class="fu">fmap</span> (<span class="fu">flip</span> checkHit <span class="dt">Torpedo</span> <span class="op">&amp;&amp;&amp;</span> <span class="fu">flip</span> checkHit <span class="dt">DepthCharge</span>) myBoard1</span></code></pre></div>
<p>We use (&amp;&amp;&amp;) from Control.Arrow which combines two
functions which take the same input and makes a single function which
returns a tuple!</p>
<div class="sourceCode" id="cb34"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb34-1"><a href="#cb34-1" aria-hidden="true" tabindex="-1"></a><span class="ot">(&amp;&amp;&amp;) ::</span> <span class="dt">Arrow</span> a <span class="ot">=&gt;</span> a b c <span class="ot">-&gt;</span> a b c&#39; <span class="ot">-&gt;</span> a b (c, c&#39;)</span></code></pre></div>
<p>Now we've got a <code>Board (Bool, Bool)</code>, Since the right
adjoint functor (Board) is distributive, flipping the the tuple to the
outside is trivial:</p>
<div class="sourceCode" id="cb35"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb35-1"><a href="#cb35-1" aria-hidden="true" tabindex="-1"></a><span class="ot">hitMap&#39; ::</span> (<span class="dt">Board</span> <span class="dt">Bool</span>, <span class="dt">Board</span> <span class="dt">Bool</span>)</span>
<span id="cb35-2"><a href="#cb35-2" aria-hidden="true" tabindex="-1"></a>hitMap&#39; <span class="ot">=</span> unzipR hitMap</span></code></pre></div>
<p>Now we've got two Boards, showing where we could get a hit if we used
a Torpedo or DepthCharge respectively.</p>
<p>Most of the functions we've written are a bit contrived. Sometimes
the adjunction-based approach was a bit clunkier than just writing a
simple function to do what you needed on a Board, but I hope this
provides some form of intuition for adjunctions. Good luck!</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Zippers using Representable and Cofree</title>
      <link href="https://chrispenner.ca/posts/representable-cofree-zippers"/>
      <id>https://chrispenner.ca/posts/representable-cofree-zippers</id>
      <updated>2017-07-05T00:00:00Z</updated>
      <summary>Using Representable and Cofree to build a zipper datatype</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/math.jpeg" alt="Zippers using Representable and Cofree">
              <p>We're going to take a look at an alternative way to define a Zipper
Comonad over a data type. Typically one would define a Zipper Comonad by
defining a new datatype which represents the Zipper; then implementing
<code>duplicate</code> and <code>extract</code> for it.
<code>extract</code> is typically straightforward to write, but I've had
some serious trouble writing <code>duplicate</code> for some more
complex data-types like trees.</p>
<p>We're looking at a different way of building a zipper, The advantages
of this method are that we can build it up out of smaller instances
piece by piece. Each piece is a easier to write, and we also gain
several utility functions from the Typeclasses we'll be implementing
along the way! It's not terribly practical, but it's a fun
experiment.</p>
<p>You can find this post as a literate haskell file <a
href="https://gist.github.com/ChrisPenner/4527dd0d9c60983562e03c28731bb3bd">here</a>
so that means you can load it up directly in GHC and play around with it
if you want to follow along! Let's get started.</p>
<p>First we'll need a few language extensions, In case you're wondering;
TypeFamilies is used by the <code>Representable</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">{-# language DeriveFunctor #-}</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# language TypeFamilies #-}</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# language InstanceSigs #-}</span></span></code></pre></div>
<p>We're going to be writing a Zipper into a list. In case you're
unfamiliar, a zipper is essentially a 'view' into a structure which is
focused on a single element. We'll call our focused view into a list a
'Tape'</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">module</span> <span class="dt">Tape</span> <span class="kw">where</span></span></code></pre></div>
<p>Go ahead and import everything we'll need:</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="co">-- http://hackage.haskell.org/package/comonad-5/docs/Control-Comonad.html#t:Comonad</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Comonad</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="co">-- http://hackage.haskell.org/package/free-4.12.4/docs/Control-Comonad-Cofree.html</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Comonad.Cofree</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="co">-- https://hackage.haskell.org/package/distributive-0.5.0.2/docs/Data-Distributive.html#t:Distributive</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Distributive</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a> <span class="co">-- https://hackage.haskell.org/package/adjunctions-4.3/docs/Data-Functor-Rep.html#t:Representable</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Functor.Rep</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a><span class="co">-- https://hackage.haskell.org/package/containers-0.5.10.2/docs/Data-Sequence.html</span></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Data.Sequence</span> <span class="kw">as</span> <span class="dt">S</span></span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a><span class="co">-- https://hackage.haskell.org/package/base-4.9.1.0/docs/Data-List-NonEmpty.html</span></span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Data.List.NonEmpty</span> <span class="kw">as</span> <span class="dt">NE</span></span></code></pre></div>
<p>Great! At this point one would typically define their zipper data
type, which for lists would look like:
<code>data Tape a = Tape [a] a [a]</code>, This represents the idea of
having a single element of the list 'under focus' with other elements to
the left and right.</p>
<p>We're trying something different, we're going to define TWO types.
One type which represents all of the POSSIBLE movements, and one which
represents a CHOICE of a specific movement.</p>
<p>First we'll define the possible movements in our tape using the
PRODUCT tape <code>TPossible</code>, we'll have a slot in our structure
for both leftward and rightward movements:</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">data</span> <span class="dt">TPossible</span> a <span class="ot">=</span> <span class="dt">TPossible</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>  {<span class="ot"> leftward ::</span> a</span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>  ,<span class="ot"> rightward ::</span> a</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>  } <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>, <span class="dt">Functor</span>)</span></code></pre></div>
<p>We're deriving Functor here too, that'll come in handy later.</p>
<p>Next we represent a choice of direction as a SUM type, i.e. we can
choose to go either LEFT or RIGHT at any given focus in the list.</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="kw">data</span> <span class="dt">TChoice</span> <span class="ot">=</span> <span class="dt">L</span> <span class="op">|</span> <span class="dt">R</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>)</span></code></pre></div>
<p>Notice that each piece contains a different piece of the information
we need, a value in <code>TPossible</code> knows what's to the left or
right, a value in <code>TChoice</code> knows which way to move, but not
what's there. This sort of relationship shows us that
<code>TPossible</code> is a <code>Representable Functor</code>.</p>
<p>Let's talk about what that means. A Representable Functor is any
functor from which you can extract elements by giving it an index. That
is; it's any functor that you can describe completely using a function
from an index to a value. Given <code>Index -&gt; a</code> you can build
up an <code>f a</code> if you have a relationship between
<code>Index</code> and <code>f</code>!</p>
<p>In our case we have such a relationship; and if we have a function
<code>TChoice -&gt; a</code> we could build up a
<code>TPossible a</code> by calling the function for the leftward and
rightward slots using <code>L</code> and <code>R</code>
respectively.</p>
<p>But we're getting a bit ahead of ourselves; we'll need to build up a
Distributive Instance first, it's a pre-requisite for the Representable
class, and in fact every instance of Representable is also Distributive;
If we like we can actually just implement Representative and use
<code>distributeRep</code> from <code>Data.Functor.Rep</code> as your
implementation of Distributive, but we'll do it the long way here.</p>
<p>Distributive can seem strange if you haven't worked with it before,
it's the dual of Traversable; Traversable can pull out other Applicative
Effects from within its structure, and so Distributive can pull its own
structure from any functor to the outside. You can define an instance by
implementing either <code>distribute</code> or <code>collect</code>.</p>
<p>Here're the signatures:</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">distribute ::</span> <span class="dt">Functor</span> f <span class="ot">=&gt;</span> f (g a) <span class="ot">-&gt;</span> g (f a)</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="ot">collect ::</span> <span class="dt">Functor</span> f <span class="ot">=&gt;</span> (a <span class="ot">-&gt;</span> g b) <span class="ot">-&gt;</span> f a <span class="ot">-&gt;</span> g (f b)</span></code></pre></div>
<p>Let's see a few examples to solidify the idea:</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">distribute ::</span> [<span class="dt">Identity</span> a] <span class="ot">-&gt;</span> <span class="dt">Identity</span> [a]</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="ot">distribute ::</span> [<span class="dt">Bool</span> <span class="ot">-&gt;</span> a] <span class="ot">-&gt;</span> (<span class="dt">Bool</span> <span class="ot">-&gt;</span> [a])</span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="ot">distribute ::</span> [<span class="dt">TPossible</span> a] <span class="ot">-&gt;</span> <span class="dt">TPossible</span> [a]</span></code></pre></div>
<p>The list here could be ANY functor, I just used lists because it's
something most people are familiar with. In many cases sequence and
distribute are interchangeable since a lot of types have
reasonableApplicative instances, but it's important to note that
<code>distribute</code> pulls a distributive functor OUT from any
wrapping functor while <code>sequence</code> from Data.Traversable
pushes a traversable INTO a wrapping Applicative.</p>
<p>A good intuition for determining whether a functor is distributive is
to ask whether values of that functor (f a) always have the same number
of elements of 'a'. If they do, and they don't have extra information
aside from their structure, then it's probably distributive. Note that
this means that we actually can't define Distributive for finite-length
lists, give it a try if you don't believe me!</p>
<p>We've got exactly two slots in EVERY <code>TPossible</code> so we can
implement distribute by creating an outer <code>TPossible</code> where
the left slot is the functor containing all the left values and likewise
for the right slot.</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">instance</span> <span class="dt">Distributive</span> <span class="dt">TPossible</span> <span class="kw">where</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="ot">  distribute ::</span> <span class="dt">Functor</span> f <span class="ot">=&gt;</span> f (<span class="dt">TPossible</span> a) <span class="ot">-&gt;</span> <span class="dt">TPossible</span> (f a)</span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>  distribute fga <span class="ot">=</span> <span class="dt">TPossible</span> (<span class="fu">fmap</span> leftward fga) (<span class="fu">fmap</span> rightward fga)</span></code></pre></div>
<p>Now that's out of the way, let's get back to Representable!
Remembering our previous definition <code>TPossible</code> is
Representable because it has exactly two slots, a left and a right which
can be indexed by <code>TChoice</code>! We need 3 things for an instance
of Representable:</p>
<ul>
<li>A type which represents our index (called Rep)</li>
<li><code>index</code> which pulls out the value at a given index.</li>
<li><code>tabulate</code> which builds up an object from a
function.</li>
</ul>
<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">Representable</span> <span class="dt">TPossible</span> <span class="kw">where</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">type</span> <span class="dt">Rep</span> <span class="dt">TPossible</span> <span class="ot">=</span> <span class="dt">TChoice</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="ot">  index ::</span> <span class="dt">TPossible</span> a <span class="ot">-&gt;</span> <span class="dt">TChoice</span> <span class="ot">-&gt;</span> a</span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>  <span class="fu">index</span> (<span class="dt">TPossible</span> l _) <span class="dt">L</span> <span class="ot">=</span> l</span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a>  <span class="fu">index</span> (<span class="dt">TPossible</span> _ r) <span class="dt">R</span> <span class="ot">=</span> r</span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a><span class="ot">  tabulate ::</span> (<span class="dt">TChoice</span> <span class="ot">-&gt;</span> a) <span class="ot">-&gt;</span> <span class="dt">TPossible</span> a</span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a>  tabulate describe <span class="ot">=</span> <span class="dt">TPossible</span> (describe <span class="dt">L</span>) (describe <span class="dt">R</span>)</span></code></pre></div>
<p>We're moving along quick! We've got the necessary tools to index into
our <code>TPossible</code> structure, which we can use to follow a
'path' through the zipper to find an element, but currently we only have
a way to represent a single choice of direction at once. We can say we
want to move right using 'R', but then we're stuck! Similarly with
<code>TPossible</code> we have places to store the value to the left and
right, but can't check the value at the current position! We can solve
the problem by wrapping our <code>TPossible</code> in Cofree!</p>
<p>Cofree allows us to promote a functor that we have into a Comonad by
ensuring we always have an element in focus and that we have a way to
move around amongst possible options while still maintaining a focus. It
does this by using an infinitely recursive structure which wraps around
a given functor (in our case <code>TPossible</code>). Let's build up a
few of these structures by combining <code>TPossible</code> with Cofree!
(:&lt;) is the Cofree constructor and has the following structure:
<code>a :&lt; f (Cofree f a)</code>.</p>
<p>Lucky for us, if we have a Representable instance for a functor f, we
get Representable of Cofree f for free! We can cheat a little and use
our Representable class to build up the data structure for us by simply
providing a describe function to 'tabulate' which returns the value we
want to appear at any given index. Remember, the index we chose for
<code>TPossible</code> is <code>TChoice</code>. The index for
<code>Cofree TPossible</code> is a Sequence of <code>TChoice</code>!</p>
<p>Let's build our first actual 'Tape' using tabulate with our Cofree
Representable instance! Here's an infinite number-line going out in both
directions from our focus:</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">relativePosition ::</span> <span class="dt">S.Seq</span> <span class="dt">TChoice</span> <span class="ot">-&gt;</span> <span class="dt">Int</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>relativePosition <span class="ot">=</span> <span class="fu">sum</span> <span class="op">.</span> <span class="fu">fmap</span> valOf</span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>    valOf <span class="dt">L</span> <span class="ot">=</span> (<span class="op">-</span><span class="dv">1</span>)</span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>    valOf <span class="dt">R</span> <span class="ot">=</span> <span class="dv">1</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="ot">numberLine ::</span> <span class="dt">Cofree</span> <span class="dt">TPossible</span> <span class="dt">Int</span></span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a>numberLine <span class="ot">=</span> tabulate relativePosition</span></code></pre></div>
<p>Kinda weird to look at eh? Effectively we're saying that if we move
left the position is 1 less than whatever we were at before, and moving
right adds one to the previous total. You could also write a recursive
version of <code>describe</code> which calculates the result by pulling
each index off of the sequence and returns the result! Let's look at
another example where we want a zipper into a finite list!</p>
<p>We'll define a function which 'projects' a list into an infinite
Cofree; we define the behaviour such that moving left 'off the edge'
just leaves you at the leftmost element and similar with the right. I'm
going to re-use our previous helper 'relativePosition' here, but this
time I'll use it to index into a list! We'll put some checks in place to
ensure we never get an index which is out of bounds, if we're given an
out of bounds index we'll just give the first or last element
respectively; i.e. the zipper will never 'fall off the end'</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">project ::</span> <span class="dt">NE.NonEmpty</span> a <span class="ot">-&gt;</span> <span class="dt">Cofree</span> <span class="dt">TPossible</span> a</span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>project l <span class="ot">=</span> tabulate describe</span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>    describe <span class="ot">=</span> (l <span class="op">NE.!!</span>) <span class="op">.</span> <span class="fu">foldl</span> go <span class="dv">0</span></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>    maxIndex <span class="ot">=</span> <span class="fu">length</span> l <span class="op">-</span> <span class="dv">1</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>    minIndex <span class="ot">=</span> <span class="dv">0</span></span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a>    go n <span class="dt">L</span> <span class="ot">=</span> <span class="fu">max</span> minIndex (n <span class="op">-</span> <span class="dv">1</span>)</span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a>    go n <span class="dt">R</span> <span class="ot">=</span> <span class="fu">min</span> maxIndex (n <span class="op">+</span> <span class="dv">1</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="ot">elems ::</span> <span class="dt">NE.NonEmpty</span> <span class="dt">String</span></span>
<span id="cb11-11"><a href="#cb11-11" aria-hidden="true" tabindex="-1"></a>elems <span class="ot">=</span> <span class="st">&quot;one&quot;</span> <span class="op">NE.:|</span> [<span class="st">&quot;two&quot;</span>, <span class="st">&quot;three&quot;</span>]</span></code></pre></div>
<p>Now we can write a sequence of directions to form a path and see
where we end up! Remember, the zipper 'sticks' to the ends if we try and
go off!</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">path ::</span> <span class="dt">S.Seq</span> <span class="dt">TChoice</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>path <span class="ot">=</span> S.fromList [<span class="dt">R</span>, <span class="dt">R</span>, <span class="dt">R</span>, <span class="dt">R</span>, <span class="dt">L</span>]</span></code></pre></div>
<p>Now we can <code>index (project elems) path</code> to get "two"!</p>
<p>All this talk and we still haven't mentioned Comonad yet! Well lucky
us; the 'free' package describes an instance of Comonad for all
<code>(Functor f =&gt; Cofree f a)</code>! So our
<code>(Cofree TPossible a)</code> is a Comonad over a for free! Remember
that a Comonad instance gives us access to <code>extend</code>,
<code>extract</code> and <code>duplicate</code> functions. You can see
their types in <a
href="https://hackage.haskell.org/package/comonad-5/docs/Control-Co%20monad.html#t:Comonad">Control.Comonad</a>.</p>
<p>We already have a way to extract an element at a given position via
'index', but don't really have a way to move our zipper WITHOUT
extracting; don't fret though, we can describe this behaviour in terms
of our new Comonad instance by using extend!</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">moveTo ::</span> <span class="dt">S.Seq</span> <span class="dt">TChoice</span> <span class="ot">-&gt;</span> <span class="dt">Cofree</span> <span class="dt">TPossible</span> a <span class="ot">-&gt;</span> <span class="dt">Cofree</span> <span class="dt">TPossible</span> a</span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>moveTo ind <span class="ot">=</span> extend (\cfr <span class="ot">-&gt;</span> <span class="fu">index</span> cfr ind)</span></code></pre></div>
<p>Great! Extend works by duplicating the Comonad meaning we'll have a
<code>(Cofree TPossible (Cofree TPossible a))</code>, then it fmaps over
the duplicated parts with the given function. The function 'move' will
move the element in each slot of the Cofree over by a given amount,
which is the same result as 'scanning' our Tape over to a given
position.</p>
<p>Cool stuff! I hope you've learned a little about Distributive,
Representable, Comonads, Cofree, and zippers! If you have any questions
find me on twitter @chrislpenner</p>
<p>Cheers!</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Shipping Haskell via Homebrew</title>
      <link href="https://chrispenner.ca/posts/homebrew-haskell"/>
      <id>https://chrispenner.ca/posts/homebrew-haskell</id>
      <updated>2017-04-24T00:00:00Z</updated>
      <summary>How to set up your Haskell project to distribute via Homebrew</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/homebrew.jpg" alt="Shipping Haskell via Homebrew">
              <p>If you're reading this I assume you already love Haskell; so I won't
convince you of why it's great to work in. One thing that isn't so great
is Haskell's story for distributing code to non-haskellers.
<code>stack install</code> is great, but most folks don't have stack
installed and compiling Haskell projects from source is a lengthy
process. These barriers prevented me from sharing my Haskell projects
for a long time.</p>
<p>Here's how I eventually set up my project to be installed via
Homebrew.</p>
<p>We'll be using Homebrew's binary deployment strategy since it's the
easiest to both set up and for users to install.</p>
<p>If you're content to build binaries using stack locally and upload
them to Github yourself then you can skip down to the Homebrew Formula
section.</p>
<h2 id="building-binaries-with-travis-ci">Building Binaries with
Travis-CI</h2>
<p>Here's a look at my <code>.travis.yml</code>:</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode yaml"><code class="sourceCode yaml"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="fu">addons</span><span class="kw">:</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">apt</span><span class="kw">:</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="at">    </span><span class="fu">packages</span><span class="kw">:</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="at">    </span><span class="kw">-</span><span class="at"> libgmp-dev</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="fu">language</span><span class="kw">:</span><span class="at"> c</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="fu">sudo</span><span class="kw">:</span><span class="at"> </span><span class="ch">false</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="fu">cache</span><span class="kw">:</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">directories</span><span class="kw">:</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="kw">-</span><span class="at"> $HOME/.local/bin</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="kw">-</span><span class="at"> $HOME/.stack</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a><span class="fu">os</span><span class="kw">:</span></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a><span class="kw">-</span><span class="at"> linux</span></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a><span class="kw">-</span><span class="at"> osx</span></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a><span class="fu">before_install</span><span class="kw">:</span></span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a><span class="kw">-</span><span class="at"> sh tools/install-stack.sh</span></span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a><span class="kw">-</span><span class="at"> sh tools/install-ghr.sh</span></span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a><span class="fu">script</span><span class="kw">:</span></span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a><span class="kw">-</span><span class="at"> stack setup</span></span>
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a><span class="kw">-</span><span class="at"> stack build --ghc-options -O2 --pedantic</span></span>
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a><span class="fu">after_success</span><span class="kw">:</span></span>
<span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a><span class="kw">-</span><span class="at"> sh tools/attach-binary.sh</span></span></code></pre></div>
<p>This is just a basic setup for building haskell on Travis-CI; we need
the additional package <code>libgmp-dev</code>, cache a few things, and
specify to build for both linux and osx. This way we'll have both linux
and osx binaries when we're done! In the pre-install hooks we install
stack manually, then install <a
href="https://github.com/tcnksm/ghr">ghr</a> a github resource
management tool.</p>
<p>You can find <a
href="https://github.com/ChrisPenner/tempered/blob/master/tools/install-stack.sh">install-stack.sh</a>
and <a
href="https://github.com/ChrisPenner/tempered/blob/master/tools/install-ghr.sh">install-ghr.sh</a>
scripts on my <a
href="https://github.com/ChrisPenner/tempered">Tempered</a> project.
They use Travis Env variables for everything, so you can just copy-paste
them into your project.</p>
<p>Inside <code>script</code> we build the project as normal you can do
this however you like so long as a binary is produced.</p>
<p>Lastly is the <a
href="https://github.com/ChrisPenner/tempered/blob/master/tools/attach-binary.sh"><code>attach-binary.sh</code></a>
script. This runs after the build and uploads the generated binaries to
the releases page on Github. It first checks if the current release is
tagged and will only build and upload tagged releases, so make sure you
<code>git tag vx.y.z</code> your commits before you push them or it
won't run the upload step. Next it pulls in your github token which ghr
will use to do the upload. You must manually add this to your Travis-CI
Environment variables for the project. Create a new github access token
<a href="https://github.com/settings/tokens">here</a> then add it to
your Travis-CI project at
<code>https://travis-ci.org/&lt;user&gt;/&lt;repo&gt;/settings</code>
under the name <code>GITHUB_TOKEN</code>.</p>
<p>The script assumes the binary has the same name as your repo, if
that's not the case you can hard-code the script to something else. At
this point whenever you upload a tagged release Travis-CI should run a
mac and a linux build and upload the result of each to your Github
Repo's releases page. You'll likely need to trouble-shoot one or two
things to get it just right.</p>
<h2 id="setting-up-a-homebrew-formula">Setting up a Homebrew
Formula</h2>
<p>You can follow <a
href="http://octavore.com/posts/2016/02/15/distributing-go-apps-os-x">this
guide by octavore</a> to set up your own homebrew tap; then we'll make a
formula. Here's what mine for my tempered project looks like:</p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode ruby"><code class="sourceCode ruby"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="cf">class</span> <span class="dt">Tempered</span> <span class="kw">&lt;</span> <span class="dt">Formula</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>  desc <span class="st">&quot;A dead-simple templating utility for simple shell interpolation&quot;</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>  homepage <span class="st">&quot;https://github.com/ChrisPenner/tempered&quot;</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>  url <span class="st">&quot;https://github.com/ChrisPenner/tempered/releases/download/v0.1.0/tempered-v0.1.0-osx.tar.gz&quot;</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>  sha256 <span class="st">&quot;9241be80db128ddcfaf9d2fc2520d22aab47935bcabc117ed874c627c0e1e0be&quot;</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>  bottle <span class="wa">:unneeded</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 class="cf">def</span> install</span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>    bin<span class="at">.install</span> <span class="st">&quot;tempered&quot;</span></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a>  <span class="cf">end</span></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a>  <span class="fu">test</span> <span class="cf">do</span></span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a>    <span class="fu">system</span> <span class="st">&quot;</span><span class="sc">#{</span>bin<span class="sc">}</span><span class="st">/tempered&quot;</span></span>
<span id="cb2-15"><a href="#cb2-15" aria-hidden="true" tabindex="-1"></a>  <span class="cf">end</span></span>
<span id="cb2-16"><a href="#cb2-16" aria-hidden="true" tabindex="-1"></a><span class="cf">end</span></span></code></pre></div>
<p>You'll of course have to change the names, and you'll need to change
the url to match the uploaded tar.gz file (for osx) on your github
releases page from step one.</p>
<p>Lastly we'll need to get the <code>sha 256</code> of the bundle; you
can just download it and run <code>shasum -a 256 &lt;filename&gt;</code>
if you like; or you can look in your Travis-CI logs for the osx build
under the <code>attach-binary.sh</code> step; the script logs out the
sha sum before uploading the binary.</p>
<p>After you've pushed up your homebrew formula pointing to the latest
binary then users can install it by running:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode sh"><code class="sourceCode bash"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Replace the names respectively</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="ex">brew</span> update <span class="kw">&amp;&amp;</span> <span class="ex">brew</span> install githubuser/tapname/reponame</span></code></pre></div>
<p>Each time you release a new version you'll need to update the url and
sha in the homebrew formula; you could automate this as a script to run
in Travis if you like; I haven't been bothered enough to do it yet, but
if you do it let me know and I'll update this post!</p>
<p>This guide was inspired by (and guided by) <a
href="http://taylor.fausak.me/2016/05/09/add-files-to-github-releases/">Taylor
Fausak's post</a> on a similar topic; most of the scripts are adapted
from his.</p>
<p>Cheers and good luck!</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Kleisli Endomorphisms</title>
      <link href="https://chrispenner.ca/posts/kleisli-endo"/>
      <id>https://chrispenner.ca/posts/kleisli-endo</id>
      <updated>2017-04-08T00:00:00Z</updated>
      <summary>Discovering an isomorphism between the Kleisli version of Endomorphisms
to the mtl StateT transformer.</summary>
      <content type="html"><![CDATA[
              <p>After listening to the latest <a
href="https://twitter.com/MagicReadAlong">Magic Read-along</a> episode
<a href="http://www.magicreadalong.com/episode/45">"You should watch
this"</a> (which you should go listen to now) I got caught up thinking
about Brian's idea of an Endomorphism version of Kleisli composition for
use with <a href="https://github.com/reactjs/react-redux">Redux</a>,
it's actually a very similar model to what I'm using in my <a
href="github.com/chrispenner/eve">event framework</a> for event
listeners so I figured I'd try to formalize the pattern and recognize
some of the concepts involved. They talk about the idea of a
Redux-reducer, which is usually of type
<code>s -&gt; Action -&gt; s</code>, it takes a state and an action and
returns a new state. He then re-arranged the arguments to
<code>Action -&gt; s -&gt; s</code>. He then recognized this as
<code>Action -&gt; Endo s</code> (an Endo-morphism is just any function
from one type to itself: <code>a -&gt; a</code>). He would take his list
of reducers and partially apply them with the <code>Action</code>,
yielding a list of type <code>Endo s</code> where <code>s</code> is the
state object the reducer operates over. At this point we can use the
Monoid instance <code>Endo</code> has defined, so we foldmap with Endo
to combine the list of reducers into a sort of pipeline where each
function feeds into the next; the Endo instance of Monoid is just
function composition over functions which return the same type as their
input.</p>
<p>This cleans up the interface of the reducers a fair amount, but what
about an alternate kind of <code>Endo</code> which uses Kleisli
composition instead of normal function composition? <a
href="http://hackage.haskell.org/package/base-4.9.1.0/docs/Control-Monad.html#v:-62--61--62-">Kleisli
composition</a> often referenced as (&gt;=&gt;); takes two functions
which return monads and composes them together using the underlying
bind/flatmap of the Monad. The type of Kleisli composition is:
<code>(&gt;=&gt;) :: Monad m =&gt; (a -&gt; m b) -&gt; (b -&gt; m c) -&gt; a -&gt; m c</code>.
If we could define a nice Endo-style monoid over this type then we could
compose reducers like we did above, but also allow the functions to
perform monadic effects (which is a bad idea in Redux, but there are
other times this would be useful, imagine running a user through a
pipeline of transformations which interact with a database or do some
error handling). We can easily define this instance like so:</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">import</span> <span class="dt">Control.Monad</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">KEndo</span> m a <span class="ot">=</span> <span class="dt">KEndo</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>  {<span class="ot"> getKEndo ::</span> (a <span class="ot">-&gt;</span> m a) }</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="kw">instance</span> <span class="dt">Monad</span> m <span class="ot">=&gt;</span> <span class="dt">Monoid</span> (<span class="dt">KEndo</span> m a) <span class="kw">where</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>  <span class="fu">mempty</span> <span class="ot">=</span> <span class="dt">KEndo</span> <span class="fu">return</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>  (<span class="dt">KEndo</span> a) <span class="ot">`mappend`</span> (<span class="dt">KEndo</span> b) <span class="ot">=</span> <span class="dt">KEndo</span> (a <span class="op">&gt;=&gt;</span> b)  </span></code></pre></div>
<p>This is great, now if we have a list of functions of some type
<code>[User -&gt; Writer Error User]</code> or something we can use
foldmap to combine them into a single function! It works 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">actions ::</span> [<span class="dt">User</span> <span class="ot">-&gt;</span> <span class="dt">Writer</span> <span class="dt">Error</span> <span class="dt">User</span>]</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>actions <span class="ot">=</span> [<span class="op">...</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="ot">pipeline ::</span> <span class="dt">User</span> <span class="ot">-&gt;</span> <span class="dt">Writer</span> <span class="dt">Error</span> <span class="dt">User</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>pipeline <span class="ot">=</span> getKEndo <span class="op">.</span> <span class="fu">foldMap</span> <span class="dt">KEndo</span> <span class="op">$</span> actions</span></code></pre></div>
<p>The whole Kleisli Endo thing is a cool idea; but this thing has
actually been done before! It's actually the same as the <a
href="http://hackage.haskell.org/package/mtl-2.2.1/docs/Control-Monad-State-Lazy.html#v:StateT"><code>StateT</code></a>
state monad transformer from mtl; let's see how we can make the
comparison. A generic Endo is of type <code>s -&gt; s</code>, this is
isomorphic to <code>s -&gt; ((), s)</code>, aka <code>State s ()</code>.
The trick is that the Kleisli Endo (<code>s -&gt; m s</code> or by
isomorphism <code>s -&gt; m ((), s)</code>) can actually be generalized
over the <code>()</code> to <code>s -&gt; m (a, s)</code> which
incidentally matches
<code>runStateT :: StateT s m a -&gt; s -&gt; m (a, s)</code> from
mtl!</p>
<p>So basically KEndo is isomorphic to StateT, but we'd still like a
monoid instance for it, Gabriel shows a monoid over the IO monad in <a
href="https://youtu.be/WsA7GtUQeB8">"Applied category theory and
abstract algebra"</a>, the Monoid he shows actually generalizes to any
monad as this instance:</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">instance</span> (<span class="dt">Monad</span> m, <span class="dt">Monoid</span> a) <span class="ot">=&gt;</span> <span class="dt">Monoid</span> (m a) <span class="kw">where</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>  <span class="fu">mempty</span> <span class="ot">=</span> <span class="fu">return</span> <span class="fu">mempty</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>  ma <span class="ot">`mappend`</span> mb <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>    a <span class="ot">&lt;-</span> ma</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>    b <span class="ot">&lt;-</span> mb</span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>    <span class="fu">return</span> (a <span class="ot">`mappend`</span> b)</span></code></pre></div>
<p>So that means we can use this instance for StateT (which is a monad).
Since <code>()</code> is a trivial monoid (where every mappend just
returns <code>()</code>) the simple case is <code>State s ()</code>
which was our <code>KEndo</code> of <code>s -&gt; ((), s)</code> but now
we have the Monoid instance, which behaves the same as the
<code>KEndo</code> instance, so we don't need <code>KEndo</code>
anymore. If we want to allow arbitrary effects we use the Transformer
version: <code>StateT s m ()</code> where <code>m</code> is a monad
containing any additional effects we want. In addition to being able to
add additional effects we also gain the ability to aggregate information
as a monoid! If you decided you wanted your reducers to also aggregate
some form of information, then they'd be:
<code>Monoid a =&gt; Action -&gt; s -&gt; (a, s)</code>, which is
<code>Action -&gt; State s a</code>, and if <code>a</code> is a monoid,
then the monoid instance of <code>State</code> acts like Endo, but also
aggregates the 'a's along the way!</p>
<p>Lastly we recognize that in the case of the Redux Reducers, if we
have a whole list of reducers: <code>Action -&gt; State s ()</code> then
we can rephrase it as the ReaderT Monad:
<code>ReaderT Action (State s) ()</code>, which maintains all of the
nice monoids we've set up so far, and becomes even more composable!</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Tail Recursion In Python</title>
      <link href="https://chrispenner.ca/posts/python-tail-recursion"/>
      <id>https://chrispenner.ca/posts/python-tail-recursion</id>
      <updated>2016-07-26T00:00:00Z</updated>
      <summary>Tail Recursion in python without introspection</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/ouroborous.jpg" alt="Tail Recursion In Python">
              <p>Some programming languages are <a
href="https://en.wikipedia.org/wiki/Tail_call">tail-recursive</a>,
essentially this means is that they're able to make optimizations to
functions that return the result of calling themselves. That is, the
function returns <strong>only</strong> a call to itself.</p>
<p>Confusing, I know, but stick with me. It turns out that most
recursive functions can be reworked into the tail-call form. Here's an
example of the factorial function in it's original form, then reworked
into the tail-call form.</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> factorial(n):</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> n <span class="op">==</span> <span class="dv">0</span>: <span class="cf">return</span> <span class="dv">1</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>  <span class="cf">else</span>: <span class="cf">return</span> factorial(n<span class="op">-</span><span class="dv">1</span>) <span class="op">*</span> n</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="kw">def</span> tail_factorial(n, accumulator<span class="op">=</span><span class="dv">1</span>):</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> n <span class="op">==</span> <span class="dv">0</span>: <span class="cf">return</span> accumulator</span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>  <span class="cf">else</span>: <span class="cf">return</span> tail_factorial(n<span class="op">-</span><span class="dv">1</span>, accumulator <span class="op">*</span> n)</span></code></pre></div>
<p>They both look similar, and in fact the original even
<strong>looks</strong> like it's in the tail call form, but since
there's that pesky multiplication which is outside of the recursive call
it can't be optimized away. In the non-tail version the computer needs
to keep track of the number you're going to multiply it with, whereas in
the tail-call version the computer can realize that the only work left
to do is another function call and it can forget about all of the
variables and state used in the current function (or if it's really
smart, it can re-use the memory of the last function call for the new
one)</p>
<p>This is all great, but there's a problem with that example, namely
that python doesn't support tail-call optimization. There's a few
reasons for this, the simplest of which is just that python is built
more around the idea of iteration than recursion.</p>
<p>But hey, I don't really care if this is something we should or
shouldn't be doing, I'm just curious if we can! Let's see if we can make
it happen.</p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode python"><code class="sourceCode python"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co"># factorial.py</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> tail_recursion <span class="im">import</span> tail_recursive, recurse</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="co"># Normal recursion depth maxes out at 980, this one works indefinitely</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="at">@tail_recursive</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> factorial(n, accumulator<span class="op">=</span><span class="dv">1</span>):</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> n <span class="op">==</span> <span class="dv">0</span>:</span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> accumulator</span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>    recurse(n<span class="op">-</span><span class="dv">1</span>, accumulator<span class="op">=</span>accumulator<span class="op">*</span>n)</span></code></pre></div>
<div class="sourceCode" id="cb3"><pre
class="sourceCode python"><code class="sourceCode python"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="co"># tail_recursion.py</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Recurse(<span class="pp">Exception</span>):</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>, <span class="op">*</span>args, <span class="op">**</span>kwargs):</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>        <span class="va">self</span>.args <span class="op">=</span> args</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>        <span class="va">self</span>.kwargs <span class="op">=</span> kwargs</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">def</span> recurse(<span class="op">*</span>args, <span class="op">**</span>kwargs):</span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>    <span class="cf">raise</span> Recurse(<span class="op">*</span>args, <span class="op">**</span>kwargs)</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 class="kw">def</span> tail_recursive(f):</span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a>    <span class="kw">def</span> decorated(<span class="op">*</span>args, <span class="op">**</span>kwargs):</span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a>        <span class="cf">while</span> <span class="va">True</span>:</span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a>            <span class="cf">try</span>:</span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a>                <span class="cf">return</span> f(<span class="op">*</span>args, <span class="op">**</span>kwargs)</span>
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true" tabindex="-1"></a>            <span class="cf">except</span> Recurse <span class="im">as</span> r:</span>
<span id="cb3-16"><a href="#cb3-16" aria-hidden="true" tabindex="-1"></a>                args <span class="op">=</span> r.args</span>
<span id="cb3-17"><a href="#cb3-17" aria-hidden="true" tabindex="-1"></a>                kwargs <span class="op">=</span> r.kwargs</span>
<span id="cb3-18"><a href="#cb3-18" aria-hidden="true" tabindex="-1"></a>                <span class="cf">continue</span></span>
<span id="cb3-19"><a href="#cb3-19" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> decorated</span></code></pre></div>
<p>Now, don't get scared by decorators if you haven't seen them before,
in fact go <a
href="http://thecodeship.com/patterns/guide-to-python-function-decorators/">read
about them now</a>, basically they're functions which are called on
other functions and change the behaviour in some way.</p>
<p>This decorator will call the function it's given and will check to
see if it wants to 'recurse'. We signal a 'recursion' by simply raising
an exception with the arguments we'd like to recurse with. Then our
decorator simply unpacks the variables from the exception and tries
calling the function again.</p>
<p>Eventually we'll reach our exit condition (we hope) and the function
will <strong>return</strong> instead of raising an exception. At this
point the decorator just passes along that return value to whoever was
asking for it.</p>
<p>This particular method helps out with doing recursive calls in python
because python has a rather small limit to how many recursive calls can
be made (typically ~1000). The reason for this limit is (among other
things) doing recursive calls takes a lot of memory and resources
because each frame in the call stack must be persisted until the call is
complete. Our decorator gets around that problem by continually entering
and exiting a single call, so technically our function isn't actually
recursive anymore and we avoid the limits.</p>
<p>I tested out both versions, the normal version hits the
tail-recursion limit at factorial(980) whereas the tail-recursive
version will happily compute numbers as large as your computer can
handle.</p>
<p>There's an <a
href="http://code.activestate.com/recipes/474088-tail-call-optimization-decorator/">alternative
approach</a> that actually uses stack introspection to do it, but it's a
bit more complex than the one we built here.</p>
<p>Hope you learned something, cheers!</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>The Interface We Need</title>
      <link href="https://chrispenner.ca/posts/dont-argue"/>
      <id>https://chrispenner.ca/posts/dont-argue</id>
      <updated>2016-02-15T00:00:00Z</updated>
      <summary>Starting with the interface can make things easier for everyone</summary>
      <content type="html"><![CDATA[
              <p>I suffer from a not-so-rare condition where as soon as a problem is
presented to me I immediately start trying to solve it with the tools I
know well. This may not sound like a bad thing, but what happens is that
I end up with a user interface built around supporting the
implementation I was planning to write, which is very rarely an
interface that anyone would actually like to use. In the worst case I
end up changing my implementation plans along the way and now we're
stuck with a crappy API designed around an implementation that doesn't
even exist! I've been learning that it's usually better to design an
interface that's elegant and does what you need, then the implementation
will fall into place from there.</p>
<p>Anyway, I ended up learning this lesson once more the other day,
here's the story: I was writing a laughably simple script and I wanted
it to be able to accept arguments from the command line. I remembered
that Python has an argument parsing module in its standard library
(argparse), but upon looking it up I remembered how much of a pain it
was to get all your arguments set up. Argparse is great in that it
allows you to do complex things with arguments, but I think there should
be an alternate path to avoid the complexity when all you need is to
grab a few arguments from the command line. Sure I could have just used
sys.argv manually, but I wanted to use command line '--options' and
parsing those out from argv would be a royal pain.</p>
<p>In the end I decided to write my own little helper module for this
sort of thing, which you can find here. The goal was to design the
simplest possible interface that just does the right thing.</p>
<p>At this point I would usually write out a few example use-cases with
an interface that I'd want to use even if I'm not sure it's possible to
implement that way. For some reason I avoided my own advice this time
and started on the implementation first. Here's an example of the
interface that resulted from my original implementation:</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="at">@supply_args</span>(<span class="st">&#39;first&#39;</span>, <span class="st">&#39;second&#39;</span>, <span class="st">&#39;third&#39;</span>, keyword<span class="op">=</span><span class="dv">42</span>, args<span class="op">=</span><span class="va">True</span>)</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> main(first, second, third, keyword<span class="op">=</span><span class="dv">42</span>, args):</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>    <span class="bu">print</span> first, second, third, keyword, args</span></code></pre></div>
<p>Hrmm, so it works, but you can see that we're writing each argument
out twice. Keyword args are also doubled, and for some reason keywords
aren't strings, whereas the other arguments are. The worst offender is
the 'args' syntax. In order to specify we want to collect extra
arguments into a list we set "args=True", then have an argument named
args below. Hrmm, all of this is a little clunky, this definitely isn't
an "it just works" scenario and honestly it's just as easy to screw up
as using argparse in the first place. It was at this point that I
realized I built it this way because it was easy to implement, not
because it was easy to use! So back to the drawing board, let's design
something we'd like to use first, then see if we can implement it!</p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode python"><code class="sourceCode python"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="at">@supply_args</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> main(first, second, keyword<span class="op">=</span><span class="dv">42</span>, <span class="op">*</span>extras):</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>  <span class="bu">print</span> first, second, keyword, extras</span></code></pre></div>
<p>Whoah, okay that's a lot simpler! No more duplication, I'd use that!
But it almost seems a bit too much like magic, is it even possible to
implement it this way? Let's try it out, one of the things we wanted was
to be able to handle '--options' on the command line, and argparse has
that ability, so we should probably take advantage of that. To that end
we need to pass the names of the arguments to argparse to set it up, how
can we do that now that we're not passing argument names to our
decorator? After a quick dive into the depths of Stack Overflow I
discovered what we need in the 'inspect' module from the standard
library.</p>
<p>The <strong>inspect</strong> module allows us to peer into code
that's running during execution. What I though was impossible is
actually pretty easy to do! Using inspect's getargspec function we can
get the names of the arguments of a function just like we need! From
this point it was just a matter of outfitting the decorator to handle
different combinations of arguments, keyword arguments, and splat
arguments properly and we can end up with exactly the API we wanted! The
code ends up being much cleaner too since we don't have to deal with as
many edge cases.</p>
<p>We ended up with a much simpler interface, one that we probably
wouldn't have even thought was possible if we'd started thinking about
the implementation too early on. This just goes to show that designing a
nice interface first can lead to better design, a much improved user
experience, and in this case: cleaner code! Remember to put the
interface first the next time you're implementing some new feature for
your app.</p>
<p>You can find the full decorator <a
href="https://github.com/chrispenner/dont-argue">here</a>, it's only a
few lines long.</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Let there be Truth</title>
      <link href="https://chrispenner.ca/posts/let-there-be-truth"/>
      <id>https://chrispenner.ca/posts/let-there-be-truth</id>
      <updated>2016-01-02T00:00:00Z</updated>
      <summary>Let&#39;s re-visit truthy/falsy.</summary>
      <content type="html"><![CDATA[
              <p>Okay, so here's the deal. The idea of "truthy" and "falsy" values is
a pretty common language pattern these days that saves us all some time
and effort. I've been thinking about it lately and I think we made a
pretty big mistake as to the implementation of this idea in most
languages, namely that 0 is usually considered "falsy". Why did we do
that? Yes, I know that it's how false was represented in C, but modern
languages aren't C and they can make their own choices. We have types
and classes and all sorts of nice tools now, we don't need 0 to
represent false.</p>
<p>So what should 0 be then? I think we should revisit this and actually
think about it rather than just allowing old limitations to make our
decision for us. I'm going to make the case that 0 should be truthy, the
argument for this is very simple: 0 is a value. In most cases where I've
seen truthyness and falsyness used in code it's used to check whether a
variable has a value; something like
<code>if(account){do stuff with account}</code>. We need to check that
the 'account' we returned from a function or API call actually exists
before we perform operations on it, ensuring that it isn't 'null' or
'None' or something like that. This case works great, but what about
this:
<code>if(number_of_accounts){do stuff} else {raise APIError}</code>?
Granted, this is a simplified case that won't come up often, but in this
case if there are 0 accounts, our code will raise an APIError rather
than executing our operation. In this case 0 is clearly a value, and so
should be considered truthy.</p>
<p>While the previous example may seem contrived, it comes from a
real-life case that I dealt with at work one day. We were doing some
pretty complex work with web forms using JavaScript and had multiple
field-types in the form. Some of these fields used numerical values, and
since <code>if (value !== null &amp;&amp; value !== undefined)</code> is
a bit wordy, in most cases we were just using <code>if (value)</code>.
This worked great in almost all cases, including checking whether or not
the user had typed in a text field (<code>""</code> is falsy).
Unfortunately we hadn't handled the case where the value of a numerical
field was 0, and were incorrectly throwing validation errors. We knew 0
was a value, but JavaScript disagreed and treats it as falsy, causing us
a bug or twelve.</p>
<p>I'm sure we're not the only ones to have made that mistake. Clever
folks can probably come up with some case where it makes sense for 0 to
be falsy, but I think that the value-checking scenario I've presented
above is the most common use-case of truthy/falsy by far.</p>
<p>It's unfortunate, but languages are largely undecided on
truthy/falsy. Python has all of <code>'', 0, {}, []</code> and
<code>None</code> as falsy values, in JavaScript
<code>0, '', null,</code> and <code>undefined</code> are all falsy, but
<code>[]</code> and <code>{}</code> are truthy! PHP even considers
<code>'0'</code> to be false! Ruby has the strict definition that only
nil and False are considered falsy, everything else (including
<code>0, '', [], {}</code>) are ALL considered true!</p>
<p>I'm still undecided as to the fate of <code>'', [],</code> and
<code>{}</code>, but I think it's time for 0 to be truthy.</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Autoenv Trick</title>
      <link href="https://chrispenner.ca/posts/auto-env-trick"/>
      <id>https://chrispenner.ca/posts/auto-env-trick</id>
      <updated>2015-09-04T00:00:00Z</updated>
      <summary>Use Auto-env to streamline your workflow.</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/autoenv.gif" alt="Autoenv Trick">
              <p>Firstly, if you haven't heard of <a
href="https://github.com/kennethreitz/autoenv">autoenv</a> then I
suggest you go check it out now. Basically it allows you to run
arbitrary shell scripts any time you enter a directory or any of its
children, it's pretty useful.</p>
<p>You can do all sorts of things with this tool, though most people use
it to configure their environment variables (hence the name). I use it
for that as well, but I've added a new trick.</p>
<p>Basically, each time you enter a project it will try to join an
existing tmux session for that project, if none exist it will create
one.</p>
<p>Here's what's in each project's '.env' file now:</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="co">#!/bin/sh</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="co"># Echo the root folder of the current git repo.</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="fu">gitroot()</span><span class="kw">{</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>    <span class="bu">echo</span> <span class="kw">`</span><span class="fu">git</span> rev-parse <span class="at">--show-toplevel</span><span class="kw">`</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="kw">}</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="co"># Reconnect tmux session</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="fu">tmuxproj()</span><span class="kw">{</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a><span class="co"># Don&#39;t attach to tmux if already in tmux</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="ot">! </span><span class="kw">{</span> <span class="bu">[</span> <span class="st">&quot;</span><span class="va">$TERM</span><span class="st">&quot;</span> <span class="ot">=</span> <span class="st">&quot;screen&quot;</span> <span class="bu">]</span> <span class="kw">||</span> <span class="bu">[</span> <span class="ot">-n</span> <span class="st">&quot;</span><span class="va">$TMUX</span><span class="st">&quot;</span> <span class="bu">]</span><span class="kw">;</span> <span class="kw">}</span> <span class="cf">then</span></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a>    <span class="co"># Attach to project tmux session if it exists, otherwise create it.</span></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a>        <span class="ex">tmux</span> attach <span class="at">-t</span> <span class="kw">`</span><span class="ex">gitroot</span><span class="kw">`</span> <span class="kw">||</span> <span class="ex">tmux</span> new <span class="at">-s</span> <span class="kw">`</span><span class="ex">gitroot</span><span class="kw">`</span></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a>    <span class="cf">fi</span></span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a><span class="kw">}</span></span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a><span class="co"># inside a project&#39;s .env:</span></span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a><span class="ex">tmuxproj</span></span></code></pre></div>
<p>I use vim with tmux extensively, and so I often set up a workplace
with several tmux windows and splits. Setting all this up and
remembering what I was working on every time I context switch can be a
bit of a pain, so now I use autoenv to manage it for me. What would
usually happen to me is that I'd set up a tmux session with all of this,
then forget about it next time I went to work on this project, but now
every time I enter a project's directory it automagically puts me back
into the session.</p>
<p>Simple! Now I can't forget!</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Semantic Versioning</title>
      <link href="https://chrispenner.ca/posts/use-semantic-versioning"/>
      <id>https://chrispenner.ca/posts/use-semantic-versioning</id>
      <updated>2015-04-02T00:00:00Z</updated>
      <summary>Semantic versioning helps, use it!</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/versioning.jpg" alt="Semantic Versioning">
              <p>So! I'm going to talk about Semantic Versioning today because it's
something that I think <em>everyone</em> should be using. Why? Because
it takes something that is largely arbitrary and meaningless and redeems
it by giving it meaning. A side effect of the system is that everyone
thinks a little more about how their software changes affect those who
actually use it.</p>
<p>How's this whole Semantic Versioning thing work? Well essentially
it's a set of conventions for how version numbers are changed when
software is altered. I recommend reading the whole description <a
href="http://semver.org/">here</a>, but I'll give you the TL;DR version.
The idea is that versions should take the form X.Y.Z where each letter
is an integer (e.g. 2.5.17). Each number has it's own meaning;
MAJOR.MINOR.PATCH</p>
<p>X = MAJOR-version: This is incremented any time the new API is not
back compatible with an API you've previously shipped. It doesn't matter
how different it is, if the API acts differently, change the MAJOR
version.</p>
<p>Y = MINOR-version: This is incremented when the API is changed, but
it's completely back compatible with previous versions of this MAJOR
release. Use this when ADDING features to your API.</p>
<p>Z = PATCH-version: This is incremented when you make bugfixes that
don't affect the API.</p>
<p>The idea is to allow devs to reason about when/how to update their
dependencies. Under this system, the dev knows that they can safely
update to any version that changes the MINOR or PATCH versions, but that
a change in the MAJOR version will mean API alterations which may break
their application.</p>
<p>It's as simple as that. Read <a
href="http://semver.org/">semver.org</a> for more info on all of this,
and start using this system TODAY!</p>
<p>Cheers!</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>BoxKite: Open-Sourced</title>
      <link href="https://chrispenner.ca/posts/boxkite"/>
      <id>https://chrispenner.ca/posts/boxkite</id>
      <updated>2015-03-25T00:00:00Z</updated>
      <summary>I&#39;ve open-sourced the code that I use to generate this blog.</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/boxkite.png" alt="BoxKite: Open-Sourced">
              <p>When I was first developing interested in web-technologies (almost
exactly a year ago now) I wanted to build some things to test my skills.
I've always believed that book learning will only get you so far, you
discover so much more about a system by building something tangible with
it. I decided as a first project to make a blog for myself. I looked at
things like Jekyll and Wordpress, but I initially had trouble
customizing Jekyll (though I'm sure I could manage it now). I didn't
think I'd learn what I wanted to from building with Wordpress, so I
decided to go with a custom solution.</p>
<p>I fiddled around and made a few handlers in a Python Google App
Engine site, adding a bit of logic to convert Markdown files into HTML
and insert them into jinja templates. This worked pretty well so I
cleaned it up, added a few functions to parse metadata about each post,
using it to build a table of contents and a site structure. Pretty soon
I had a working blog framework that I knew from front to back and it was
simple enough to extend in any way I could imagine.</p>
<p>The result is an adaptable and intuitive framework that for some
unknown reason I've decided to call "BoxKite". Check out the Source (and
installation instructions) here: <a
href="http://github.com/ChrisPenner/BoxKite">BoxKite</a></p>
<p>So why should you try out BoxKite? Well, it depends on what you want
to use it for; but here are some things that I like about it:</p>
<ul>
<li>ALL data related to a post is stored plain-as-day in the post's
markdown file. (I can't stress how nice this is for organizational
purposes)</li>
<li>No managing images or content through clunky CMS systems, just put
it in the right folder and reference it in your post or template.</li>
<li>Need to change a post or it's tags/categories/image? Just edit the
text file and everything dependent on it will be updated when you
deploy.</li>
<li>Want to add something unique to your site? Just edit the jinja
template (or CSS), everything is available to you.</li>
<li>The entire site can be exported statically if you have a vendetta
against using web-servers (or performance concerns, see the
README).</li>
<li>It's responsive and scales to the viewport size. It also reflows
content properly for a good mobile experience.</li>
<li>Did I mention that comments and social media connectivity are a
breeze? They're configured by default. You just need to input your
Disqus name.</li>
</ul>
<p>Who shouldn't use BoxKite?</p>
<ul>
<li>People who aren't interested in learning anything about
websites</li>
<li>Companies with hundreds and hundreds of posts.</li>
<li>Blogs with many authors, this set-up is great for personal blogs,
but breaks down with more than a few people posting.</li>
</ul>
<p>In conclusion, I'd highly recommend building something like this from
scratch in whatever web framework you like to use (node, rails,
appengine, etc.). It's a great way to learn, and you'll understand the
whole framework better (and web tech as a whole) as a result. This is
actually my first try at open-source and any sort of distributable
project, so take it with a grain of salt, but take a look at it, mess
around with it, and let me know what you think! Cheers!</p>
<p><a href="http://github.com/ChrisPenner/BoxKite">BoxKite at
Github</a></p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Getting Schooled</title>
      <link href="https://chrispenner.ca/posts/getting-schooled"/>
      <id>https://chrispenner.ca/posts/getting-schooled</id>
      <updated>2015-03-19T00:00:00Z</updated>
      <summary>When did schooling become more important than skill? Should we really be
discriminating against people based on the school they went to?</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/getting-schooled.png" alt="Getting Schooled">
              <p>I must prefix this discussion with the disclaimer that I haven't done
any studies nor performed official research, however I have a general
feeling, it's an atmosphere, that I've noticed. And often a shared
feeling like this, or a bias perpetuated in the media is enough to make
a difference in the way we think about things.</p>
<p>In the TV Series <strong>Suits</strong> (which I've been watching
lately) the main law firm has a strict policy wherein they hire
exclusively from Harvard. "Of course!" many people say... "Harvard is
the best!", but are they really? Is everyone who graduates from Harvard
just inherently better than those girls and guys who get their community
college degrees or go to a local state University in Mississippi
somewhere?</p>
<blockquote>
<p>When did schooling become more important than skill?</p>
</blockquote>
<p>Certainly these schools have obtained their reputations as a result
of careful planning, good professors, and a rigorous and uncompromising
gauntlet of education. This means that to make it through one of these
schools you must be rather clever, and that graduating there DOES mean
something, but I'm not convinced that it means enough to justify this
educational prejudice that I've seen.</p>
<p>These Ivy League schools require amazing marks, community
involvement, and LOTS of money for students to attend. If a student is
missing one or more of these things, they will miss out on the
opportunity to attend one of these schools, and as a result will miss
many further opportunities that they may have otherwise been been
qualified for. Many companies will pass over State University degrees
for someone from Yale without even a second thought. When did schooling
become more important than skill? Someone who made a few poor choices in
high school and didn't find their passions until a few years into
college is systematically disadvantaged from that point on. It doesn't
have to be this way!</p>
<p>I'm Canadian, and as far as I can tell, this problem hasn't gained
much traction here. I can get just as far with a degree from University
of Saskatchewan as I can with one from University of Toronto. In fact,
I'd never even heard of University of Toronto until now when I needed to
look it up to confirm that it actually exists. Companies here tend to
use degrees as a baseline requirement for a job, but not as a strong
indicator of skill or personal ability. This is good, it gives equal
opportunity to all qualified applicants and makes the job hunt about
finding the person most qualified, not the one with the most family
money or who happened to be the smartest when they were 16. Additional
benefits are that students can go to school close to home (further
reducing financial barriers to education), or can choose a school that
has programs that are interesting to them; making these choices without
fear that their future will suffer as a result.</p>
<p>Discrimination is discrimination; if a company is hiring someone
based on their age, race, religion, OR their Alma Mater instead of
solely evaluating their skills as objectively as possible, then it's
still discrimination.</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Gem: Duckling</title>
      <link href="https://chrispenner.ca/posts/gem-duckling"/>
      <id>https://chrispenner.ca/posts/gem-duckling</id>
      <updated>2015-02-21T00:00:00Z</updated>
      <summary>Check out the Duckling project</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/duckling.png" alt="Gem: Duckling">
              <p>Duckling is a very interesting project that I think exemplifies many
great design principles. It's a parser written in Clojure that can turn
natural language sentences into structured computer readable data.
Clojure, if you haven't heard, is a Lisp that runs on Java's virtual
machine. Now's a good a time as any to check it out!</p>
<p>Here are some things Duckling can understand:</p>
<ul>
<li>"from 9:30 - 11:00 on Thursday</li>
<li>"the day before labor day 2020"</li>
<li>"thirty two Celsius"</li>
<li>"seventh"</li>
</ul>
<p>Some of the design decisions that really set Duckling apart:</p>
<ul>
<li>Extensibility: Easily write your own set of rules to make it work
for your own purposes.</li>
<li>Probabilistic: Duckling doesn't always know what's right, but it'll
take its best guess and tell you how sure it is.</li>
<li>Data Agnostic: Duckling doesn't make assumptions about what you
need, it can be trained to do whatever you like.</li>
</ul>
<p>Go ahead and check out the docs and give building your own parser a
try: <a href="http://duckling-lib.org/">Duckling</a>.</p>
<p>Follow me on twitter <a
href="http://www.twitter.com/chrislpenner">@chrislpenner</a> to catch
new articles as they come!</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANkAAAAzCAYAAAAaYa2SAAAABGdBTUEAALGPC/xhBQAAC8VJREFUeAHtXQmwFMUZ/npmFpHzcQgBRSFcAnIfcimICEFEEFAEj5SlUMYkVTEKJpgQSSmSUGWMFimJUEQTFa8UEdAkGENEi0MBBQQMgiCX3Icc8t7MdP6/Z2d2dt/bdd/bHdis/Vc9tqePv3u+7r//ayzF2XvHSmjSCGgEIkPAiIyzZqwR0AgoBLSQ6YOgEYgYAS1kEQOs2WsEtJDpM6ARiBgBLWQRA6zZawS0kOkzoBGIGAEtZBEDrNlrBLSQ6TOgEYgYAS1kEQOs2WsEtJDpM6ARiBgBLWQRA6zZawS0kOkzoBGIGAEtZBEDrNlrBLSQ6TOgEYgYAS1kEQOs2WsErFwhKFlxKmAx+eIYHr60WvAcFBo3hXn1UBjtOgIlDYCyMsj9e+CuWwX3vbfpuTToqgsagWJDIGchs90EJE6iGJTMEeNgDL0JwjSDOlwIiDp1YbRuDzlkJOy5v4PctiXRrksagSJCIFJz0Rw/Eeb1Y5MFLAU8UVIf1k+mQbRql9KiHzUCxYFAZEImuvYmE3FIVigJKwbrnvuBC6pn1f+cd2rYGIK0LupfRCpYZJ6e3kU0awHRvFXhvk/mN/j/bi1A/HM2F9PtiDXilnRNFdaLuvVgkFC6S9+osD1TpfXwLBiXNE/qItnPO3yQ/L6VcP6xEDj7NdCoCapNfyqpX/jBWbEMzvOzvSrDhDl8LIxBwyGqk30bJ3nkEJxFL8Nducyv8n7rNYQ1YSJE+84QNJZJSgm5/b9wXpwDuXeX14/+Da9XOg7KptwNnE74tubNd8EcdH3Q3573JNwP36/c+oPRyQVz+M0wb/D2Rp46ibKfTQRsO7lTypPxvdGwRo5PqpUuOQeHDsD9dAOcxa8CJ44F7enmEC1aIzZlRtAvXaH0wbtgXDWk/JyEFY4egvv5VjhLaM79exMsqoi/vfAFuHw+4mQMHQVr1G3qqfQ+won2MFeKRpNRoEM0aVbptRldrqz0mPAA3nh5aD/kscMQsWoQ37kY5rAxsO68L9xNlaVjQ5Lghf9gl3n9DAPWA9M9U5cETLou5NdnVJuoT8L0/R/CuGZYwFM0vRSxaU/AuKKbEjB58ivI40dJ6QkYLdvC+vlvINp1CvqHC+yrGh27h6vKPSc1xh8yrr+iAfE6o8/AoFXUrAWjU8/gOZsCC6b86jhpdAOCLi2ThCE25TGgRs1geK5zBIziBcaS9xW0D4KsCrNnf8Qeehxo0Ej1yAV/ky4Q0AUfJUWiyfhwV4WqOi6Y6/gxlP3yR94jbUaMNBxrIdG5F2Amv6q77O9wXnsuGBouGAOHwfhuW1XlrF5OmuiPKgIqOnSBNfEBJcDm6DvgkuYDCZ85YZKah7WS86enPa1Do8XlHWFNehDiwhqk5Sah7Nc/TYqk8mEVtSkA1KUX3FXvqvlEk0sgLmoMeYLaKDiUjjKtP90YNnkFHUx1Ga1fo+Y1+lwDd+2KdEPK1duzZ0CSJgGt27r1Hhjdeiueis+/FiuzOt0ccuc2lE4mrR2n2CO/Bws6ayb7DzP9aoAEOUz2nFnenHRxmjfeCnPwCIWp2W8QnDcWVBl/noPPhzn6djjznw5PmddyJJqMfawqkZUsCFXi4Q86fAA4c1o9STYrSHNlSyaZiEwsBM5fnvFMTdZmG9YqYZBnTkHu3K6EQVzWUmkr7u+u+k8gYGr8lg1w6eAx8Q2cqrHUYeW29l0AOkCqX1yryR10kPNMLAhMPK+zOi7U7UnD1imp/EyMTchk5ouBKeMchCFOnkj8+aYY7024Pt1qyAVwN65NtNaohZzw/3KP4mX2uhoifqkmmOevlMdTnViUPHIw8VCZEvk7ORFpDPOm28npoeBD2ysg6jWA8qFenV+OrdGha7nD5S57C3LPFxTgaKj6q7RCSg7PeWkunBfmBPyM3gODsty8Pij7BZcEzfeBRFMyoUNaw6WbnQ8J+6NsTsr1H5L51kMNdT9ZF5R9XuHftOsnH7BCoqASax0md80KyI3rlKksuP7KAeQL/63CYWkra9WB2XdQ0Cz37laBnrzO4XOnfQULFGl5k9JBPrmbPkpySyqN/56dEHQBG517whx3N+yZD/ms8/objZDt2Ab2S0St2pVaLB+sXEipfsq7hYk3Ihx08NuUv5Zi1soNayApAMG+FJPyPfwB/i87/GGKCyRXVdQ/qS7UV7Ggm9wlwTKvuk5ttLPtU4gWbSBLz1JAYWN4lnLltOtPI2QGRXtZoDgYo8xD1go8N/k3Jvlp2QqZdS8dRNY8fDGQ78okSSNwIMjo1icvc6S+bOzHv0itgrP8n5CfkJBRoMKnJKzjlUl1KfgLCNivP48YuQHGpS1g9Bvss8rrbyRCRkY/nHeWwCL7OVuSFHRwSJPkQuzHsM/AxBqCE+Fm/8EUkOiKsqk/SGLNX5s47y1NqpO7d3qmYbxW1KWvU1KJ0wwc5fKDJOyQx4lzfqmxKNZSPinn3X+I/7off+AJGWkwuXWTOris/VBK0dEMlHb9acYYfT1Tkc0yX/uKmGfWKz/wslZkAn+WZnSoujq9P5t9ZDK7FL2VW9ZDRW/pYsjbHKHpuOiy6Ux4GG06qBbPT37W65Uj/jj4Jdy3F4EDIOaN4+C+m3wmvEly+zcaIaM1cSje7dQdRvPWWa3QWfiiCgln1TldJ44YfrFdtfKv4M+5rr0Bgj7lEi0vp2DCsWAkm7Ry08fBc7ggj1J0kkxN0aa9MlNw+mTQbI65kw7TIDIrd8JZMA9yXyI0L9ifigcw/AFhP6wijSopBM6RS0Hml+/PuOT7fRNlWn+5sQ0bBcl+DrRYoyaU68IRQScLIbOfnO4FIVI55HGOVNbOK/PVnNb9jyhB40CRU7c+cPxIzvjzXM5bf6WLZ4A6J0afAanT5/zs6fuc2VTAgG56e/ZMuN/wuRSbLzZFiPwAQQWcqlZFiWOO7iUoVcckWlJLzr/fVFVsfqokOQkcKChjdO+rtACH3dlcYwGTu3ZAaR4awSaZ0f86UqOeuSlIOxkDhipebFJx4KQcUY7KF3b/pnY3rinXLZcKk/xGNoE5FWGTP2k/Nzv4C9beo596x6rOcy7m4Pwkk6h2AVkpt6hyzvgzF9LCzut/VvwEf3CQZ4pMk6l1kmliP/ErsnWvhUl5pXDujM1DdlSdJa9lZ6Zk8+J1SxB7nIISdKDCZppLWk1u3wrQbesTJ5nDuS6ul+QH2U89CvedN+H26O/Z6RSQqDbjGUj6qNk3r7iv89KzKnzPZXvBXMQmP0rh6NqwbpsEOeYOleD1fVJOjNucBkgT4XTXf5AISuz6HDh2BKDkaibKtP7UcXxLM3EgR32QHerAkVKDLiM/Z1aZcH6IjdIEUc8hP9usLjRer9K8ZOaBLq9c8ed1c7LfpY8h+HvafFO0QqZW78JdvlT9KWeZv8K3SyHpawH1FUYe30h9aUF+ERPnrEBhfJdMQmfxK4RicsBCBTeEmTS7pASrIhIGe9ZUstHHk2YarHIyvoBxOoC/EpAfrU6MpTrOgXHeSHSkhDRpQCaVj9q62ROwA/sS/VNKbB5yX16/DIeoU/qFHzOuP9RRkB/DeSsmd+3KUItX5OCBMldpzSrXFYp+luucpuJczOFP7Sxa4F0KhJU1cgI4h8ZffuSCf8D75XkQU3+r9sGvy8evyPV/nVTr/cTnQFOaxTCtov/UJR8rPZ882PQsqQdJjj7o64OMRBE39gXZvJT7KA/jB0gyDtKNeUOgAPGPXpPlDb3zyIiDJNnm/jhpvW/3eVzst3zqAsQ/usDHt3yv9etrBHwEtJD5SOhfjUBECORsLp7sVzOipWm2GoHiQEBrsuLYR/0WBYyAFrIC3hy9tOJAQAtZceyjfosCRkALWQFvjl5acSCghaw49lG/RQEjoIWsgDdHL604ENBCVhz7qN+igBHQQlbAm6OXVhwIaCErjn3Ub1HACGghK+DN0UsrDgS0kBXHPuq3KGAEtJAV8ObopRUHAlrIimMf9VsUMAJayAp4c/TSigMBLWTFsY/6LQoYgf8BIVTf3IgGuLEAAAAASUVORK5CYII=" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Worth a Read #4 - Unix Tools</title>
      <link href="https://chrispenner.ca/posts/worth-a-read-4"/>
      <id>https://chrispenner.ca/posts/worth-a-read-4</id>
      <updated>2015-02-13T00:00:00Z</updated>
      <summary>Check out these posts!</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/unix-prompt.png" alt="Worth a Read #4 - Unix Tools">
              <p>Okay! This time we're reading about cool and useful Unix tools. We've
got some wargames to start us off, a fun way to learn Unix better
through a series of challenges. Next is a great series of articles
regarding using Unix as a development environment, then an overview of
awk and tmux, some of the most useful Unix tools that I use. Finally a
list of some other cool tools you may want to check out. I hope you find
that it's worth a read!</p>
<p>Follow me on twitter <a
href="http://www.twitter.com/chrislpenner">@chrislpenner</a> to keep up
with future posts!</p>
<h3 id="worth-a-read">Worth a read:</h3>
<ul>
<li><a href="http://overthewire.org/wargames/bandit/">Some fun wargames
to learn the secrets of Unix</a></li>
<li><a href="http://blog.sanctum.geek.nz/series/unix-as-ide/">Using Unix
as an IDE</a></li>
<li><a
href="http://code.tutsplus.com/tutorials/intro-to-tmux--net-33889">Overview
of tmux, a session manager</a></li>
<li><a href="http://www.vectorsite.net/tsawk.html">Basic 'awk' overview,
the swiss-army knife of text filtering</a></li>
<li><a href="http://kkovacs.eu/cool-but-obscure-unix-tools">A list of
cool and useful tools, pick a new one to learn</a></li>
</ul>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Vim vs. Emacs?</title>
      <link href="https://chrispenner.ca/posts/vim-vs-emacs"/>
      <id>https://chrispenner.ca/posts/vim-vs-emacs</id>
      <updated>2015-02-06T00:00:00Z</updated>
      <summary>I&#39;ve tried out both; here are some thoughts</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/vim-vs-emacs.png" alt="Vim vs. Emacs?">
              <p>So about a year ago I realized that as someone going into Computer
Science as a career I would be typing for the rest of my life. Somewhere
on the vastness of the internet I read that learning how to properly use
a text editor (or, how to use a proper editor) would not only help me
type faster, but also that being able to get what's in my head onto the
screen efficiently would help keep me focused on the task at hand. These
posts all came with the disclaimer that it would take time, effort, and
that learning something new would slow me down at the start. However, if
I can spend a few hours here and there to save myself countless hours
throughout my career, it doesn't take complex mental math to see that
it's a worthwhile thing to do.</p>
<p>I started researching the best editor to learn, there're hundreds out
there, and most shortcuts and advanced techniques tend to be
non-transferable (at least among the more complex editors). After a
short period of watching some videos and reading a thing or two I
quickly uncovered the presence of the everlasting holy war between Emacs
and Vi users. Personally I've never been interested in participating in
fanboy-ism. I don't particularly care what anyone else uses; as long as
I'm content and efficient with what I have. Unfortunately though, due to
the holy war it's nearly impossible to get any sort of objective
assessment of the pros and cons of each editor.</p>
<p>Nonetheless I picked one and started spending some time with it. One
thing is for certain, learning a new system definitely changes the way
you approach data entry. I felt pretty much useless and slow at first,
but held to my stubbornness and waited it out. It wasn't long before I
had the basics down, and I realized that having something so amazingly
customizable was really an amazing thing. In fact, thinking of it now I
can't come up with a single other system that I use that offers this
level of highly accessible customization. My car doesn't let me record a
macro of me backing out of my driveway, (probably a good thing), I can't
easily get my web-browser to load specific sites dependent on the time
of day, heck I can't even change most keyboard shortcuts in my OS. The
customization quickly became an addiction, I'd think constantly about
how I could improve my work-flow or shave a few keystrokes off of a task
I do often. Granted, all this thought and consideration often caused me
to take an hour or so to figure out something that saved me a total of
30 seconds; but in that hour I'd also learn 2 or 3 other tricks that
would also save me 30 seconds each time I used them. It became really
fun actually to find new tricks and improve my expertise, and now I
consider myself something of a Guru in my editor of choice (though I
still have endless amounts to learn).</p>
<p>This post isn't to tell you which editor to use, I'd sooner help you
decide whether you should bother learning one at all. First, if you're
not a programmer, writer, or typist, I'd say it's probably just not
worth the effort. I absolutely love these editors, but that's because as
a programmer I'm often doing complicated reformatting, refactoring,
editing dozens of files at a time, and testing code alongside it. If all
that you do is type up an essay now and again or write up your grocery
list, you're just not going to get a very good return on your
investment. If you fit into one of the typing-centric categories however
it MAY be worth your while. If you spend a lot of time in code then I'd
say it's worth it (even if you're already far along in your career).
Note that Vim and Emacs actually do relatively little in the way of
helping with your TYPING, but rather help almost exclusively with
EDITING and ORGANIZATION.</p>
<p>Without further delay, here's a list of objective (see: opinionated)
pros and cons (take with a grain [or boulder] of salt).</p>
<h2 id="emacs">Emacs</h2>
<p>Emacs is often mocked by Vim users as "A great operating system,
lacking only a decent editor", while Emacs users would disagree, there's
still a shadow of truth in this statement. Emacs prides itself on being
able to organize your projects, write your email, play Tetris, compile
your code, and even tie your shoes for you in the morning! (Oh and it'll
edit text too!)</p>
<p>This means that if you choose Emacs you'll likely end up using Emacs
for almost everything text related, which is great actually because it
means you'll only need to learn one set of shortcuts and one
interface.</p>
<p>Emacs is also great (and far ahead of Vim) when it comes to doing
more than one thing at once, and for being able to run and check code as
you work on it. It's the defacto editor of most Lisps (it's also written
in a Lisp variant, which helps) because it's a cinch to get a shell or
REPL running alongside your project. All of these things are possible in
Vim too of course, though you'll be in for more than a few
headaches.</p>
<p>The downsides of emacs include the famed 'Emacs-pinky', a reference
to the strain and difficulty of inputting some of Emacs's long mapping
sequences. Since Emacs has decided to leave the keyboard open for typing
it means all editor commands and shortcuts use one or more modifiers
like control or alt to enter. This has the benefit of letting beginners
type away on the keyboard as they expect it to work, but these
complicated sequences can get tiresome and difficult to remember later
on.</p>
<p>Emacs has <strong>strong</strong> extensibility in the way of plugins
and sheer Lisp hackability. If there's something you want to do, you can
probably find an Emacs plugin to help you do it, or build one yourself.
You'll need to learn a bit of eLisp to do accomplish anything, but it
makes sense and comes with a lot of power once you get used to it.
Though honestly in most cases whichever functionality you require is
probably already a part of some plugin in the repository.</p>
<h2 id="vim">Vim</h2>
<p>First off, Vim is a modal editor, that is to say that keys on your
keyboard will do different things depending on which state the editor is
in. This is both its weakest and strongest point. Most user interface
designers will tell you that modes should be avoided whenever possible,
consult the insightful <a
href="http://www.azarask.in/blog/post/is_visual_feedback_enough_why_modes_kill/">Aza
Raskin</a> for further study. However, in this case the modes are
central to the whole design, so although they definitely confuse new
users, seasoned Vimmers never forget which mode they're in because they
use them very particularly, staying in 'normal' mode always except when
switching to insert or visual mode for a quick change.</p>
<p>Vim takes a different design philosophy and runs with it. Vim is
about having a dialog with your editor. You tell it what you want it to
do and where to do it and Vim will happily oblige. It's best to think of
Vim commands and shortcuts more as a language than as individual
keypresses. For example, to change a paragraph to something else you
position the cursor within the paragraph and press the keys (ignore the
quotes) "cip". This is a small statement in Vim's 'language' that states
(c)hange (i)nside this (p)aragraph. It has a verb (change) and an object
to do the verb to (inside the paragraph). This system makes it very easy
to remember Vim commands because you only need to spell out what you'd
like to do (most keys have a pretty good mnemonic associated with them).
Once you learn an action for use in one area you can automatically
assume it'll also work on the other object and motion commands you
already know.</p>
<p>Vim excels at editing the text that's in front of you as quickly and
efficiently as possible. What it lacks in organization it makes up for
in speed. It boots up in milliseconds and works just as well over ssh as
it does locally. It's installed <em>almost</em> everywhere and like
Emacs has a large userbase that is constantly adding functionality in
the way of plugins.</p>
<p>Vim is very easy to customize, maybe not as easy as ticking boxes in
a preferences panel, but you can get it to do almost anything you'd like
if you think about it. One of the beautiful things about creating vim
commands or mappings is that it uses the same interface as normal
editing. The mapping you need is exactly what you'd type inside the
editor. This means that the more you learn in the main editor, the more
customization options you unlock.</p>
<p>Unfortunately if you'd like to write any plugins or more complex
functions you'll need to learn some Vimscript, which honestly is simply
an atrocious language (nearly everyone agrees).</p>
<p>Another area Vim currently has trouble is mostly related to
concurrency. Vim is primarily single-threaded and so can't do more than
one thing at a time. This currently is being addressed in an offshoot
called NeoVim, (see my post on that <a
href="http://www.chrispenner.ca/post/gem-neovim">here</a>), though it's
got a bit of a way to go yet. Vim isn't great at multitasking or doing
complex tasks like email or chat, but it's blazing fast at doing the
editing it's designed for.</p>
<h2 id="summary">Summary</h2>
<p>So, there's good and bad to each, though they definitely do fill two
different niches at the end of the day, if only we could have both... oh
wait! There's a way to do that actually. There's a plugin called Evil
that emulates Vim's modal interface almost flawlessly within Emacs. This
allows the quick and effective editing commands of Vim within the
adaptability and all-inclusiveness of Emacs. Some would say this is the
way to go, the best of both worlds, but the jury is still out on this
one.</p>
<p>Some things to check out (check back for more posts on getting
started soon):</p>
<ul>
<li>Type vimtutor on your terminal to get started on Vim.</li>
<li>Download &amp; open Emacs then press Ctrl + h, t for an Emacs
starter.</li>
<li>Bling has written some great articles on Emacs, Vim, and their
intersection <a
href="http://bling.github.io/blog/2013/10/16/emacs-as-my-leader-evil-mode/">here,</a>
<a
href="http://bling.github.io/blog/2013/10/27/emacs-as-my-leader-vim-survival-guide/">here,</a>
and <a
href="http://bling.github.io/blog/2013/10/16/emacs-as-my-leader-evil-mode/">here.</a></li>
</ul>
<p>Anyways, I hope you consider putting in a bit of an investment to
save yourself time in the long run! It's totally worth it, no matter
which tool you use (Sublime Text is pretty good too!). Drop a comment or
find me on twitter if you have any questions. Cheers!</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Gem: Font-Awesome</title>
      <link href="https://chrispenner.ca/posts/gem-font-awesome"/>
      <id>https://chrispenner.ca/posts/gem-font-awesome</id>
      <updated>2015-01-21T00:00:00Z</updated>
      <summary>Check out Font-Awesome</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/font-awesome-logo.png" alt="Gem: Font-Awesome">
              <p>Not all open-source projects are software or code! Here's a project
that has definitely helped me out as I build various websites.</p>
<p>Their site states their project best: "Font Awesome gives you
scalable vector icons that can instantly be customized — size, color,
drop shadow, and anything that can be done with the power of CSS." This
has many advantages over using images for these icons. Firstly they can
be included with other text in-line without any trouble, no need to
worry about margins/padding etc. The icons will also scale with their
font size according to the CSS. Lastly (this was a game-changer for me)
you can change the colour of the icons in any way you can change
text-colour. This makes mouse-over responsive buttons a cinch and also
means you don't need to recolor every icon on the site when you change
your colour-scheme.</p>
<p>All of these perks are on top of the fact that you don't need to hire
an artist to create these icons in the first place, they've got quite a
comprehensive collection already.</p>
<p>TLDR:</p>
<ul>
<li>Every type of icon you could need available as one easy font.</li>
<li>Icons scale, change color, and react like text.</li>
<li>Free!</li>
</ul>
<p>Go ahead and check out the icons and maybe even add one of your own
here: <a
href="http://fortawesome.github.io/Font-Awesome/">Font-Awesome</a>.</p>
<p>Follow me on twitter <a
href="http://www.twitter.com/chrislpenner">@chrislpenner</a> to catch
new articles as they come!</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Worth a Read #3 - Typography</title>
      <link href="https://chrispenner.ca/posts/worth-a-read-3"/>
      <id>https://chrispenner.ca/posts/worth-a-read-3</id>
      <updated>2015-01-13T00:00:00Z</updated>
      <summary>Check out these posts!</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/typography-t.png" alt="Worth a Read #3 - Typography">
              <p>This time we're talking typography. Some would say that good
web-design is 90-99% typography. I'll let you decide whether you want to
believe that, but regardless a few more tools in the typography
tool-chest sure doesn't hurt. Here are a few articles to check out.</p>
<p>Follow me on twitter <a
href="http://www.twitter.com/chrislpenner">@chrislpenner</a> to keep up
with future posts!</p>
<h3 id="worth-a-read">Worth a read:</h3>
<ul>
<li><a href="http://typ.io">Some well curated heading &amp; body font
pairings</a></li>
<li><a href="http://tendollarfonts.com/">Beautiful Ten Dollar
Fonts!</a></li>
<li><a href="http://femmebot.github.io/google-type/">Some very beautiful
handpicked font-pairs from (Free) Google Webfonts</a></li>
<li><a href="http://hellohappy.org/beautiful-web-type/">More of the best
(Free!) Google Webfont pairings</a></li>
<li><a href="http://flippingtypical.com/">Display and peruse all the
fonts on your computer</a></li>
<li><a href="http://trentwalton.com/2012/06/19/fluid-type/">A discussion
of adapting typography to the web. Mostly here because I just really
wanted to link to Trent Walton, he's a typography/web-design
genius</a></li>
<li><a href="https://tobi.oetiker.ch/lshort/lshort.pdf">A not so short
introduction to the LaTeX document layout and typesetting
system</a></li>
</ul>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Gem: Git</title>
      <link href="https://chrispenner.ca/posts/gem-git"/>
      <id>https://chrispenner.ca/posts/gem-git</id>
      <updated>2015-01-05T00:00:00Z</updated>
      <summary>Check out git</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/git-logo.png" alt="Gem: Git">
              <p>Speaking of open-source gems, it's tough to make it too far into this
topic without mentioning Git. If you've been at all involved in the open
source community recently then you're certainly familiar with it
already. If not, then learning Git is a great place to start your
journey into open-source tech.</p>
<p>Git is a distributed version control system that has taken the
open-source world by storm. In contrast with most previous version
control systems, everyone working on a project has access to their own
copy of the source files. They can change them as they like, and then
may merge their changes back into the main repository when their change
is complete. This method allows hundreds of people to work on the same
project at a time, and git's focus on branching and merging makes it
painless to add experimental features. In addition to it's unique
design, git is also blazing fast in comparison with it's
competition.</p>
<p>Git has seamless integration with Github, a website dedicated to
hosting open-source software that is managed with git. At any rate, I
can yammer on about it, or you can just go check it out and start using
it.</p>
<p>TLDR:</p>
<ul>
<li>Git's <em>Distributed</em> nature allows hundreds of people to work
on a project at the same time.</li>
<li>Git is fast and is built around the ideals of quick branching and
merging</li>
<li>Git's integration with Github (for hosting) make it a great choice
for hosting open-source projects.</li>
</ul>
<p>If you want to check out the source, of course you can find it on <a
href="https://github.com/git/git">Github</a>, read the documentation to
learn how to contribute.</p>
<p>Follow me on twitter <a
href="http://www.twitter.com/chrislpenner">@chrislpenner</a> to catch
new articles as they come!</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Procedural Generation is the Future</title>
      <link href="https://chrispenner.ca/posts/procedural-content"/>
      <id>https://chrispenner.ca/posts/procedural-content</id>
      <updated>2015-01-03T00:00:00Z</updated>
      <summary>Procedural generation allows us to build incredibly vast and rich
systems</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/no-mans-sky.png" alt="Procedural Generation is the Future">
              <p>I 've been noticing a trend in gaming recently towards procedurally
generated content. <a href="https://minecraft.net/">Minecraft</a> has
it, <a href="http://playstarbound.com/">Starbound</a> and <a
href="http://terraria.org/">Terraria</a> have it, and randomized
rogue-likes are running amok. No longer do we just play the same level
over and over again until we memorize it well enough (remember Super
Mario Bros?). The new gaming paradigm is one of discovery and adventure!
While I know from experience that meticulously planned dungeons and
carefully crafted levels can deliver an amazing experience, there are
several reasons as to why I think the trend towards procedurally
generated content is a good one.</p>
<p>These are some of the primary benefits I've discovered in using
procedural generation:</p>
<ol>
<li><strong>PG Allows you to produce near unlimited amounts of
content.</strong></li>
<li><strong>PG Saves disk space.</strong></li>
<li><strong>PG Spikes Creativity</strong></li>
</ol>
<h2 id="1-pg-allows-you-to-produce-near-unlimited-amounts-of-content">1)
pg allows you to produce near unlimited amounts of content.</h2>
<p>If <a href="https://minecraft.net/">Minecraft</a> or <a
href="http://terraria.org/">Terraria</a> had been built by hand with
only one world to explore, people would have figured out its tricks,
read about them online, figured out the quickest way to their goal and
would be done with them by now. A key part of what makes these games
special is that they have amazing replay value because the whole world
changes every time you start over. You can explore as far as you like,
the developer didn't need to put bounds on the world because the
computer can just follow its rules and continue to create! A procedural
generation approach lets your world create and discover itself!</p>
<h2 id="2-pg-saves-disk-space">2) pg saves disk space.</h2>
<p>One amazing and mostly unintended benefit of generating your world on
the fly is that an entire game world can be represented as a seed value
of just a few letters or numbers. If a part of the world hasn't been
altered, then any given section of that world can be regenerated as
needed from the seed value. Since math doesn't change, it will turn out
the same every time. In a world like <a
href="https://minecraft.net/">Minecraft</a> where the world morphs and
changes, only the differences from the generated world need to be
remembered and can be applied like a patch. This means that in a game
like <a href="http://www.no-mans-sky.com/">No Man's Sky</a> with 18
quintillion planets, every one of those planets can be remembered with a
single seed value taking up no more than a few bits.</p>
<h2 id="3-pg-spikes-creativity">3) pg spikes creativity</h2>
<p>When things are randomly generated, sometimes they don't always go
according to plan. While this is one of the bigger frustrations with
creating this sort of game, it's also one of the best sources of
inspiration. Did a bug in your system accidentally create an entire city
under the ocean biome? Cool, that might be fun! Uh-oh, gorillas are
accidentally spawning all over the north pole, what would a tribe of
arctic apes look like? The unexpected nature of generators like this can
spark some interesting ideas. I can't remember how many times I've been
cruising through Spelunky when something so beautifully unplanned causes
my run to come to a hilarious and unpredictable demise.</p>
<h2 id="case-study">Case Study</h2>
<p>Let's examine two cases, that of Assassin's Creed and that of No
Man's Sky, which is unreleased at the writing of this article, however
most of its design principles have been announced through various
developer interviews. Assassin's Creed is made by Ubisoft, a corporate
giant; ballpark estimates for the number of employees working on <a
href="http://assassinscreed.ubi.com/en-us/games/assassins-creed-black-flag.aspx">Assassin's
Creed IV: Black Flag</a> range between 900 and 1000 people. In the other
corner we have Hello Games, a team of less than a dozen people who are
developing No Man's Sky, a far reaching game about space exploration
that according to the developers could have as many as 18 quintillion
possible planets. How is it that it takes a team of over 900 people to
craft one world, when a team of 10 can craft 18 quintillion? It's a
matter of where they've invested their effort.</p>
<p>Ubisoft is using a more traditional development paradigm. They are
designing their world by hand, carefully crafting graphical assets to
fit that world as it is designed. This means that every window,
building, nook and handhold are intentionally placed, by hand, in spots
that a designer chose. This method, while effective, is clearly time
consuming and can sometimes seem too contrived.</p>
<p>Hello Games on the other hand have decided to leverage the full power
of their paradigm and have decided to put their hard work into creating
a clever system that will do the rest of their work for them. They
decided that instead of crafting worlds, they would create a
world-crafter. The initial work-load to do this is substantial, but the
payoff is that now they can create as many worlds as they like with
little effort, able to tweak their algorithm as they go along.</p>
<p>The take-home point here isn't that every game should be using
procedural generation, but rather that every developer should at least
<strong>consider</strong> whether it's appropriate for their current use
case. Who knows, could end up saving you a ton of time and adding some
awesome new features.</p>
<p>Cheers everyone!</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Worth a Read #2 - CSS</title>
      <link href="https://chrispenner.ca/posts/worth-a-read-2"/>
      <id>https://chrispenner.ca/posts/worth-a-read-2</id>
      <updated>2014-11-10T00:00:00Z</updated>
      <summary>Check out these posts!</summary>
      <content type="html"><![CDATA[
              <p>This Worth A Read highlights some articles about CSS. See how the
pros do things and learn a new trick or two.</p>
<p>Follow me on twitter <a
href="http://www.twitter.com/chrislpenner">@chrislpenner</a> to keep up
with future posts!</p>
<h3 id="worth-a-read">Worth a read:</h3>
<ul>
<li><a href="http://codepen.io/chriscoyier/blog/codepens-css">Overview
of CodePen's CSS Organization and Design</a></li>
<li><a href="http://codyhouse.co/gem/icons-filling-effect/">Learn how to
create an icon-filling scroll effect</a></li>
<li><a
href="http://www.hugeinc.com/ideas/perspective/why-the-best-designers-dont-specialize">Why
the best designers don't specialize</a></li>
<li><a
href="http://demosthenes.info/blog/908/The-First-CSS-Variable-currentColor">The
first CSS variable: currentColor</a></li>
<li><a
href="http://alistapart.com/blog/post/ten-css-one-liners-to-replace-native-apps">Ten
CSS one-liners that replace native-apps</a></li>
</ul>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANkAAAAzCAYAAAAaYa2SAAAABGdBTUEAALGPC/xhBQAAC8VJREFUeAHtXQmwFMUZ/npmFpHzcQgBRSFcAnIfcimICEFEEFAEj5SlUMYkVTEKJpgQSSmSUGWMFimJUEQTFa8UEdAkGENEi0MBBQQMgiCX3Icc8t7MdP6/Z2d2dt/bdd/bHdis/Vc9tqePv3u+7r//ayzF2XvHSmjSCGgEIkPAiIyzZqwR0AgoBLSQ6YOgEYgYAS1kEQOs2WsEtJDpM6ARiBgBLWQRA6zZawS0kOkzoBGIGAEtZBEDrNlrBLSQ6TOgEYgYAS1kEQOs2WsEtJDpM6ARiBgBLWQRA6zZawS0kOkzoBGIGAEtZBEDrNlrBLSQ6TOgEYgYAS1kEQOs2WsErFwhKFlxKmAx+eIYHr60WvAcFBo3hXn1UBjtOgIlDYCyMsj9e+CuWwX3vbfpuTToqgsagWJDIGchs90EJE6iGJTMEeNgDL0JwjSDOlwIiDp1YbRuDzlkJOy5v4PctiXRrksagSJCIFJz0Rw/Eeb1Y5MFLAU8UVIf1k+mQbRql9KiHzUCxYFAZEImuvYmE3FIVigJKwbrnvuBC6pn1f+cd2rYGIK0LupfRCpYZJ6e3kU0awHRvFXhvk/mN/j/bi1A/HM2F9PtiDXilnRNFdaLuvVgkFC6S9+osD1TpfXwLBiXNE/qItnPO3yQ/L6VcP6xEDj7NdCoCapNfyqpX/jBWbEMzvOzvSrDhDl8LIxBwyGqk30bJ3nkEJxFL8Nducyv8n7rNYQ1YSJE+84QNJZJSgm5/b9wXpwDuXeX14/+Da9XOg7KptwNnE74tubNd8EcdH3Q3573JNwP36/c+oPRyQVz+M0wb/D2Rp46ibKfTQRsO7lTypPxvdGwRo5PqpUuOQeHDsD9dAOcxa8CJ44F7enmEC1aIzZlRtAvXaH0wbtgXDWk/JyEFY4egvv5VjhLaM79exMsqoi/vfAFuHw+4mQMHQVr1G3qqfQ+won2MFeKRpNRoEM0aVbptRldrqz0mPAA3nh5aD/kscMQsWoQ37kY5rAxsO68L9xNlaVjQ5Lghf9gl3n9DAPWA9M9U5cETLou5NdnVJuoT8L0/R/CuGZYwFM0vRSxaU/AuKKbEjB58ivI40dJ6QkYLdvC+vlvINp1CvqHC+yrGh27h6vKPSc1xh8yrr+iAfE6o8/AoFXUrAWjU8/gOZsCC6b86jhpdAOCLi2ThCE25TGgRs1geK5zBIziBcaS9xW0D4KsCrNnf8Qeehxo0Ej1yAV/ky4Q0AUfJUWiyfhwV4WqOi6Y6/gxlP3yR94jbUaMNBxrIdG5F2Amv6q77O9wXnsuGBouGAOHwfhuW1XlrF5OmuiPKgIqOnSBNfEBJcDm6DvgkuYDCZ85YZKah7WS86enPa1Do8XlHWFNehDiwhqk5Sah7Nc/TYqk8mEVtSkA1KUX3FXvqvlEk0sgLmoMeYLaKDiUjjKtP90YNnkFHUx1Ga1fo+Y1+lwDd+2KdEPK1duzZ0CSJgGt27r1Hhjdeiueis+/FiuzOt0ccuc2lE4mrR2n2CO/Bws6ayb7DzP9aoAEOUz2nFnenHRxmjfeCnPwCIWp2W8QnDcWVBl/noPPhzn6djjznw5PmddyJJqMfawqkZUsCFXi4Q86fAA4c1o9STYrSHNlSyaZiEwsBM5fnvFMTdZmG9YqYZBnTkHu3K6EQVzWUmkr7u+u+k8gYGr8lg1w6eAx8Q2cqrHUYeW29l0AOkCqX1yryR10kPNMLAhMPK+zOi7U7UnD1imp/EyMTchk5ouBKeMchCFOnkj8+aYY7024Pt1qyAVwN65NtNaohZzw/3KP4mX2uhoifqkmmOevlMdTnViUPHIw8VCZEvk7ORFpDPOm28npoeBD2ysg6jWA8qFenV+OrdGha7nD5S57C3LPFxTgaKj6q7RCSg7PeWkunBfmBPyM3gODsty8Pij7BZcEzfeBRFMyoUNaw6WbnQ8J+6NsTsr1H5L51kMNdT9ZF5R9XuHftOsnH7BCoqASax0md80KyI3rlKksuP7KAeQL/63CYWkra9WB2XdQ0Cz37laBnrzO4XOnfQULFGl5k9JBPrmbPkpySyqN/56dEHQBG517whx3N+yZD/ms8/objZDt2Ab2S0St2pVaLB+sXEipfsq7hYk3Ihx08NuUv5Zi1soNayApAMG+FJPyPfwB/i87/GGKCyRXVdQ/qS7UV7Ggm9wlwTKvuk5ttLPtU4gWbSBLz1JAYWN4lnLltOtPI2QGRXtZoDgYo8xD1go8N/k3Jvlp2QqZdS8dRNY8fDGQ78okSSNwIMjo1icvc6S+bOzHv0itgrP8n5CfkJBRoMKnJKzjlUl1KfgLCNivP48YuQHGpS1g9Bvss8rrbyRCRkY/nHeWwCL7OVuSFHRwSJPkQuzHsM/AxBqCE+Fm/8EUkOiKsqk/SGLNX5s47y1NqpO7d3qmYbxW1KWvU1KJ0wwc5fKDJOyQx4lzfqmxKNZSPinn3X+I/7off+AJGWkwuXWTOris/VBK0dEMlHb9acYYfT1Tkc0yX/uKmGfWKz/wslZkAn+WZnSoujq9P5t9ZDK7FL2VW9ZDRW/pYsjbHKHpuOiy6Ux4GG06qBbPT37W65Uj/jj4Jdy3F4EDIOaN4+C+m3wmvEly+zcaIaM1cSje7dQdRvPWWa3QWfiiCgln1TldJ44YfrFdtfKv4M+5rr0Bgj7lEi0vp2DCsWAkm7Ry08fBc7ggj1J0kkxN0aa9MlNw+mTQbI65kw7TIDIrd8JZMA9yXyI0L9ifigcw/AFhP6wijSopBM6RS0Hml+/PuOT7fRNlWn+5sQ0bBcl+DrRYoyaU68IRQScLIbOfnO4FIVI55HGOVNbOK/PVnNb9jyhB40CRU7c+cPxIzvjzXM5bf6WLZ4A6J0afAanT5/zs6fuc2VTAgG56e/ZMuN/wuRSbLzZFiPwAQQWcqlZFiWOO7iUoVcckWlJLzr/fVFVsfqokOQkcKChjdO+rtACH3dlcYwGTu3ZAaR4awSaZ0f86UqOeuSlIOxkDhipebFJx4KQcUY7KF3b/pnY3rinXLZcKk/xGNoE5FWGTP2k/Nzv4C9beo596x6rOcy7m4Pwkk6h2AVkpt6hyzvgzF9LCzut/VvwEf3CQZ4pMk6l1kmliP/ErsnWvhUl5pXDujM1DdlSdJa9lZ6Zk8+J1SxB7nIISdKDCZppLWk1u3wrQbesTJ5nDuS6ul+QH2U89CvedN+H26O/Z6RSQqDbjGUj6qNk3r7iv89KzKnzPZXvBXMQmP0rh6NqwbpsEOeYOleD1fVJOjNucBkgT4XTXf5AISuz6HDh2BKDkaibKtP7UcXxLM3EgR32QHerAkVKDLiM/Z1aZcH6IjdIEUc8hP9usLjRer9K8ZOaBLq9c8ed1c7LfpY8h+HvafFO0QqZW78JdvlT9KWeZv8K3SyHpawH1FUYe30h9aUF+ERPnrEBhfJdMQmfxK4RicsBCBTeEmTS7pASrIhIGe9ZUstHHk2YarHIyvoBxOoC/EpAfrU6MpTrOgXHeSHSkhDRpQCaVj9q62ROwA/sS/VNKbB5yX16/DIeoU/qFHzOuP9RRkB/DeSsmd+3KUItX5OCBMldpzSrXFYp+luucpuJczOFP7Sxa4F0KhJU1cgI4h8ZffuSCf8D75XkQU3+r9sGvy8evyPV/nVTr/cTnQFOaxTCtov/UJR8rPZ882PQsqQdJjj7o64OMRBE39gXZvJT7KA/jB0gyDtKNeUOgAPGPXpPlDb3zyIiDJNnm/jhpvW/3eVzst3zqAsQ/usDHt3yv9etrBHwEtJD5SOhfjUBECORsLp7sVzOipWm2GoHiQEBrsuLYR/0WBYyAFrIC3hy9tOJAQAtZceyjfosCRkALWQFvjl5acSCghaw49lG/RQEjoIWsgDdHL604ENBCVhz7qN+igBHQQlbAm6OXVhwIaCErjn3Ub1HACGghK+DN0UsrDgS0kBXHPuq3KGAEtJAV8ObopRUHAlrIimMf9VsUMAJayAp4c/TSigMBLWTFsY/6LQoYgf8BIVTf3IgGuLEAAAAASUVORK5CYII=" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Gem: Jekyll</title>
      <link href="https://chrispenner.ca/posts/gem-jekyll"/>
      <id>https://chrispenner.ca/posts/gem-jekyll</id>
      <updated>2014-11-03T00:00:00Z</updated>
      <summary>Check out Jekyll</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/jekyll-logo.png" alt="Gem: Jekyll">
              <p>Jekyll is a web-framework written in Ruby for creating
<em>static</em> pages. If you're unfamiliar with the term,
<em>static</em> means that it can take a set of input files and turn it
into a site that's linked up very nicely, but cannot provide any
interaction with the user, nor can it react to it's environment by using
a web-server. Interactivity is still available on the client-side
through the use of javascript of course.</p>
<p>Jekyll is very good at things like making informational sites, or
even simple blogs. It will parse markdown and load it into templates for
you, which makes it quick and easy to write content for your site. If
creating a blog is something that interests you, also check out <a
href="http://octopress.org/">Octopress</a>, which is a blog framework
built on top of Jekyll.</p>
<p>If you've always wanted your own blog, or even just want to get
started learning out to create a website, now is a good a time as any.
Jekyll and Octopress integrate perfectly with <a
href="https://pages.github.com/">Github Pages</a>, which allow you to
host static sites completely free!</p>
<p>TLDR:</p>
<ul>
<li>Jekyll is a quick and easy static site framework.</li>
<li>Host a blog for free on <a href="https://pages.github.com/">Github
Pages</a>.</li>
</ul>
<p>If you want to check out the source it's available on the Jekyll <a
href="https://github.com/jekyll/jekyll">Github page</a>.</p>
<p>Follow me on twitter <a
href="http://www.twitter.com/chrislpenner">@chrislpenner</a> to catch
new articles as they come!</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Worth a Read #1</title>
      <link href="https://chrispenner.ca/posts/worth-a-read-1"/>
      <id>https://chrispenner.ca/posts/worth-a-read-1</id>
      <updated>2014-10-31T00:00:00Z</updated>
      <summary>Check out these posts!</summary>
      <content type="html"><![CDATA[
              <p>This marks the beginning of a new feature, <strong>Worth a
Read</strong>, which will contain a quick and easy list of blog posts
and articles that I've found interesting recently. They may have to do
with programming, design, lifestyle, cool products, or anything else
I've been reading. Might be themed, might not! Hope you enjoy it!</p>
<p>This week's list contains a variety of topics from different
disciplines, hopefully you'll find something interesting! Follow me on
twitter <a href="http://www.twitter.com/chrislpenner">\@chrislpenner</a>
to keep up with future posts!</p>
<h3 id="worth-a-read">Worth a read:</h3>
<ul>
<li><a href="http://vimeo.com/100264064">A clever and informative talk
about CSS's quirks</a></li>
<li><a
href="http://lifehacker.com/wordmark-it-instantly-previews-all-your-installed-fonts-1624496407">Wordmark.it
helps preview all your fonts</a></li>
<li><a
href="http://nothingbutsnark.svbtle.com/how-to-argue-for-pythons-use">Python
(vs?) Go</a></li>
<li><a
href="http://www.agencypost.com/10-principles-design-transformed-gorgeous-colored-paper-posters/">Principles
of design as a poster series</a></li>
<li><a
href="http://lifehacker.com/the-30-percent-rule-and-the-art-of-early-feedback-1619474527">The
30% rule of early feedback</a></li>
</ul>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Gem: Neovim</title>
      <link href="https://chrispenner.ca/posts/gem-neovim"/>
      <id>https://chrispenner.ca/posts/gem-neovim</id>
      <updated>2014-10-15T00:00:00Z</updated>
      <summary>Check out Neovim</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/neovim-logo.png" alt="Gem: Neovim">
              <p>This is the first of a series which will highlight open-source "Gems
in the rough" that is, projects which are worth taking a look at,
downloading, or contributing to. Let's get started!</p>
<p>Neovim is a rebirth of the retro text editor <a
href="http://en.wikipedia.org/wiki/Vim_(text_editor)">Vim</a> (circa
1991). It's interesting that the team decided to rebuild it because Vim
itself is still very much alive, there are new plugins and patches
released often and development on it continues. The folks at Neovim have
realized however that it's getting old and the Vim Script language that
original vim plugins are written in is a syntax nightmare. It's tougher
to extend and interact with than it could be, so they decided to renew
the project by rebuilding the entire code-base into something easier to
maintain.</p>
<p>Some of Neovim's driving principals are as follows:</p>
<ul>
<li>Allow vim to be extended in any language.</li>
<li>Allow plugins to run asynchronously and send events.</li>
<li>Implement an embedded text interface, ready for integration into any
application.</li>
</ul>
<p>I'll be writing more about vim and what it's capable of soon, so keep
an eye out for more, and run vimtutor on your terminal to try it out!
You can help out right now by checking out the source on <a
href="http://github.com/neovim/neovim">Github</a> or by donating on <a
href="https://www.bountysource.com/teams/neovim/">BountySource</a>.</p>
<p>Follow me on twitter <a
href="http://www.twitter.com/chrislpenner">@chrislpenner</a> to catch
new articles as they come!</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>You Own Your Data</title>
      <link href="https://chrispenner.ca/posts/you-own-your-data"/>
      <id>https://chrispenner.ca/posts/you-own-your-data</id>
      <updated>2014-09-26T00:00:00Z</updated>
      <summary>Don&#39;t give up control over your data</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/security-vs-privacy.jpg" alt="You Own Your Data">
              <p>First off, thanks for taking the time to read this, please send me a
message on twitter <a
href="http://www.twitter.com/chrislpenner">@chrislpenner</a> if you have
ideas or comments, and share this post around if you agree with it.</p>
<p><em>Comic used with permission of <a
href="http://www.claybennett.com/">Clay Bennett</a>.</em></p>
<p>Okay, so what's this whole thing about? To put it in a nutshell for
you: our data is important, our data isn't safe, therefore something
needs to change. What is Facebook doing with your data? Are they giving
it to the NSA? What if my employer finds out about such and such? We
spend far too much time worrying about whether our data is safe and what
would happen if these businesses that we trust with our virtual lives
decide to go bad.</p>
<p>Most people you ask would say that Facebook (who I'll be picking on
because they're most popular at the time) is free to use, but the
reality is far from that, the cost is your data. Facebook doesn't work
unless everyone shares data. You can't actively use your FB account
unless you take the plunge and decide to give them your pictures,
thoughts, buying habits, movie and music likes and dislikes... the list
goes on. Everyone knows that they're giving this information away, but
when asked, most would say they don't really have much of a choice. They
either share their data, or Facebook becomes useless. Heck, I myself
have been keenly aware of this for years, but I still participate
because having access to my friend's thoughts, contact info and photos
is far too convenient to justify giving up. We've grown to a place where
every one of us needs social media in some form or another, that's not
even a question at this point, the question then becomes: Who do we
trust to handle all this data?</p>
<p><em>Think about that for a minute, maybe even two...</em></p>
<p>No, seriously, stop looking at this screen and actually think: Who do
you really trust to handle all of your personal data? Trust is
important.</p>
<p>Now I don't know about you, but my answer was simple, I can only
trust myself. I propose we address this issue by decentralizing data
storage. There's a very important clarification to make: the data is
separate from the service. Facebook isn't a collection of data, it's a
service that curates and presents a collection of data to you. What this
means is that programs like Facebook's "news feed" could exist and be
maintained separately from the data itself.</p>
<blockquote>
<p>Who do we trust to handle all this data?</p>
</blockquote>
<p>I propose that as an open-source community we devise a generic social
media program which users can download and run on their computers which
pulls in data and presents data about users from personal data
repositories. Users can choose to host their data wherever they feel
comfortable, maybe on their own secure web server, maybe on Dropbox,
maybe they trust a third party site with it, maybe they can even host it
on their own computer, the point is that this choice is up to the user
and the user alone. This data would then be pulled down to the program
when requested if and only if the user who is signed into the program
has that person's permission to do so, either through a link or some
sort of case by case verification system; think of friending on Facebook
or sharing a document on Google Drive. These permissions can be revoked
by the owner of the data at any time, or the data can simply be deleted
from their own storage container.</p>
<blockquote>
<p>The data is separate from the service</p>
</blockquote>
<p>Though this system has its own challenges, I believe it solves some
major problems. In the new model:</p>
<ul>
<li>Data is decentralized. (No one company controls it all)</li>
<li>Control belongs to the data's owner. (They can change, delete, or
revoke the permissions of their own data)</li>
<li>No middleman. (The open-source software would pull data directly
from people's sources to the user's computer, no opportunity for it to
be snatched up)</li>
<li>Extensible. (Once everyone is hosting their own data and the process
is standardized in some fashion, new programs and social networks can
simply use existing data-stores and people don't need to rebuild their
virtual life every 5 years)</li>
</ul>
<p><em>It'll take work, it'll be a tough change, but if we don't demand
it, it'll never happen.</em></p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>The Future of Software</title>
      <link href="https://chrispenner.ca/posts/modular-software"/>
      <id>https://chrispenner.ca/posts/modular-software</id>
      <updated>2014-09-24T00:00:00Z</updated>
      <summary>The future of software exists in modularity and modularity</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/modular.png" alt="The Future of Software">
              <p>I 've always been annoyed with software, the particular reasons have
changed consistently over the years, but I think that for all of us
there's always been something that gets on our nerves; whether it's how
your word processor never indents your lists properly, or how your
computer's calendar starts on Sunday when you'd prefer to have it start
on Monday.</p>
<p>Lately what's been bothering me is the closed-ness of most desktop
software in general. Don't like the default colour-scheme? Too bad, you
can't change it. Don't like the way your notes are laid out? Too bad,
can't change that either. Want to use your favourite text editor instead
of that tiny box they're giving you? Nope!</p>
<p>This problem has actually already been solved for the most part. The
solution exists in <em>modularity</em>. For the uninitiated, modular
design means that the way a thing works is separated into distinct
sections. A home theater system would be a good example to think of: you
have a source for your sound and video (A DVD player perhaps) the video
signal proceeds to your Television, the sound goes to your amplifier,
then continues to your speakers. Each link in this chain has a specific
purpose and works independently from the other links. If you'd like to
switch out your speakers, you simply unplug the old ones and plug the
new ones in. Similarly with the video signal; the DVD player doesn't
care where the video ends up. If you'd like to switch your Television
out for a Projector, Video Recorder, or even a toaster it doesn't know
the difference and continues to happily send video. Whether you'd like
to view your movie on a toaster or an IMAX screen is entirely up to the
user (though the viewing experience is likely to change
dramatically).</p>
<blockquote>
<p>The solution exists in modularity.</p>
</blockquote>
<p>Unfortunately, in the world of software the parts aren't as clearly
defined. Where should one box end and another box start? Modern web
technologies provide insight into this. Websites are complicated these
days. On any given news website you'll have writers, designers,
programmers and editors all working together to deliver a good
experience. To keep these groups from stepping all over each other's
toes content, presentation, and behaviour must be separated from each
other. These aspects correspond to HTML, CSS, and Javascript
respectively. HTML contains the content and gives the content meaning,
CSS tells the browser how to present it, which colours to use and what
goes where, while Javascript handles any user interaction and responds
accordingly. I believe this is how we should be modelling our desktop
software.</p>
<p>Whether this means actually using HTML, CSS and Javascript for
desktop software I'm not sure (that's certainly a possible solution),
but whichever tools are used, the programs created must recognize what
they're actually trying to do and should focus solely on that. If a
program is an email client it should handle the sending and receiving of
email and should do it well, and do no more and no less. Allow the user
to patch in and use any text editor they'd like to create those emails.
All programs should allow mixing and matching of different program
components.</p>
<p>A strong benefit to this approach is that it would allow programs to
easily interact with one another and solve problems together. This is
something that is nearly impossible to do given the current
architecture. Imagine a "Dashboard" plugin that focused only on bringing
multiple programs from your computer together in one place. You'd have a
column of emails on the right, some favourite music playlists on the
left, your favourite text editor in the middle that can send directly to
Evernote, Microsoft Word, Email, or a text message. When the user
chooses an action to perform the Dashboard sends the appropriate
<em>event</em> to the corresponding program with any necessary text or
user information as parameters. A timer app could send an email, start a
song or switch into "work-mode" when certain timer events fire. Users
could easily design new facades for their favourite clients so long as
it sends any necessary events and data to the program behind the
scenes.</p>
<p>Responding to any and every event in any way you like provides
extensive hackability to everything. Note-taking apps and Email clients
wouldn't need to go through all the work to (poorly) implement
autocompletion or spell-checks because that would be the job of the text
editor (which it would do well).</p>
<p>I'm sure that you can see that the possibilities are nearly endless
if we can just unlock this method of interaction and modularization.
Everyone can work on doing just one thing well and can borrow all the
other functionality from other programs.I can only hope we'll end up
there eventually.</p>
<p>Until next time.</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Set the Data Free</title>
      <link href="https://chrispenner.ca/posts/set-the-data-free"/>
      <id>https://chrispenner.ca/posts/set-the-data-free</id>
      <updated>2014-08-02T00:00:00Z</updated>
      <summary>Simple formats afford adaptability</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/set-the-data-free.png" alt="Set the Data Free">
              <p>So lately I've been noticing something. The way we consume our data
is changing, suddenly just having data isn't good enough, it's all about
presentation. Most modern data formats such as Microsoft Word documents,
Powerpoint Slides and PDFs are increasingly focused on making your data
LOOK good.</p>
<p>This is a good thing, it's good that consumer computing has developed
to a point where we have enough tools to easily format and present our
data the way we want, and it's great that as a result we can send
messages not only through the text itself, but also through the way we
display it, but we're losing something valuable with this transition as
well: The ability to manipulate plain-old vanilla text. Most data is now
being trapped inside proprietary layers of code. While tools like grep
can still sometimes decipher these encodings and still find what you're
looking for, piping text from a Powerpoint file, formatting the string
with Unix utilities, then compiling it with several other Powerpoint
files and their text would not be a pleasent experience.</p>
<p>I understand that all of this formatting is complicated, that it
would not be easy to encode a modern day Word document without using
special characters and bytes and bytes of stored settings; however, I
think it's worth looking for a compromise.</p>
<p>Two options come readily to mind. Perhaps text from Word Documents,
Powerpoints, PDF files, and other proprietary formats could be included
in full as a precursor to the needed code which would then use
combinations of line-numbers or character addresses to apply formatting
to code in chunks. Perhaps transformations could be performed through
the use of recognized tags (similar to HTML) which could be parsed or
ignored depending on context. These both have the downside of
unnecessarily bloating the files and increasing the data stored on disc,
and would get complicated very quickly with more complex presentations,
however they would allow common command-line programs to be taught to
understand them properly and allow full command-line piping and
functionality.</p>
<p>Unfortunately, it would be very difficult (see: impossible) to get
vendors to agree on a set convention for this and would most-likely lead
to big tangled mess of competing standards, but as I learn more and more
about Unix utilities and the wealth of functionality that they provide,
it seems a crying shame to invalidate them all just because we'd like a
bold word or want to position our margins correctly. Ideally there would
be a strong way to separate content from formatting a la HTML and
CSS.</p>
<p>It is also unfortunate that so few people know and use the command
line these days, there are so many shortcuts and so much functionality
in their computers that they're missing. Let's hope more will be
inspired to explore!</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Legacy in Design</title>
      <link href="https://chrispenner.ca/posts/legacy-in-design"/>
      <id>https://chrispenner.ca/posts/legacy-in-design</id>
      <updated>2014-07-26T00:00:00Z</updated>
      <summary>Things that come before greatly affect the success of our design</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/legacy-in-design.png" alt="Legacy in Design">
              <p>Designers often feel pressure to come up with something new and
revolutionary. They want to make their mark on the design world by
revolutionizing some new concept or idea. Certainly this form of
thinking is a good thing; it fuels innovation and leads to exciting new
possibilities that others wouldn't have ever contrived. However, humans
build habits, and if we're designing for humans we simply must take this
into account.</p>
<h2 id="habits">Habits.</h2>
<p>Have you ever switched operating systems and found yourself trying to
close a window but the 'X' is on the wrong side? Have you ever driven a
friend's car and suddenly jerked forward because their gas pedal was
more sensitive than you were used to? Humans are habit forming
creatures, we build muscle memory and our brains will begin to automate
tasks that we perform often enough. This is a great thing! Can you
imagine the effort that typing would require if you had to consciously
remember where each key was and deliberately press them in sequence?</p>
<p>Whether we like it or not, our design 'ancestors' have pioneered the
field and have developed many habits in users. Some good, some great,
some absolutely terrible. This means that whenever you make a design
decision we must all be conscious of how the user expects it to work
from past experience, and then only change it if we're certain that the
improvement strongly outweighs the discomfort the user will endure
learning the new system.</p>
<p>You must ask yourself, will the user do this enough to develop a new
habit? If you're designing a simple company website, or a simple utility
program the answer is no. It is better to follow convention and lay out
the site as people would expect, even if your design and layout is
'improved' in some way.</p>
<h2 id="innovation">Innovation.</h2>
<p>How then can we innovate? There's a few options here. Unfortunately
in most cases, as a single designer it is simply impossible to have a
large enough effect to change the design landscape. Existing habits are
strongly formed by years of legacy and shift only slightly over many
many years.</p>
<p>One way the design landscape changes is through the introduction of
new mediums. Mobile devices and tablets, though they are computers, are
different enough from laptops and desktops so as to require a
fundamental shift in design paradigms. It is in these moments that
designers thrive. When technology is new, habits have yet to form and
designers can form the landscape as they see fit. These are times when
designers must be conscious of every little decision they make, for it
again sets precedent for all future designers in the medium.</p>
<p>Good luck!</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>Caps-lock</title>
      <link href="https://chrispenner.ca/posts/capslock"/>
      <id>https://chrispenner.ca/posts/capslock</id>
      <updated>2014-05-25T00:00:00Z</updated>
      <summary>Caps lock is poorly designed. Read to find out why</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/capslock.png" alt="Caps-lock">
              <p>Any time I consider decisions of designers past, my mind always
drifts towards the keyboard. It is a ubiquitous piece of hardware that
most take for granted. If you take more than a second to think about it,
it's a very strange design. The letters seem to be placed without rhyme
or reason, most layouts have rows staggered by a seemingly arbitrary
amount from one another, some keys are mirrored on either side (shift,
control, etc) others are not (tab, return). It seems as though no-one in
their right mind would ever design such a piece of work! The keyboard is
the result of years of 'legacy' design, one or two things get carried
over from iteration to iteration and over time the sense of it all is
lost.</p>
<p>Even stranger is that the nonsensical layout doesn't tend to slow us
down in the slightest. Once learned it is sufficiently fast. Studies
have shown that even laboriously designed key layouts (Dvorak) provide
only very modest improvements to typing speeds.</p>
<p>The worst offender of design legacy that I have yet to come across is
the Caps-lock key. Here's just a few of the many reasons why:</p>
<p>Caps-lock is the only modal key on the keyboard, (i.e. press to
engage, again to disengage), this is extremely unintuitive and is a
source of constant frustration. Consult the brilliant <a
href="http://www.azarask.in/blog/post/is_visual_feedback_enough_why_modes_kill/">Aza
Raskin</a> for more on how modes break things. People begin to type
without knowing that Caps-lock is engaged and after writing one or two
lines they notice that they've been yelling the whole time. They must
then delete the whole thing because for some reason there's STILL no
easy way to switch cases on already typed text in most editors.</p>
<p>This would be bad enough as-is, however someone had the gall to place
this evil key in prime real-estate where it is easily accessible, and is
often pressed by accident.I don't know how it ended up where it is, but
I do know that it shouldn't be there. Why not use this position for
shift or Ctrl/Cmd ? I can't think of any good reasons, can you?</p>
<p>Caps-lock offends again in the behaviour department. Standard
Caps-lock behaviour is nonsensical. At first glance it appears as though
engaging Caps-lock simply locks the shift key ON, though when one
attempts to type a symbol or number key, one finds that this isn't the
case. This destroys the initial mental model that is formed and forces
each person to learn a completely new typing paradigm for these few
small use-cases.</p>
<p>I don't we ended up here, but I think it's about time to start a
trend towards making the Caps-lock key useful again or deprecating it
from future designs. You can start right now by rebinding it to
something useful to you and encouraging your friends to do the same.
Being a faithful Vim user I've bound it to act as Escape on every system
I own. If you're not a Vim user, I'd recommend trying Ctrl/Cmd.
Rebinding on OSX is as simple as looking through the system settings and
changing the modifier keys, for more complex mappings I recommend <a
href="http://pqrs.org/macosx/keyremap4macbook/pckeyboardhack.html.en">PCKeyboardHack</a>.
For Windows I'd check out <a
href="http://www.autohotkey.com/">AutoHotKey</a>. For Linux try googling
an appropriate xmodmap command.</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
  <entry>
      <title>The Switch To Mac</title>
      <link href="https://chrispenner.ca/posts/switch-to-mac"/>
      <id>https://chrispenner.ca/posts/switch-to-mac</id>
      <updated>2014-05-19T00:00:00Z</updated>
      <summary>I switched to using a Mac, and I love it</summary>
      <content type="html"><![CDATA[
          <img src="https://chrispenner.ca/images/the-switch-to-mac.png" alt="The Switch To Mac">
              <p>The time had come to replace my slowly fading laptop, it had served
me well in the last four years, but all good things must come to an end.
I was faced with a choice: which operating system do I commit to for my
next four years? As a Computer Science student I wanted to make the
right choice. These days most things I could ever want to do are
possible on any one of the big three (Windows, OSX or Linux), so it was
mostly a choice of form factor and style. How would each choice affect
my experience throughout the years to come? Would I have to give up some
long-loved programs that I had invested my time and money into? How
could it affect my workflow? Here's a bit about my past experience with
each OS.</p>
<h2 id="windows">Windows</h2>
<p>I've always been a Windows guy. My family grew up with them. I can
still remember playing computer games with my father on our old Windows
2.1 desktop. My Father works in IT, so we managed to keep up with trends
and usually had the latest version Windows on mostly-decent hardware.
I'd gotten used to it and didn't have any reason to mess with a good
thing so when I got my first personal laptop as a graduation gift
naturally I went with Windows 7. It mostly did as it was told, it rarely
complained, it handled device drivers like a champ. Aside from the
occasional annoying "Your computer will reboot for updates in 5 minutes"
I didn't have any major complaints. It was only once I started to get a
little deeper into programming (mostly in C++) that I started to find a
few shortfalls. Installing any sort of IDE was a nightmare due to way
the file system was (mis)organized. Things you attempt to install would
misplace libraries or install them twice. There's really no system for
where programs were meant to put things and often programs would clutter
up my own files with their junk. Since when do Adobe plugin files count
as "Documents"?</p>
<p>Installation problems could usually be fixed by editing some
complicated system settings that weren't meant to be messed with.
Editing the system path consisted of fumbling through a long jumbled
line of file paths all sandwiched together in a fixed size text-box,
making it impossible to see what's already there, nor what you're
changing. The native command-line interface is lacking in most areas and
isn't meant for doing any serious work in. These design warts, legacies
of the Microsoft's past OS's have been patched and repaired, but
continue to cause problems in their modern OS's. Around this time I
started fiddling around with Linux, more specifically Ubuntu, to see
what it could do.</p>
<h2 id="linux">Linux</h2>
<p>After getting fed up with some of Windows' more annoying design and
organization problems I sought to try out the veteran-praised Linux. I
started out with Ubuntu because I'd been told it was easy both to
install and understand, which was perfect for someone new to the
command-line like me. I installed it onto a partition on my Laptop,
choosing to dual-boot with Windows because I wasn't sure I'd be ready to
make the switch cold turkey. Once Ubuntu had very kindly walked me
through the installation I excitedly began to study the BASH command
line and some of the things it could do. I was amazed when I learned I
could type a simple 'sudo apt-get' to have my system download, install,
and update most common programs. Though it uses the command-line, this
seems like a vastly superior method of installation. No need to hope you
downloaded the right version for your system, installing it manually,
then deleting the installation files afterwards.</p>
<p>The Unix core's structure is very well defined, you know where to
look for your programs, hard-drives, configuration files, etc. Your home
folder is kept separate for your own personal use where you won't
accidentally mess with anything important. Everything is properly
modularized for easy organization and security. The 'root' permissions
system seems much more secure than the Windows 'always administrator'
approach that most people default to. Unfortunately, my laptop wasn't
supported 100% in everything, so I had to do a little fiddling to get
things like my function keys and headphone jack to work properly, but
once configured it worked fine. Flash was an issue, my browsers couldn't
load YouTube videos or listen to flash-based music players, but after
installing a more recent version of Ubuntu most of those problems went
away. Overall it worked great and I really enjoyed the system, but Linux
still has fewer options available for software than the other OS's.</p>
<h2 id="mac">Mac</h2>
<p>I had never had an apple computer before, in fact prior to purchasing
my macbook I had never purchased a single product from apple. I knew
their reputation well however, "It just works!" my friends would
exclaim. I liked the idea of it, but of course I used Windows with
pride, sure it was a little tougher to do some things, but hey, I'm a
Computer Science student so of course I can figure it out. Of course, I
never stopped to ask myself weather I should actually have to put that
work in. The philosophy and design of apple products eluded me, I just
wasn't convinced. Then I started comparing bullet points.</p>
<h2 id="proscons">Pros/Cons</h2>
<h3 id="windows-1">Windows</h3>
<p><strong>Pros</strong></p>
<ul>
<li>Familiarity</li>
<li>Well-supported</li>
<li>Inexpensive</li>
</ul>
<p><strong>Cons</strong></p>
<ul>
<li>Disorganized OS structure</li>
<li>Difficulty with programming tools</li>
<li>Bad command-line (bring on the hate-mail)</li>
</ul>
<h3 id="linux-ubuntu">Linux (Ubuntu)</h3>
<p><strong>Pros</strong></p>
<ul>
<li>Open Source</li>
<li>Constantly updated</li>
<li>Free</li>
<li>Unix command-line</li>
<li>Unix system structure</li>
</ul>
<p><strong>Cons</strong></p>
<ul>
<li>Poorly supported on some hardware</li>
<li>Less choice of software</li>
</ul>
<h3 id="osx">OSX</h3>
<p><strong>Pros</strong></p>
<ul>
<li>Lots of software available</li>
<li>Powerful and reliable hardware.</li>
<li>Unix system structure</li>
</ul>
<p><strong>Cons</strong></p>
<ul>
<li>"Hold your hand" approach</li>
<li>Expensive</li>
<li>Stuck in apple's dictatorship</li>
</ul>
<p>After considering the pros and cons of each, I pulled out my yellow
legal pad and began to rank things based on their importance to me.
After a few minutes I realized that I was really quite fed up with the
Windows file structure and sloppy organization/installation. The
registry is really just a bad idea, made worse by every new iteration.
That left me with two options, Linux or OSX. I really liked Ubuntu and
how much control it gave me over everything, it was well organized,
supports the free-software movement and was also free of charge. OSX is
also very well organized, it limits control over some aspects, but in
turn delivers a well designed experience that is intuitive and
efficient. In the end, the combination of a large software ecosystem,
well-built hardware, and good customer support won out in the end and I
dove in head-first, purchasing a re-furbished 13" macbook pro retina
with a 2.6 GHz processor.</p>
<p>Now that the dust has settled I'm very happy with my decision. There
were a few bumps in the road of adapting to the new OS, but most things
were just a matter of learning a slightly new way of doing things. I can
confidently say that I'm very impressed with how OSX handles application
installation (in most cases you simply drag application files onto your
hard-drive and they work as-is). I haven't experienced a single crash or
hang-up yet, and if one were to occur I know that time-machine would
allow me to recover gracefully. I've been able to reconstruct most of my
old Windows workflows, as well as develop some new ones. Overall I would
say that choosing an OS is very much situational, something that's good
for one person may be bad for another and in most cases doing research
and trying out each OS you're considering is probably the best way to
make a decision.</p>
        <p>Hopefully you learned something 🤞! Did you know I'm currently writing a book? It's all about Lenses and Optics! It takes you all the way from beginner to optics-wizard and it's currently in early access! Consider supporting it, and more posts like this one by pledging on my <a
            href="https://www.patreon.com/bePatron?u=7263362">Patreon page</a>! It takes quite a bit of work to put
        these things together, if I managed to teach your something or even just entertain you for a minute or two
        maybe send a few bucks my way for a coffee? Cheers! 🍻</p>
    <div class="centered"> <a href="https://www.patreon.com/bePatron?u=7263362"><img width="170" height="40" src="data:image/png;base64,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" alt="Become a Patron!"></a></div>
              ]]></content>
      </entry>
</feed>
