<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:planet="http://planet.intertwingly.net/" xmlns:indexing="urn:atom-extension:indexing" indexing:index="no"><access:restriction xmlns:access="http://www.bloglines.com/about/specs/fac-1.0" relationship="deny"/>
  <title>Planet Haskell</title>
  <updated>2026-06-13T06:06:00Z</updated>
  <generator uri="http://intertwingly.net/code/venus/">Venus</generator>
  <author>
    <name>Haskell Admin Team</name>
    <email>planet@haskell.org</email>
  </author>
  <id>http://planet.haskell.org/atom.xml</id>
  <link href="http://planet.haskell.org/atom.xml" rel="self" type="application/atom+xml"/>
  <link href="http://planet.haskell.org/" rel="alternate"/>

  <entry>
    <id>tag:,2026:/math/egyptian-105</id>
    <link href="https://blog.plover.com/math/egyptian-105.html" rel="alternate" type="text/html"/>
    <title>Egyptian fractions for 2/105</title>
    <content type="xhtml" xml:lang="en"><div xmlns="http://www.w3.org/1999/xhtml"><p><img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%24%5cdef%5cu%231%7b%5cfrac1%7b%231%7d%7d%24"/></p>

<p>The ancient Egyptians had a terrible notation for fractions.  They had
notations for <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%24%5cu%20n%24"/> for each <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%24n%24"/>, for <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%24%5cfrac23%24"/>, but everything
else was written as a sum of these, with repeats forbidden, so that
for example <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%24%5cfrac25%24"/> had to be written as <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%24%5cu3%20%2b%0a%5cu%7b15%7d%24"/>. (<a href="https://en.wikipedia.org/wiki/Egyptian_fraction">Wikipedia</a>)</p>

<p><a href="https://blog.plover.com/math/egyptian-fractions.html">In an older article about Egyptian fractions and the Rhind
Mathematical Papyrus</a>, I said:</p>

<blockquote>
  <p>Getting the table of good-quality representations of <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%24%5cfrac2n%24"/> is
  not trivial, and requires searching, number theory, and some trial
  and error. It's not at all clear that <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%24%5cfrac2%7b105%7d%3d%5cu%7b90%7d%20%2b%20%5cu%7b126%7d%24"/>.</p>
</blockquote>

<p>I think I see now where this comes from.  <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%24105%20%3d%203%c2%b77%c2%b75%24"/>, so two of
the summands must have denominators divisible by <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%245%24"/> and by <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%247%24"/>
respectively.  The first thing you should do is consider $$\u5 + \u7
= \frac{12}{35} = \frac{36}{105}.$$</p>

<p>But you don't want <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%24%5cfrac%7b36%7d%7b105%7d%24"/>, you want <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%24%5cfrac%7b2%7d%7b105%7d%24"/>, so
you multiply by <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%24%5cu%7b18%7d%24"/>: </p>

<p>$$\u{18}\left(\u5 + \u7\right) = \u{90}+\u{126}
= \frac 2{105}$$</p>

<p>and there it is.</p>

<p>Why pick <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%24%5cu5%24"/> and <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%24%5cu7%24"/> rather than, say, <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%24%5cu3%24"/> and
<img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%24%5cu5%24"/>? I suspect the answer is probably: Ahmes (or someone
earlier) tried it both ways and picked the result they liked best.
Remember Ahmes is compiling a reference table here, so he does these
calculations once, writes down the best result, and throws the others
away.</p>

<p>If you do the same trick with <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%243%24"/> and <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%245%24"/> instead you get
<img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%24%5cu3%2b%5cu5%20%3d%20%5cfrac8%7b15%7d%20%3d%20%5cfrac%7b56%7d%7b105%7d%24"/>.  Then you multiply
everything by <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%24%5cu%7b28%7d%24"/> producing $$\u{84} + \u{140} =
\frac2{105}$$ which seems a little worse than the other one.  Using
the <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%243%24"/> and the <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%245%24"/> produces $$\u{75} + \u{175} =
\frac2{105}$$ which seems much worse.</p>

<p>Of course this only works when the denominator is composite.</p>

<p>Here's another approach, which doesn't work too well in this case but
might be useful for other examples.  Consider that <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%24%5cfrac23%20%3d%0a%5cu2%20%2b%20%5cu6%24"/>.  We want <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%24%5cfrac2%7b105%7d%20%3d%0a%5cu%7b35%7d%5ccdot%5cfrac23%24"/>.  So</p>

<p>$$
\begin{align}
\frac2{105} &amp; = \u{35}\cdot\frac23 \\
            &amp; = \u{35}\left(\u2+\u6\right) \\
            &amp; = \u{70} + \u{210}
\end{align}
$$</p>

<p>The denominators here are a lot bigger than the first expansion, but
they do at least have the advantage of being multiples of <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%2410%24"/>.
The Egyptians like this because they, like us, often need to multiply
numbers by <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%2410%24"/>, and whereas a fraction like <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%24%5cu%7b126%7d%24"/> is hard for
them to multiply by <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%2410%24"/>, it's trivial to multiply <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%24%5cu%7b210%7d%24"/> by <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%2410%24"/>.</p></div>
    </content>
    <updated>2026-06-12T17:53:00Z</updated>
    <published>2026-06-12T17:53:00Z</published>
    <category term="/math"/>
    <author>
      <name>Mark Dominus</name>
      <email>mjd@plover.com</email>
      <uri>http://www.plover.com/</uri>
    </author>
    <source>
      <id>tag:,2005:/</id>
      <icon>http://perl.plover.com/favicon.ico</icon>
      <link href="https://blog.plover.com/index.atom" rel="self" type="application/atom+xml"/>
      <link href="https://blog.plover.com" rel="alternate" type="text/html"/>
      <subtitle>The Universe of Discourse (Mark Dominus Blog)</subtitle>
      <title>The Universe of Discourse</title>
    </source>
  </entry>

  <entry>
    <id>https://tweag.io/blog/2026-06-11-diff-package-static-checks/</id>
    <link href="https://tweag.io/blog/2026-06-11-diff-package-static-checks/" rel="alternate" type="text/html"/>
    <title>Writing static checks to an unsuspecting library with Liquid Haskell</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>This post presents a little epic to insert static checks in Haskell’s <a href="https://hackage.haskell.org/package/Diff"><code class="language-text">Diff</code> package</a> using <a href="https://ucsd-progsys.github.io/liquidhaskell/">Liquid Haskell</a> (LH).<sup id="fnref-1"><a class="footnote-ref" href="https://www.tweag.io/rss.xml#fn-1">1</a></sup>
Static or compile-time checks are helpful to confirm formerly implicit assumptions in the implementation,
providing an additional layer of assurance.</p>
<p><em>Making illegal states unrepresentable</em> at an affordable cognitive cost is a staple of statically typed functional programming.
Endeavors like <a href="https://ghc.serokell.io/dh">Dependent Haskell</a> and Liquid Haskell delve into this aspect.
A distinctive feature of LH is that it works on top of regular Haskell code,
meaning that the program can still be compiled after disabling it,
thus making it possible to enforce properties without changing the source code.
In what follows I’ll give you a glimpse of how the Liquid Haskell approach feels in practice and how far it can go.</p>
<p>Liquid Haskell was created by the <a href="https://ucsd-progsys.github.io/liquidhaskell/papers/#people">UCSD Programming Systems group</a>
and these days is mainly maintained and further improved by my colleague Facundo Domínguez.
<a href="https://dl.acm.org/doi/10.1145/2633357.2633366">Applying Liquid Haskell to strengthen libraries</a> has precedent in the Haskell ecosystem,
and it was in this spirit that Facundo suggested this project as we were pondering an attempt to statically check our in-house <a href="https://github.com/tweag/ormolu">Ormolu</a>,
of which <code class="language-text">Diff</code> is a transitive dependency and a more suitable commitment given the engineering time I could bestow upon it.<sup id="fnref-2"><a class="footnote-ref" href="https://www.tweag.io/rss.xml#fn-2">2</a></sup></p>
<h2 id="diff-will-never-be-the-same"><a class="anchor before" href="https://www.tweag.io/rss.xml#diff-will-never-be-the-same"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a><code class="language-text">Diff</code> will never be the same</h2>
<p>The <code class="language-text">Diff</code> package is a small and (relatively) self-contained library implementing the <a href="https://publications.mpi-cbg.de/Myers_1986_6330.pdf">Myers diff algorithm</a>.
As a provider of basic functionality in the Haskell ecosystem,
adding formal guarantees to it is of intrinsic value to the community.</p>
<p>From the get-go, my objective was adding static checks to strengthen this library
in a contribution guided by two opposing desiderata:</p>
<ul>
<li>Minimize source changes</li>
<li>Maximize checked invariants</li>
</ul>
<p>While the first is about testing how (non-)intrusive Liquid Haskell can be,
the second is about its expressiveness.
To put it bluntly, the ideal LH would be able to statically check all the existing invariants
of an unsuspecting library using nothing more than <em>specification annotations</em>.
Reality is not that kind, forcing me to compromise on both objectives,
but I kept this mindset to help me see how close LH is to this ideal.</p>
<p>My first milestone was filling the mind gap between the <code class="language-text">Diff</code> implementation and the referenced paper’s algorithm,
through an in-depth study of the library,
resulting in documentation contributions highlighting the most salient invariants (pre- and post-conditions) and assumptions.<sup id="fnref-3"><a class="footnote-ref" href="https://www.tweag.io/rss.xml#fn-3">3</a></sup></p>
<p>In general, it is by a careful threading of logic that a program is built into existence;
the problem (and the source of well engineered solutions) is that the critical aspects of it lie within a <a href="https://pages.cs.wisc.edu/~remzi/Naur.pdf">theory in its writer’s mind</a>,
which tends to be lost across iterations, updates, refactors and people moving on.
Both documentation and specification cannot completely solve this problem,
but they can help.</p>
<p>For example, I added a post-condition to this function haddock</p>
<div class="gatsby-highlight"><pre class="language-haskell"><code class="language-haskell"><span class="token keyword">data</span> <span class="token constant">PolyDiff</span> <span class="token hvariable">a</span> <span class="token hvariable">b</span> <span class="token operator">=</span> <span class="token constant">First</span> <span class="token hvariable">a</span> <span class="token operator">|</span> <span class="token constant">Second</span> <span class="token hvariable">b</span> <span class="token operator">|</span> <span class="token constant">Both</span> <span class="token hvariable">a</span> <span class="token hvariable">b</span>

<span class="token comment">-- | Like 'getGroupedDiff' but accepts a custom equality predicate.</span>
<span class="token comment">--</span>
<span class="token comment">-- Postcondition: the output list is guaranteed to be /chunked/. i.e. no two adjacent</span>
<span class="token comment">-- elements share the same constructor.</span>
<span class="token hvariable">getGroupedDiffBy</span> <span class="token operator">::</span> <span class="token punctuation">(</span><span class="token hvariable">a</span> <span class="token operator">-&gt;</span> <span class="token hvariable">b</span> <span class="token operator">-&gt;</span> <span class="token constant">Bool</span><span class="token punctuation">)</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">b</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token constant">PolyDiff</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span> <span class="token punctuation">[</span><span class="token hvariable">b</span><span class="token punctuation">]</span><span class="token punctuation">]</span></code></pre></div>
<p>making the expected form of its output explicit.
This allows a reader to get an immediate notion of what the implementation is supposed to accomplish in order to satisfy the caller’s expectations.</p>
<p>Similarly, data types often carry more meaning than what they actually encode,
in which case documenting the implicit assumptions can help understand their intended use.</p>
<div class="gatsby-highlight"><pre class="language-haskell"><code class="language-haskell"><span class="token comment">-- | Line Range: start, end and contents.</span>
<span class="token comment">--</span>
<span class="token comment">-- The following invariants hold:</span>
<span class="token comment">--</span>
<span class="token comment">-- &gt; snd lrNumbers &gt;= fst lrNumbers</span>
<span class="token comment">-- &gt; snd lrNumbers - fst lrNumbers + 1 == length lrContents</span>
<span class="token comment">--</span>
<span class="token comment">-- which imply @lrContents@ cannot be empty.</span>
<span class="token keyword">data</span> <span class="token constant">LineRange</span> <span class="token operator">=</span> <span class="token constant">LineRange</span> <span class="token punctuation">{</span> <span class="token hvariable">lrNumbers</span> <span class="token operator">::</span> <span class="token punctuation">(</span><span class="token constant">LineNo</span><span class="token punctuation">,</span> <span class="token constant">LineNo</span><span class="token punctuation">)</span>
                           <span class="token punctuation">,</span> <span class="token hvariable">lrContents</span> <span class="token operator">::</span> <span class="token punctuation">[</span><span class="token constant">String</span><span class="token punctuation">]</span>
                           <span class="token punctuation">}</span></code></pre></div>
<p>These haddocks are inspired by the kind of properties that LH can express.
Nevertheless, their value doesn’t depend on providing static checks
as they already save us from some arduous code path diving.
Wouldn’t it be wonderful if the compiler could take those haddocks to heart?
In a sense that’s what LH is about!</p>
<p>Engineering the static checks took me into a tight feedback loop between the documentation process,
coming up with refactorings<sup id="fnref-4"><a class="footnote-ref" href="https://www.tweag.io/rss.xml#fn-4">4</a></sup> to make the code easier to check (which always implied easier to explain!)
and the writing of LH specifications matching the documented invariants.
This approach is in close sympathy with the <a href="https://www.tweag.io/blog/2026-04-16-doc-it-like-its-hot/"><em>doc it like it’s hot</em></a> philosophy.</p>
<h2 id="from-dry-code-to-liquid-types"><a class="anchor before" href="https://www.tweag.io/rss.xml#from-dry-code-to-liquid-types"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>From dry code to liquid types</h2>
<p>After <a href="https://ucsd-progsys.github.io/liquidhaskell/install/">installing LH</a>, compilation failed due to new shiny errors,
even though I hadn’t written a single LH specification yet.
This is because LH inspects the bodies of all function definitions out of the box to prove that</p>
<ol>
<li>Existing specifications are fulfilled</li>
<li>Recursive functions terminate</li>
</ol>
<p>The first condition is not limited to local specifications;
LH comes bundled with <a href="https://www.tweag.io/blog/2023-06-22-lh-assumption-imports/#new-solution-packages-with-assumptions">specifications for many boot package functions</a>.
For instance, many of Prelude’s partial functions are <em>refined</em> this way to be total,
so LH tries to prove that all their uses are safe.</p>
<p>One prominent example is <code class="language-text">head</code>, which was the only failure of the first condition in <code class="language-text">Diff</code>:
it was not certain that the list passed to <code class="language-text">head</code> in its <code class="language-text">ses</code> function is <em>always</em> non-empty,
which can be found to be true from the algorithm specification
and by following the composition of the involved processes.
LH tries to build this knowledge from specifications, in the form of <a href="https://en.wikipedia.org/wiki/Refinement_type">refinement types</a>, found along the call stack.
Such specifications are introduced using a special comment syntax <code class="language-text">{-@ ... @-}</code>
whose contents are processed to generate a set of constraints for an external <a href="https://en.wikipedia.org/wiki/Satisfiability_modulo_theories">SMT solver</a> to verify.
This allows us to mechanically check function specifications, formed out of pre- and post-conditions,
and data invariants expressed as <em>simple</em> logical predicates at compile time.
In what follows I’ll show some examples of LH specification annotations,
but in most cases I won’t be explaining their syntax or fundamentals,
trusting that their meaning within the general argument can be gathered from context.
For further details please look at the <a href="https://ucsd-progsys.github.io/liquidhaskell/specifications/">spec reference documentation</a>.</p>
<p>The same comment syntax is also used to set LH directives,
like the <code class="language-text">ignore</code> annotation I used to skip checks in the body of the offending <code class="language-text">ses</code> function.</p>
<div class="gatsby-highlight"><pre class="language-haskell"><code class="language-haskell"><span class="token comment">{-@ ignore ses @-}</span>
<span class="token hvariable">ses</span> <span class="token operator">::</span> <span class="token punctuation">(</span><span class="token hvariable">a</span> <span class="token operator">-&gt;</span> <span class="token hvariable">b</span> <span class="token operator">-&gt;</span> <span class="token constant">Bool</span><span class="token punctuation">)</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token hvariable">b</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token constant">DI</span><span class="token punctuation">]</span>
<span class="token hvariable">ses</span> <span class="token hvariable">eq</span> <span class="token hvariable">as</span> <span class="token hvariable">bs</span> <span class="token operator">=</span> <span class="token hvariable">path</span> <span class="token operator">.</span> <span class="token builtin">head</span> <span class="token operator">.</span> <span class="token builtin">dropWhile</span> <span class="token punctuation">(</span><span class="token operator">\</span><span class="token hvariable">dl</span> <span class="token operator">-&gt;</span> <span class="token hvariable">poi</span> <span class="token hvariable">dl</span> <span class="token operator">/=</span> <span class="token hvariable">lena</span> <span class="token operator">||</span> <span class="token hvariable">poj</span> <span class="token hvariable">dl</span> <span class="token operator">/=</span> <span class="token hvariable">lenb</span><span class="token punctuation">)</span> <span class="token operator">.</span>
            <span class="token builtin">concat</span> <span class="token operator">.</span> <span class="token builtin">iterate</span> <span class="token punctuation">(</span><span class="token hvariable">dstep</span> <span class="token hvariable">cd</span><span class="token punctuation">)</span> <span class="token operator">.</span> <span class="token punctuation">(</span><span class="token operator">:</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">.</span> <span class="token hvariable">addsnake</span> <span class="token hvariable">cd</span> <span class="token operator">$</span>
            <span class="token constant">DL</span> <span class="token punctuation">{</span><span class="token hvariable">poi</span><span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">,</span><span class="token hvariable">poj</span><span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">,</span><span class="token hvariable">path</span><span class="token operator">=</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">}</span>
            <span class="token keyword">where</span> <span class="token hvariable">cd</span> <span class="token operator">=</span> <span class="token hvariable">canDiag</span> <span class="token hvariable">eq</span> <span class="token hvariable">as</span> <span class="token hvariable">bs</span> <span class="token hvariable">lena</span> <span class="token hvariable">lenb</span>
                  <span class="token hvariable">lena</span> <span class="token operator">=</span> <span class="token builtin">length</span> <span class="token hvariable">as</span><span class="token punctuation">;</span> <span class="token hvariable">lenb</span> <span class="token operator">=</span> <span class="token builtin">length</span> <span class="token hvariable">bs</span></code></pre></div>
<p>Turning now to the second condition:
To prove termination of a recursive function, LH needs to be told of a size reduced towards a lower bound at each recursive call.
This is called a <a href="https://ucsd-progsys.github.io/liquidhaskell/specifications/#termination-metrics">termination metric</a>.</p>
<p>Some recursive functions might be proved terminating without intervention, because when no explicit metric is given LH follows a simple heuristic:
it checks for the first (non-function) argument with an <a href="https://ucsd-progsys.github.io/liquidhaskell/specifications/#default-termination-metrics">associated size metric</a> to be strictly decreasing and non-negative at each recursive call.
LH has definitions of associated size metric for lists (their length) and integer values,
which are considered metrics themselves when non-negative.
Metrics get interesting when we have mutually recursive functions,
as is the case for <code class="language-text">doPrefix</code> and <code class="language-text">doSuffix</code>,
a pair of local functions whose job is to chop common lines of input to create the context windows that make a diff’s hunks.
I introduced a <a href="https://ucsd-progsys.github.io/liquidhaskell/specifications/#lexicographic-termination-metrics">lexicographic metric</a>,
annotated with the syntax <code class="language-text">/ [metric1, metric2, ...]</code> at the end of a function refinement,
to prove their termination:</p>
<div class="gatsby-highlight"><pre class="language-haskell"><code class="language-haskell"><span class="token keyword">type</span> <span class="token constant">Diff</span> <span class="token hvariable">c</span> <span class="token operator">=</span> <span class="token constant">PolyDiff</span> <span class="token hvariable">c</span> <span class="token hvariable">c</span>

<span class="token comment">{-@ doPrefix :: hunk : [Diff [c]] -&gt; [Diff [c]] / [len hunk, 0] @-}</span>
<span class="token hvariable">doPrefix</span> <span class="token operator">::</span> <span class="token punctuation">[</span><span class="token constant">Diff</span> <span class="token punctuation">[</span><span class="token hvariable">c</span><span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token constant">Diff</span> <span class="token punctuation">[</span><span class="token hvariable">c</span><span class="token punctuation">]</span><span class="token punctuation">]</span>
<span class="token hvariable">doPrefix</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
<span class="token hvariable">doPrefix</span> <span class="token punctuation">[</span><span class="token constant">Both</span> <span class="token hvariable">_</span> <span class="token hvariable">_</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
<span class="token hvariable">doPrefix</span> <span class="token punctuation">(</span><span class="token constant">Both</span> <span class="token hvariable">xs</span> <span class="token hvariable">ys</span> <span class="token operator">:</span> <span class="token hvariable">more</span><span class="token punctuation">)</span> <span class="token operator">=</span>
  <span class="token constant">Both</span> <span class="token punctuation">(</span><span class="token builtin">drop</span> <span class="token punctuation">(</span><span class="token builtin">length</span> <span class="token hvariable">xs</span> <span class="token operator">-</span> <span class="token hvariable">contextSize</span><span class="token punctuation">)</span> <span class="token hvariable">xs</span><span class="token punctuation">)</span>
       <span class="token punctuation">(</span><span class="token builtin">drop</span> <span class="token punctuation">(</span><span class="token builtin">length</span> <span class="token hvariable">ys</span> <span class="token operator">-</span> <span class="token hvariable">contextSize</span><span class="token punctuation">)</span> <span class="token hvariable">ys</span><span class="token punctuation">)</span>
    <span class="token operator">:</span> <span class="token hvariable">doSuffix</span> <span class="token hvariable">more</span>
<span class="token hvariable">doPrefix</span> <span class="token punctuation">(</span><span class="token hvariable">d</span> <span class="token operator">:</span> <span class="token hvariable">ds</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token hvariable">d</span> <span class="token operator">:</span> <span class="token hvariable">doSuffix</span> <span class="token hvariable">ds</span>

<span class="token comment">{-@ doSuffix :: hunk : [Diff [c]] -&gt; [Diff [c]] / [len hunk, 1]@-}</span>
<span class="token hvariable">doSuffix</span> <span class="token operator">::</span> <span class="token punctuation">[</span><span class="token constant">Diff</span> <span class="token punctuation">[</span><span class="token hvariable">c</span><span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token constant">Diff</span> <span class="token punctuation">[</span><span class="token hvariable">c</span><span class="token punctuation">]</span><span class="token punctuation">]</span>
<span class="token hvariable">doSuffix</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
<span class="token hvariable">doSuffix</span> <span class="token punctuation">[</span><span class="token constant">Both</span> <span class="token hvariable">xs</span> <span class="token hvariable">ys</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token constant">Both</span> <span class="token punctuation">(</span><span class="token builtin">take</span> <span class="token hvariable">contextSize</span> <span class="token hvariable">xs</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token builtin">take</span> <span class="token hvariable">contextSize</span> <span class="token hvariable">ys</span><span class="token punctuation">)</span><span class="token punctuation">]</span>
<span class="token hvariable">doSuffix</span> <span class="token punctuation">(</span><span class="token constant">Both</span> <span class="token hvariable">xs</span> <span class="token hvariable">ys</span> <span class="token operator">:</span> <span class="token hvariable">more</span><span class="token punctuation">)</span>
  <span class="token operator">|</span> <span class="token builtin">length</span> <span class="token hvariable">xs</span> <span class="token operator">&lt;=</span> <span class="token hvariable">contextSize</span> <span class="token operator">*</span> <span class="token number">2</span> <span class="token operator">=</span> <span class="token constant">Both</span> <span class="token hvariable">xs</span> <span class="token hvariable">ys</span> <span class="token operator">:</span> <span class="token hvariable">doPrefix</span> <span class="token hvariable">more</span>
  <span class="token operator">|</span> <span class="token builtin">otherwise</span> <span class="token operator">=</span>
      <span class="token constant">Both</span> <span class="token punctuation">(</span><span class="token builtin">take</span> <span class="token hvariable">contextSize</span> <span class="token hvariable">xs</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token builtin">take</span> <span class="token hvariable">contextSize</span> <span class="token hvariable">ys</span><span class="token punctuation">)</span> <span class="token operator">:</span>
        <span class="token hvariable">doPrefix</span> <span class="token punctuation">(</span><span class="token constant">Both</span> <span class="token punctuation">(</span><span class="token builtin">drop</span> <span class="token hvariable">contextSize</span> <span class="token hvariable">xs</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token builtin">drop</span> <span class="token hvariable">contextSize</span> <span class="token hvariable">ys</span><span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token hvariable">more</span><span class="token punctuation">)</span>
<span class="token hvariable">doSuffix</span> <span class="token punctuation">(</span><span class="token hvariable">d</span> <span class="token operator">:</span> <span class="token hvariable">ds</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token hvariable">d</span> <span class="token operator">:</span> <span class="token hvariable">doSuffix</span> <span class="token hvariable">ds</span></code></pre></div>
<p>Using this metric LH checks that either the input <code class="language-text">hunk</code> (a list of diff elements) length is reduced after each recursive call,
as it would do by its default heuristic,
or considers a call to <code class="language-text">doPrefix</code> (0) from <code class="language-text">doSuffix</code> (1) to be a strict reduction.
This second fallback metric is needed because of the third equation of <code class="language-text">doSuffix</code> (second guard),
where <code class="language-text">doPrefix</code> is called with a list of equal length.
Apart from this case, each (mutually) recursive call is done on the tail of the input and thus strictly decreasing.</p>
<p>Here I’ve presented instances of two general strategies to handle LH errors:</p>
<ol>
<li>Fight: Fix the failing termination checks by introducing <em>metrics</em>
and offending functions calls by adding specifications.</li>
<li>Flight: Disable checks by using an <em>escape hatch</em>, e.g. the <code class="language-text">{-@ lazy myRecursiveFunction @-}</code> annotation to circumvent termination checking,
the <code class="language-text">{-@ ignore myOffendingFunction @-}</code> to disable all checks within a function’s body
or the <code class="language-text">{-@ assume myFunction :: ... spec ... @-}</code> to set a function specification as true without verification.</li>
</ol>
<p><em>A priori</em> it’s desirable to minimize the use of escape hatches,
but they’re also tools to prioritize static checking efforts.</p>
<h2 id="invariant-static-checking"><a class="anchor before" href="https://www.tweag.io/rss.xml#invariant-static-checking"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>Invariant static checking</h2>
<p>One thing that made <code class="language-text">Diff</code> particularly suitable for this effort is that a detailed specification of it existed in the form of a research paper.
Indeed, my <a href="https://github.com/seereason/Diff/pull/21">first documentation contribution</a> was making their connection explicit throughout.
The Myers diff algorithm can be summarized as a breadth-first search for the shortest path across a bidimensional <em>edit grid</em> to an endpoint,<sup id="fnref-5"><a class="footnote-ref" href="https://www.tweag.io/rss.xml#fn-5">5</a></sup>
the latter representing the complete transformation of one input to the other.
The algorithm is in fact tersely expressed in the <code class="language-text">ses</code> definition presented before;
its name stands for “smallest edit script”,
which is one of the output characterizations of the diff algorithm.
What I found is that the idea of a <em>wave front</em> is the link between this implementation and the original algorithm.
This statement is now supported by a static check showing that a wave front is transformed
as the algorithm prescribes for its inner loop.</p>
<p>A wave front is defined as a list of nodes at the same <em>depth</em>,
i.e. the edit trace length,
which is iterated upon by the <code class="language-text">dstep</code> function to return nodes one step deeper.
This function is a direct implementation of the extension procedure used by the algorithm at each search step.
Furthermore, the paper proves a pair of <a href="https://en.wikipedia.org/wiki/Lemma_(mathematics)">lemmas</a> that result in a specific configuration of the node list after each iteration,
which is related to the diagonals on the edit grid and checked by a <code class="language-text">wfDiags</code> predicate that I wrote to specify it.
The details of this condition aren’t essential here:
while the paper leverages it to introduce a space optimization,
the Haskell implementation doesn’t depend on it,
but the configuration is preserved nonetheless.</p>
<p>I encoded the fixed depth of nodes and their diagonal configuration using <a href="https://ucsd-progsys.github.io/liquidhaskell/specifications/#type-aliases">refinement type aliases</a> to obtain a wave front specification.</p>
<div class="gatsby-highlight"><pre class="language-haskell"><code class="language-haskell"><span class="token comment">-- | A node representing the tip of a path in the edit grid.</span>
<span class="token keyword">data</span> <span class="token constant">DL</span> <span class="token operator">=</span> <span class="token constant">DL</span>
    <span class="token punctuation">{</span> <span class="token operator">...</span>
    <span class="token punctuation">,</span> <span class="token hvariable">path</span> <span class="token operator">::</span> <span class="token punctuation">[</span><span class="token constant">DI</span><span class="token punctuation">]</span>   <span class="token comment">-- ^ The edit trace accumulated so far</span>
    <span class="token punctuation">}</span> <span class="token keyword">deriving</span> <span class="token punctuation">(</span><span class="token constant">Show</span><span class="token punctuation">,</span> <span class="token constant">Eq</span><span class="token punctuation">)</span>

<span class="token comment">-- A node at a fixed edit trace length (depth).</span>
<span class="token comment">{-@ type DLN D = { x : DL | len (path x) = D } @-}</span>

<span class="token comment">-- | This function is used only in LH specs to check if</span>
<span class="token comment">-- diagonal configuration holds for a node list.</span>
<span class="token hvariable">wfDiags</span> <span class="token operator">::</span> <span class="token punctuation">[</span><span class="token constant">DL</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token constant">Bool</span>
<span class="token hvariable">wfDiags</span> <span class="token operator">=</span> <span class="token operator">...</span>

<span class="token comment">-- All nodes in a wave front are at the same depth,</span>
<span class="token comment">-- and satisfy the diagonal configuration.</span>
<span class="token comment">{-@ type WaveFront D = {xs : [DLN D] | wfDiags xs} @-}</span></code></pre></div>
<p>With this encoding, and a phantom parameter carrying the current depth,
I specified <code class="language-text">dstep</code> (called from <code class="language-text">ses</code>) to match the algorithm behavior
(which also includes the node list growing by one).</p>
<div class="gatsby-highlight"><pre class="language-haskell"><code class="language-haskell"><span class="token comment">{-@
dstep
  :: (Nat -&gt; Nat -&gt; Bool)
  -&gt; d : Nat
  -&gt; {nodes : WaveFront d | len nodes &gt; 0}
  -&gt; {v : WaveFront (d + 1) | len v = len nodes + 1}
@-}</span>
<span class="token hvariable">dstep</span>
  <span class="token operator">::</span> <span class="token punctuation">(</span><span class="token constant">Int</span> <span class="token operator">-&gt;</span> <span class="token constant">Int</span> <span class="token operator">-&gt;</span> <span class="token constant">Bool</span><span class="token punctuation">)</span> <span class="token comment">-- ^ Check for node coordinates producing a free edge</span>
  <span class="token operator">-&gt;</span> <span class="token constant">Int</span>                  <span class="token comment">-- ^ The current depth; used for the static check of the wave front invariant</span>
  <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token constant">DL</span><span class="token punctuation">]</span>                 <span class="token comment">-- ^ A non-empty wave front of nodes at edit distance D</span>
  <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token constant">DL</span><span class="token punctuation">]</span>                 <span class="token comment">-- ^ A non-empty wave front of nodes at edit distance D+1</span></code></pre></div>
<p>Refinement type aliases become statically checked invariants when used in a function specification,
and are verified to hold at each call site.</p>
<p>As a second example, let’s see the invariants of a <code class="language-text">Hunk</code>,
expressed again using refinement type aliases.</p>
<div class="gatsby-highlight"><pre class="language-haskell"><code class="language-haskell"><span class="token comment">-- A valid list diff is such that any `Both` value has arguments of equal length.</span>
<span class="token comment">{-@ type ValidListDiff a b = { d : PolyDiff [a] [b] | validListDiff d }@-}</span>

<span class="token comment">-- | True when, for a 'Both' value, both sides have the same length.</span>
<span class="token comment">-- 'First' and 'Second' trivially satisfy this.</span>
<span class="token comment">-- Introduced for LH specifications.</span>
<span class="token hvariable">validListDiff</span> <span class="token operator">::</span> <span class="token constant">PolyDiff</span> <span class="token punctuation">[</span><span class="token hvariable">a</span><span class="token punctuation">]</span> <span class="token punctuation">[</span><span class="token hvariable">b</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token constant">Bool</span>
<span class="token hvariable">validListDiff</span> <span class="token punctuation">(</span><span class="token constant">Both</span> <span class="token hvariable">xs</span> <span class="token hvariable">ys</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token builtin">length</span> <span class="token hvariable">xs</span> <span class="token operator">==</span> <span class="token builtin">length</span> <span class="token hvariable">ys</span>
<span class="token hvariable">validListDiff</span> <span class="token hvariable">_</span> <span class="token operator">=</span> <span class="token constant">True</span>

<span class="token comment">-- | True if the list does not contain adjacent 'PolyDiff's with the same constructor.</span>
<span class="token hvariable">noStuttering</span> <span class="token operator">::</span> <span class="token punctuation">[</span><span class="token constant">PolyDiff</span> <span class="token hvariable">a</span> <span class="token hvariable">b</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token constant">Bool</span>
<span class="token hvariable">noStuttering</span> <span class="token operator">=</span> <span class="token operator">...</span>

<span class="token comment">-- | A 'Hunk' is a list of adjacent 'Diff's.</span>
<span class="token comment">--</span>
<span class="token comment">-- No two consecutive elements in a 'Hunk' are both applications</span>
<span class="token comment">-- of 'First', 'Second', or 'Both', i.e. the list does not stutter</span>
<span class="token comment">-- on 'Diff' constructors.</span>
<span class="token keyword">type</span> <span class="token constant">Hunk</span> <span class="token hvariable">c</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token constant">Diff</span> <span class="token punctuation">[</span><span class="token hvariable">c</span><span class="token punctuation">]</span><span class="token punctuation">]</span>

<span class="token comment">{-@ type Hunk c = { h : [ValidListDiff c c] | noStuttering h} @-}</span></code></pre></div>
<p>The interesting part here is the check for the <code class="language-text">noStuttering</code> invariant in the specification of the main <code class="language-text">Hunk</code> producing function.
For brevity’s sake I won’t show this function, but let’s see what came to be of the specification of the previously presented <code class="language-text">doPrefix</code>,
that is part of it,
for the check to pass.</p>
<div class="gatsby-highlight"><pre class="language-haskell"><code class="language-haskell"><span class="token comment">{-@ doPrefix ::  h : Hunk c
             -&gt; {v : [ValidListDiff c c] | noFFSS v
                 &amp;&amp; ... other auxiliary post-conditions ... } / [len h, 0] @-}</span></code></pre></div>
<p>Essentially, this function traverses a given <code class="language-text">Hunk</code> and chops and splits <code class="language-text">Both</code> elements to a context size argument.
After doing so the <code class="language-text">Hunk</code> “stutters” on such elements,
so it stops being a <code class="language-text">Hunk</code> in the <em>refined</em> sense,
even though the Haskell types match.
Note the regular type synonym and the refinement type synonym don’t coalesce:
At the Haskell level the synonym is just a renaming,
but in the specification it is shadowed by the refinement synonym (thus enforcing its invariants).
The <code class="language-text">noFFSS</code> helper characterizes the resulting list;
it is like <code class="language-text">noStuttering</code>, but just for the other <code class="language-text">PolyDiff</code> constructors: <code class="language-text">First</code> and <code class="language-text">Second</code>.
Other auxiliary post-conditions (not shown) stating that input and output lists shared head constructors were also necessary for this check.</p>
<p>The verification of these and other invariants followed a similar outline:</p>
<ol>
<li>Identify and document the invariant</li>
<li>Encode it in refinements</li>
<li>Write the specifications</li>
<li>Please the compiler</li>
</ol>
<p>Pleasing the compiler after adding a new specification was trickier for me than the usual Haskell type error propagation and fix workflow.
Figuring out exactly what LH is aware of when checking a specification requires an intuition of how it builds a context;
then it’s a matter of making the missing information available.</p>
<p>For instance,
the last step to get back a <code class="language-text">Hunk</code> after the <code class="language-text">doPrefix</code>-<code class="language-text">doSuffix</code> operation required passing a lemma within a local dead binding for the specification to be verified.</p>
<div class="gatsby-highlight"><pre class="language-haskell"><code class="language-haskell"><span class="token comment">{-@ assume lemmaReverseNoStuttering
      :: xs:_ -&gt; { noStuttering (reverse xs) = noStuttering xs } @-}</span>
<span class="token hvariable">lemmaReverseNoStuttering</span> <span class="token operator">::</span> <span class="token constant">Hunk</span> <span class="token hvariable">c</span> <span class="token operator">-&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token hvariable">lemmaReverseNoStuttering</span> <span class="token hvariable">_</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span>

<span class="token comment">-- | Split a 'Diff' list at consecutive 'Both'-'Both' boundaries.</span>
<span class="token comment">{-@ splitBothBoth :: {ds:[ValidListDiff c c] | noFFSS ds} -&gt; [Hunk c] @-}</span>
<span class="token hvariable">splitBothBoth</span> <span class="token operator">::</span> <span class="token punctuation">[</span><span class="token constant">Diff</span> <span class="token punctuation">[</span><span class="token hvariable">c</span><span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token constant">Hunk</span> <span class="token hvariable">c</span><span class="token punctuation">]</span>
<span class="token hvariable">splitBothBoth</span> <span class="token operator">=</span> <span class="token hvariable">go</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
  <span class="token keyword">where</span>
    <span class="token comment">{-@ go
          :: g:Hunk c
          -&gt; {xs : [ValidListDiff c c] | noFFSS xs &amp;&amp; not (headAlike g xs) }
          -&gt; [Hunk c] / [len xs]
      @-}</span>
    <span class="token hvariable">go</span> <span class="token operator">::</span> <span class="token constant">Hunk</span> <span class="token hvariable">c</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token constant">Diff</span> <span class="token punctuation">[</span><span class="token hvariable">c</span><span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token operator">-&gt;</span> <span class="token punctuation">[</span><span class="token constant">Hunk</span> <span class="token hvariable">c</span><span class="token punctuation">]</span>
    <span class="token hvariable">go</span> <span class="token hvariable">g</span> <span class="token punctuation">(</span><span class="token hvariable">x</span><span class="token operator">@</span><span class="token constant">Both</span><span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token operator">:</span> <span class="token hvariable">y</span><span class="token operator">@</span><span class="token constant">Both</span><span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token operator">:</span> <span class="token hvariable">xs</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token builtin">reverse</span> <span class="token punctuation">(</span><span class="token hvariable">x</span><span class="token operator">:</span><span class="token hvariable">g</span><span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token hvariable">go</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">(</span><span class="token hvariable">y</span><span class="token operator">:</span><span class="token hvariable">xs</span><span class="token punctuation">)</span>
      <span class="token keyword">where</span>
        <span class="token hvariable">lemma</span> <span class="token operator">=</span> <span class="token hvariable">lemmaReverseNoStuttering</span> <span class="token punctuation">(</span><span class="token hvariable">x</span><span class="token operator">:</span><span class="token hvariable">g</span><span class="token punctuation">)</span>
    <span class="token hvariable">go</span> <span class="token hvariable">g</span> <span class="token punctuation">(</span><span class="token hvariable">x</span> <span class="token operator">:</span> <span class="token hvariable">xs</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token hvariable">go</span> <span class="token punctuation">(</span><span class="token hvariable">x</span><span class="token operator">:</span><span class="token hvariable">g</span><span class="token punctuation">)</span> <span class="token hvariable">xs</span>
    <span class="token hvariable">go</span> <span class="token hvariable">g</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token builtin">reverse</span> <span class="token hvariable">g</span><span class="token punctuation">]</span>
      <span class="token keyword">where</span>
        <span class="token hvariable">lemma</span> <span class="token operator">=</span> <span class="token hvariable">lemmaReverseNoStuttering</span> <span class="token hvariable">g</span></code></pre></div>
<p>This binding ultimately gets optimized away by GHC, but LH requires it to satisfy the static checks.
LH didn’t have a means to know that <code class="language-text">reverse</code> preserves the <code class="language-text">noStuttering</code> of a <code class="language-text">PolyDiff</code> list,
so I provided it.</p>
<p>I decided to <code class="language-text">assume</code> the lemma above on the rationale that its validity is straight-forward,
while its proof would probably not be,
making the disease not worth the medicine.</p>
<h2 id="lifting-a-dam"><a class="anchor before" href="https://www.tweag.io/rss.xml#lifting-a-dam"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>Lifting a dam</h2>
<p>After this work I’m flooded with many thoughts and feelings about LH from the user perspective,
but also ideas for important future developments.</p>
<p>One particular source of difficulty I found is differentiating between the existing means of <em>lifting</em> a Haskell function into the logic:
<code class="language-text">reflect</code>, <code class="language-text">inline</code>, <code class="language-text">measure</code> and <code class="language-text">define</code>.
By default, Haskell functions like <code class="language-text">wfDiag</code> cannot be used in the refinement type predicates.
They have to be accompanied by an annotation that indicates how to make them available in the predicates,
which I omitted in my examples for the sake of argument.</p>
<p>Existing documentation does a good job at explaining their requirements and purpose.
Nevertheless, subtle differences in constraint generation and logical expression unfolding aren’t documented,
and these details matter when choosing between them in certain cases.
Addressing this could lead to unifying or deprecating some functionality,
but at least specifying them at a finer grain and adding some use case examples could go a long way.</p>
<p>A more salient difficulty are the error messages.
They can be baffling,
featuring not very human friendly variable names spread across enormous lists of bindings forming their “context”.
Skimming through this context is a skill that I would love to deprecate.
Looking first at the “inferred type” and the “required type” part at the start of the message is a useful technique,
which can provide a lead to the source of the problem.</p>
<p>I find refinement types appealing because they are powerful yet non-sophisticated enough to be intuitive.
Nevertheless, getting a function specification checked can become intricate,
requiring additional proving machinery like
function definitions exclusively intended for refinement predicates,
lemmas in dead bindings to pass additional constraints
or even heavy refactoring.
However,
I think the upfront cost of entry can be easily balanced out by using the escape hatches to focus the effort investment.
In the <code class="language-text">Diff</code> package, for instance,
some low hanging fruit could be picked right away after disabling the checks on error triggering functions,
e.g. refining integer values to naturals or enforcing clear-cut relations between record fields,
adding immediate value without additional machinery.</p>
<p>A drawback is that polymorphism seems at odds with the simplicity of refinements:
the more we want to specify about a value or function, the more we narrow its type.
That said,
there seems to be a correlation between code complexity and LH verification complexity that is worth investigating further:
changes that simplified the verification of an invariant tended to benefit the code quality independently of it.</p>
<p>Choosing between fight or flight for a given invariant is ultimately about balancing safety gains with added complexity,
and in my experience the code structure is what tips the scale:
it determined both the refactorings I needed and the checks I had to forgo.
My guess is that the whole equation changes when refinement types are a first class consideration during design.</p>
<h2 id="clearing-up-the-waters"><a class="anchor before" href="https://www.tweag.io/rss.xml#clearing-up-the-waters"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>Clearing up the waters</h2>
<p>Hopefully this little epic amounts to a useful case study that,
by showing what using LH is like today,
encourages you to add static checks to an existing codebase
or experiment in your next project with LH in your toolbox,
and the techniques I’ve shared help prioritize the approach.</p>
<p>I discussed some of LH pain points to offer a balanced view and propose further DX improvements.
There’s much to be done, but it’s steadily getting there.
My opinion is that Liquid Haskell is a viable option today to add formal guarantees to an unsuspecting codebase at a reasonable cost,
as long as the palette of shapes and extent this can take is kept in mind during design.
Know that you’re welcome to contribute to LH development and that we’re ready to help strengthen your codebase.
Just reach out!</p>
<p>Finally, I would like to express my gratitude to Aleksandr Vershilov, Arnaud Spiwack and Christopher Harrison for reviewing this text,
and notably to Facundo Domínguez whose close collaboration was instrumental to streamline this work.</p>
<div class="footnotes">
<hr/>
<ol>
<li id="fn-1">At the time of writing, the static checks are about to be proposed for upstream integration. But they can be found in the <a href="https://github.com/ucsd-progsys/liquidhaskell/tree/5e043ad25987fed9d11c8df365ac7fae396262d6/tests/Diff">Liquid Haskell test suite</a> as well.<a class="footnote-backref" href="https://www.tweag.io/rss.xml#fnref-1">↩</a></li>
<li id="fn-2">A nice perk of working at Tweag is being supported to do open source contributions during or in-between client projects.<a class="footnote-backref" href="https://www.tweag.io/rss.xml#fnref-2">↩</a></li>
<li id="fn-3">Found in <a href="https://github.com/seereason/Diff/pull/21">https://github.com/seereason/Diff/pull/21</a> and <a href="https://github.com/seereason/Diff/pull/23">https://github.com/seereason/Diff/pull/23</a><a class="footnote-backref" href="https://www.tweag.io/rss.xml#fnref-3">↩</a></li>
<li id="fn-4">Found in <a href="https://github.com/seereason/Diff/pull/24">https://github.com/seereason/Diff/pull/24</a>, <a href="https://github.com/seereason/Diff/pull/25">https://github.com/seereason/Diff/pull/25</a>, <a href="https://github.com/seereason/Diff/pull/26">https://github.com/seereason/Diff/pull/26</a> and <a href="https://github.com/seereason/Diff/pull/27">https://github.com/seereason/Diff/pull/27</a>.<a class="footnote-backref" href="https://www.tweag.io/rss.xml#fnref-4">↩</a></li>
<li id="fn-5">The coordinates of a node in the edit grid represent the size of the prefix consumed from the first input and the size of the produced prefix of the other input, respectively. Thus, the endpoint has coordinates matching both input lengths. The grid’s most relevant feature is that, in addition to vertical and horizontal edges (corresponding to deletions and additions, respectively), there are “free” diagonal edges wherever both inputs have matching elements.<a class="footnote-backref" href="https://www.tweag.io/rss.xml#fnref-5">↩</a></li>
</ol>
</div></div>
    </summary>
    <updated>2026-06-11T00:00:00Z</updated>
    <published>2026-06-11T00:00:00Z</published>
    <source>
      <id>https://tweag.io</id>
      <author>
        <name>Tweag I/O</name>
      </author>
      <link href="https://tweag.io" rel="alternate" type="text/html"/>
      <link href="http://www.tweag.io/rss.xml" rel="self" type="application/rss+xml"/>
      <subtitle>Scale your engineering power. We enable deep-tech startups to achieve
their vision, from research to product delivery.</subtitle>
      <title>Tweag - Engineering blog</title>
      <updated>2026-06-12T11:01:45Z</updated>
    </source>
  </entry>

  <entry>
    <id>https://www.stackage.org/blog/2026/06/hashell-ecosystem-ws-2026-talk</id>
    <link href="https://www.stackage.org/blog/2026/06/hashell-ecosystem-ws-2026-talk" rel="alternate" type="text/html"/>
    <title>Stackage talk at Haskell Ecosystem Workshop 2026</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><h2>Stackage talk at Haskell Ecosystem Workshop 2026</h2>
<p>Jens Petersen gave a talk about Stackage at
the Haskell Ecosystem Workshop 2026 (4th June),
organized by the Haskell Foundation before Zurihac.</p>
<p>Here are the html <a href="https://petersen.fedorapeople.org/talks/hew-2026-stackage.html">slides</a> (<a href="https://petersen.fedorapeople.org/talks/hew-2026-stackage-single.html">single page html</a>).</p></div>
    </content>
    <updated>2026-06-08T16:00:00Z</updated>
    <source>
      <id>https://www.stackage.org/</id>
      <author>
        <name>The Stackage Curator team</name>
      </author>
      <link href="https://www.stackage.org/blog/feed" rel="self" type="application/atom+xml"/>
      <link href="https://www.stackage.org/" rel="alternate" type="text/html"/>
      <title>Stackage Curator blog</title>
      <updated>2026-06-08T16:00:00Z</updated>
    </source>
  </entry>

  <entry xml:lang="en-us">
    <id>https://haskellforall.com/2026/06/ergonomic-overrides-for-nixpkgs</id>
    <link href="https://haskellforall.com/2026/06/ergonomic-overrides-for-nixpkgs" rel="alternate" type="text/html"/>
    <title>Ergonomic overrides for Nixpkgs</title>
    <summary>Announcement post for the override-utils Nix package</summary>
    <updated>2026-06-06T00:00:00Z</updated>
    <published>2026-06-06T00:00:00Z</published>
    <source>
      <id>https://haskellforall.com</id>
      <author>
        <name>Gabriella Gonzalez</name>
      </author>
      <link href="https://haskellforall.com" rel="alternate" type="text/html"/>
      <link href="https://haskellforall.com/rss.xml" rel="self" type="application/rss+xml"/>
      <subtitle>A blog about Haskell and functional programming.</subtitle>
      <title>Haskell for all</title>
      <updated>2026-06-07T13:45:09Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-9757377.post-7786446406428155110</id>
    <link href="https://wadler.blogspot.com/feeds/7786446406428155110/comments/default" rel="replies" title="Post Comments" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment/fullpage/post/9757377/7786446406428155110" rel="replies" title="0 Comments" type="text/html"/>
    <link href="https://www.blogger.com/feeds/9757377/posts/default/7786446406428155110" rel="edit" type="application/atom+xml"/>
    <link href="https://www.blogger.com/feeds/9757377/posts/default/7786446406428155110" rel="self" type="application/atom+xml"/>
    <link href="https://wadler.blogspot.com/2026/06/professor-emeritus.html" rel="alternate" title="Professor Emeritus" type="text/html"/>
    <title>Professor Emeritus</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><div class="separator"><p style="margin-left: 1em; margin-right: 1em;"><img alt="" class="alignleft size-medium wp-image-217956" height="640" src="https://www.angrymetalguy.com/wp-content/uploads/2025/06/Professor-Emeritus_A-Land-Long-Gone-01-350x350.jpg" width="640"/></p></div><p style="font-style: normal; line-height: normal; margin: 0px;"><span style="font-size: large;">After retiring last July, the University Senate have approved my emeritus status. I'm grateful to Julian Bradfield for his work drafting the generous minute that accompanied the approval.</span></p><p style="font-style: normal; line-height: normal; margin: 0px;"><span style="font-family: times;"><br/></span></p><p style="font-style: normal; line-height: normal; margin: 0px; text-align: center;"><b><span style="font-family: times;"/></b></p><blockquote><p style="font-style: normal; line-height: normal; margin: 0px; text-align: center;"><b><span style="font-family: times;">Special Minute</span></b></p><p style="font-style: normal; line-height: normal; margin: 0px; text-align: center;"><b><span style="font-family: times;">Professor Philip Wadler BSc, MSc, PhD, FRSE, FACM, FRS</span></b></p><p style="font-style: normal; line-height: normal; margin: 0px; text-align: center;"><b><span style="font-family: times;">Emeritus Professor of Theoretical Computer Science</span></b></p><p style="font-style: normal; line-height: normal; margin: 0px;"><span style="font-family: times;"><br/></span></p><p style="font-style: normal; line-height: normal; margin: 0px;"><span style="font-family: times;">We are pleased to nominate Professor Philip Wadler for the title of Emeritus Professor at the University of Edinburgh. Professor Wadler is a popular educator and has had an extensive career in both academia and industry, with seminal contributions to the field of computer science, particularly in the theory and practice of programming languages. Philip Wadler obtained a BSc with honours in mathematics from Stanford University in 1977, followed by a MSc and PhD in computer science in 1979 and 1984 from Carnegie-Mellon University. He took up a postdoc at Oxford University, and in 1987 he was appointed as a lecturer at the University of Glasgow. In 1996, Phil switched to industry, working at Bell Labs and Avaya Labs. He returned to academia in 2003, taking up the Chair of Theoretical Computer Science at the University of Edinburgh.</span></p><p style="font-style: normal; line-height: normal; margin: 0px;"><span style="font-family: times;"><br/></span></p><p style="font-style: normal; line-height: normal; margin: 0px;"><span style="font-family: times;">Professor Wadler’s research centres on the theory and practice of programming languages. He served as first editor of the Haskell report, and introduced what are arguably its two main innovations, type classes and monads. Haskell saw widespread use, and type classes and </span><span style="font-family: times;">monads were adopted by a wide variety of other programming languages and proof assistants. He contributed to the design of the programming language Java, and introduced a model of it widely used by researchers. By influencing the design of popular programming languages, Phil has had a profound impact not only on programmers, but also on the users of the systems those programmers build. If you’ve used Facebook or X, Android or iPhone, you’ve run code that exploits concepts Phil pioneered.</span></p><p style="font-style: normal; line-height: normal; margin: 0px;"><span style="font-family: times;"><br/></span></p><p style="font-style: normal; line-height: normal; margin: 0px;"><span style="font-family: times;">Professor Wadler has published many seminal monographs and textbooks throughout his illustrious career. His contribution has been honoured in many ways. He served as chair of the ACM Special Interest Group on Programming Languages (SIGPLAN) from 2009–2012 </span><span style="font-family: times;">and received its Distinguished Service Award in 2016. He was appointed a Fellow of the Royal Society of Edinburgh in 2005, a Fellow of the Association for Computing Machinery in 2007, and a Fellow of the Royal Society in 2022. He regularly delivers keynotes at both academic </span><span style="font-family: times;">and developer conferences. In 2016, his sixtieth birthday was marked by a two-day </span><i style="font-family: times;">Wadlerfest</i><span style="font-family: times;">, and an accompanying festschrift published by Springer.</span></p><p style="font-style: normal; line-height: normal; margin: 0px;"><span style="font-family: times;"><br/></span></p><p style="font-style: normal; line-height: normal; margin: 0px;"><span style="font-family: times;">Phil is a passionate and popular teacher. On moving to Edinburgh in 2003, he introduced a first-year programming languages course based on Haskell and was shortlisted for the EUSA Teaching Award (Overall Best Performer) in 2009. His Honours courses on programming </span><span style="font-family: times;">language theory have been among the most popular theoretical courses. Phil is widely known for theatrical performance and applies this talent outside academia, often performing stand- up comedy via Bright Club, and appeared in the Fringe via the Cabaret of Dangerous Ideas in 2024.</span></p><p style="font-style: normal; line-height: normal; margin: 0px;"><span style="font-family: times;"><br/></span></p><p style="font-style: normal; line-height: normal; margin: 0px;"><span style="font-family: times;">Since 2017, Phil has worked closely with industry, including consulting for IOG where he helped to design the smart contract system for its Cardano blockchain and applied formal methods to ensure its reliability. After retirement from Edinburgh, he plans to write a version </span><span style="font-family: times;">of his online text for the proof assistant Agda updated to the proof assistant Lean. He will appear again this summer at the Fringe.</span></p><p style="font-style: normal; line-height: normal; margin: 0px;"><span style="font-family: times;"><br/></span></p><p style="font-style: normal; line-height: normal; margin: 0px;"><span style="font-family: times;">To conclude, Professor Philip Wadler's career is characterised by groundbreaking research, impactful teaching, and significant professional service. His work has shaped the landscape of programming languages and computer science education. Conferring the title of Emeritus </span><span style="font-family: times;">Professor on Professor Wadler would honour his substantial contributions to the University of Edinburgh and the broader scientific community.</span></p></blockquote><p style="font-style: normal; line-height: normal; margin: 0px;"><span style="font-family: times;"/></p></div>
    </content>
    <updated>2026-06-04T17:46:04Z</updated>
    <published>2026-06-04T17:46:04Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="Academia"/>
    <author>
      <name>Philip Wadler</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/12009347515095774366</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-9757377</id>
      <category term="Politics"/>
      <category term="Programming Languages"/>
      <category term="Functional Programming"/>
      <category term="Computing"/>
      <category term="Scotland"/>
      <category term="Independence"/>
      <category term="Haskell"/>
      <category term="Yes!"/>
      <category term="Academia"/>
      <category term="UK"/>
      <category term="Edinburgh"/>
      <category term="Science"/>
      <category term="Cycling"/>
      <category term="Graphics"/>
      <category term="Types"/>
      <category term="Mathematics"/>
      <category term="US"/>
      <category term="Logic"/>
      <category term="Covid-19"/>
      <category term="Security"/>
      <category term="Web"/>
      <category term="Comics"/>
      <category term="EU"/>
      <category term="Climate Change"/>
      <category term="Israel"/>
      <category term="Theory"/>
      <category term="Blockchain"/>
      <category term="Comedy"/>
      <category term="Education"/>
      <category term="IOHK"/>
      <category term="Writing"/>
      <category term="AI"/>
      <category term="Agda"/>
      <category term="University"/>
      <category term="Cryptocurrency"/>
      <category term="Developers"/>
      <category term="Internet"/>
      <category term="SIGPLAN"/>
      <category term="Scala"/>
      <category term="Status"/>
      <category term="ACM"/>
      <category term="Concurrency"/>
      <category term="DSL"/>
      <category term="Databases"/>
      <category term="Dynamic and Static Typing"/>
      <category term="F#"/>
      <category term="Green"/>
      <category term="JavaScript"/>
      <category term="Lego"/>
      <category term="Privacy"/>
      <category term="Recursion"/>
      <category term="Session Types"/>
      <category term="Strange Loop"/>
      <category term="Category Theory"/>
      <category term="Formal Methods"/>
      <category term="Java"/>
      <category term="Object-Oriented"/>
      <category term="Technology"/>
      <category term="Architecture"/>
      <category term="Copyright"/>
      <category term="Distributed Computing"/>
      <category term="Europe"/>
      <category term="Productivity"/>
      <category term="Racket"/>
      <category term="Science Fiction"/>
      <category term="Theatre"/>
      <category term="BLM"/>
      <category term="Brexit"/>
      <category term="Communication"/>
      <category term="DRM"/>
      <category term="Environment"/>
      <category term="Erlang"/>
      <category term="Finance"/>
      <category term="Gender"/>
      <category term="Palestine"/>
      <category term="BDS"/>
      <category term="Books"/>
      <category term="Cinema"/>
      <category term="Japan"/>
      <category term="Net Neutrality"/>
      <category term="Open Access"/>
      <category term="Pyret"/>
      <category term="Scheme"/>
      <category term="Sweden"/>
      <author>
        <name>Philip Wadler</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/12009347515095774366</uri>
      </author>
      <link href="https://wadler.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="https://www.blogger.com/feeds/9757377/posts/default?alt=atom" rel="self" type="application/atom+xml"/>
      <link href="https://wadler.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="https://www.blogger.com/feeds/9757377/posts/default?alt=atom&amp;start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <title>Wadler's Blog</title>
      <updated>2026-06-04T17:46:04Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-9757377.post-5648851443101434722</id>
    <link href="https://wadler.blogspot.com/feeds/5648851443101434722/comments/default" rel="replies" title="Post Comments" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment/fullpage/post/9757377/5648851443101434722" rel="replies" title="0 Comments" type="text/html"/>
    <link href="https://www.blogger.com/feeds/9757377/posts/default/5648851443101434722" rel="edit" type="application/atom+xml"/>
    <link href="https://www.blogger.com/feeds/9757377/posts/default/5648851443101434722" rel="self" type="application/atom+xml"/>
    <link href="https://wadler.blogspot.com/2026/06/a-good-life-for-99-isnt-pipe-dream-it.html" rel="alternate" title="A good life for the 99% isn&#x2019;t a pipe dream: it can be done. Here&#x2019;s how" type="text/html"/>
    <title>A good life for the 99% isn’t a pipe dream: it can be done. Here’s how</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p><img alt="F15" class="wp-image-469" height="394" src="https://globaljusticeproject.wid.world/www-site/uploads/2026/05/F15-1024x631.png" width="640"/></p><p><img alt="F14" class="wp-image-470" height="394" src="https://globaljusticeproject.wid.world/www-site/uploads/2026/05/F14-1024x631.png" width="640"/></p><div style="text-align: left;"><span style="font-size: medium;">Thomas Piketty is at it again. He and his colleagues at the World Inequality Lab have produced a report outlining, with quantitative modelling, what a just world might look like and how to get there. A summary appears in the <a href="https://www.theguardian.com/commentisfree/2026/jun/04/a-good-life-for-the-99-isnt-a-pipe-dream-it-can-be-done-heres-how">Guardian</a>, and their full report is <a href="https://globaljusticeproject.wid.world/insight/summary/">online</a>.</span></div><p class="dcr-130mj7b"><span class="dcr-15rw6c2"/></p><blockquote><p class="dcr-130mj7b"><span class="dcr-15rw6c2">I</span>magine a future in which everyone enjoys high levels of wellbeing; where 90% of the world’s population doubles their income but works half the hours we work today. A world in which the bottom half of humanity sees its share of global wealth rise from <a href="https://www.theguardian.com/inequality/2025/dec/10/just-0001-hold-three-times-the-wealth-of-poorest-half-of-humanity-report-finds">just 2% today</a> to 30%; a world where we consume enough, but nobody over-consumes. And imagine achieving this on a planet that can comfortably sustain human life without its climate breaking down.</p><p class="dcr-130mj7b">Against the bleak techno-authoritarian futures now being sold to us, a radical new vision for global progress in the 21st century feels urgently needed. ...</p><p class="dcr-130mj7b">What would this transition deliver? At its heart is convergence between countries. Average per capita national income, today separated by a 16-fold gap between the poorest (€290 a month in sub-Saharan Africa) and richest (€4,590 in North America/Oceania) regions of the world, would rise towards a common level of about €5,000 a month in all countries by 2100.</p><p class="dcr-130mj7b">But this convergence is not just monetary. Annual working hours per employed person would fall from roughly 2,100 to about 1,000, continuing the long shift towards shorter working time; while the share of global working hours devoted to education and health would rise from 11% to 43%. Women and men would converge on equal pay and on an equal share of economic and domestic labour.</p><p class="dcr-130mj7b">All of this would unfold within a habitable climate. Thanks to sustainable convergence and fast decarbonisation, global heating would reach 1.8C, against more than 4C on current trends.</p><p class="dcr-130mj7b">None of this will be possible without a <a href="https://www.theguardian.com/inequality/2026/may/15/wealth-britain-billionaires-gdp-rich-list-inequality">deep contraction of inequality</a>. The income scale between individuals would narrow to a ratio of one to five and the wealth scale to one to 10, prolonging what western and Nordic Europe achieved over the 20th century. The share of global wealth held by the poorest half of humanity would rise from 2% to 30%, while the share held by the billionaire class would fall from 6% to 0.05%.</p><p class="dcr-130mj7b"/></blockquote><p class="dcr-130mj7b"><br/></p><div id="sign-in-gate"/></div>
    </content>
    <updated>2026-06-04T15:37:18Z</updated>
    <published>2026-06-04T15:37:18Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="Climate Change"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="Politics"/>
    <author>
      <name>Philip Wadler</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/12009347515095774366</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-9757377</id>
      <category term="Politics"/>
      <category term="Programming Languages"/>
      <category term="Functional Programming"/>
      <category term="Computing"/>
      <category term="Scotland"/>
      <category term="Independence"/>
      <category term="Haskell"/>
      <category term="Yes!"/>
      <category term="Academia"/>
      <category term="UK"/>
      <category term="Edinburgh"/>
      <category term="Science"/>
      <category term="Cycling"/>
      <category term="Graphics"/>
      <category term="Types"/>
      <category term="Mathematics"/>
      <category term="US"/>
      <category term="Logic"/>
      <category term="Covid-19"/>
      <category term="Security"/>
      <category term="Web"/>
      <category term="Comics"/>
      <category term="EU"/>
      <category term="Climate Change"/>
      <category term="Israel"/>
      <category term="Theory"/>
      <category term="Blockchain"/>
      <category term="Comedy"/>
      <category term="Education"/>
      <category term="IOHK"/>
      <category term="Writing"/>
      <category term="AI"/>
      <category term="Agda"/>
      <category term="University"/>
      <category term="Cryptocurrency"/>
      <category term="Developers"/>
      <category term="Internet"/>
      <category term="SIGPLAN"/>
      <category term="Scala"/>
      <category term="Status"/>
      <category term="ACM"/>
      <category term="Concurrency"/>
      <category term="DSL"/>
      <category term="Databases"/>
      <category term="Dynamic and Static Typing"/>
      <category term="F#"/>
      <category term="Green"/>
      <category term="JavaScript"/>
      <category term="Lego"/>
      <category term="Privacy"/>
      <category term="Recursion"/>
      <category term="Session Types"/>
      <category term="Strange Loop"/>
      <category term="Category Theory"/>
      <category term="Formal Methods"/>
      <category term="Java"/>
      <category term="Object-Oriented"/>
      <category term="Technology"/>
      <category term="Architecture"/>
      <category term="Copyright"/>
      <category term="Distributed Computing"/>
      <category term="Europe"/>
      <category term="Productivity"/>
      <category term="Racket"/>
      <category term="Science Fiction"/>
      <category term="Theatre"/>
      <category term="BLM"/>
      <category term="Brexit"/>
      <category term="Communication"/>
      <category term="DRM"/>
      <category term="Environment"/>
      <category term="Erlang"/>
      <category term="Finance"/>
      <category term="Gender"/>
      <category term="Palestine"/>
      <category term="BDS"/>
      <category term="Books"/>
      <category term="Cinema"/>
      <category term="Japan"/>
      <category term="Net Neutrality"/>
      <category term="Open Access"/>
      <category term="Pyret"/>
      <category term="Scheme"/>
      <category term="Sweden"/>
      <author>
        <name>Philip Wadler</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/12009347515095774366</uri>
      </author>
      <link href="https://wadler.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="https://www.blogger.com/feeds/9757377/posts/default?alt=atom" rel="self" type="application/atom+xml"/>
      <link href="https://wadler.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="https://www.blogger.com/feeds/9757377/posts/default?alt=atom&amp;start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <title>Wadler's Blog</title>
      <updated>2026-06-04T17:46:04Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://www.well-typed.com/blog/2026/05/faster-haskell-builds</id>
    <link href="https://well-typed.com/blog/2026/05/faster-haskell-builds" rel="alternate" type="text/html"/>
    <title>Faster Cabal Haskell builds by eliminating redundant work</title>
    <summary>TL;DR Build your Haskell projects 10-15% faster with this one simple trick!
(Spoiler: the simple trick is to wait for the next major cabal-install release.)

In previous work (paid for by the Sovereign Tech Fund) we
did a lot of heavy lifting to make a major architectural change to Cabal. That
work is [...]</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p><strong>TL;DR</strong> Build your Haskell projects 10-15% faster with this one simple trick!
(Spoiler: the simple trick is to wait for the next major <code>cabal-install</code> release.)</p>
<p>In <a href="https://well-typed.com/blog/2023/10/sovereign-tech-fund-invests-in-cabal/">previous work</a> (paid for by the Sovereign Tech Fund) we
did a lot of heavy lifting to make a major architectural change to <code>Cabal</code>. That
work is now paying off with practical benefits. This post covers follow-on
architectural improvements to <code>cabal-install</code> which then enable us to eliminate
redundant work in the <code>configure</code> phase, yielding significant reductions in
build times.</p>
<p>The changes will be available to everyone in the next major <code>cabal-install</code>
release. For a large project like <code>pandoc</code> (including all of its dependencies)
we measure a 10% (std.dev. 0.6pp) reduction in wall clock time for a 16-way
parallel build with <code>--semaphore</code>. No user changes are needed to take advantage
of this improvement.</p>

<h3 id="history-cabal-and-cabal-install">History: <code>Cabal</code> and <code>cabal-install</code></h3>
<h4 id="the-genesis-the-cabal-specification">The genesis: the <code>Cabal</code> specification</h4>
<p>First, there was <code>Cabal</code>. Its design was laid out in <a href="https://www.haskell.org/cabal/proposal/pkg-spec.pdf">A Common Architecture for Building Applications
and Tools</a>. Fundamentally, it defines the notion of a package, with
each package being built and installed with the following sequence of commands:</p>
<pre><code>&gt; hc Setup.hs
&gt; ./Setup configure
&gt; ./Setup build
&gt; ./Setup install</code></pre>
<p>Each package must be built in dependency order, with <code>hc-pkg</code> registering each
installed library into a package database.</p>
<h4 id="orchestrating-the-build-of-multiple-packages">Orchestrating the build of multiple packages</h4>
<p><code>cabal-install</code> was then born to plan and execute a build plan consisting of
many packages. With its solver, it determines a build plan, which is then
orchestrated by running the above sequence of commands for each package,
in dependency order.</p>
<p>There is however one architectural mismatch: for the solver to be able to
compute a build plan, it already needs a lot of information about the current
system:</p>
<ul>
<li>What Haskell compiler are we using?</li>
<li>What system libraries are available (<code>pkgconfig-depends</code>)?</li>
<li>What build tools are available (<code>build-tool-depends</code>)?</li>
</ul>
<p>This means that <code>cabal-install</code> already has in its hands most of the information
necessary for configuring a package; in particular it has already resolved all
the conditionals in every package description. We should thus be able to skip
most of the steps in the package’s <code>./Setup configure</code> phase. However,
the command-line interface of <code>./Setup configure</code> makes it practically
impossible to do so: passing a fully resolved dependency graph would require many
additions to the <a href="https://hackage-content.haskell.org/package/Cabal/docs/Distribution-Simple-Setup.html#t:ConfigFlags">already bloated <code>ConfigFlags</code> datatype</a>,
and a lot more data being serialised/deserialised.</p>
<p>Because of this limitation, <code>cabal-install</code>’s approach was to take its hard-won
build plan and convert it into <code>ConfigFlags</code> that specify exact dependency
versions and flag assignments. This amounts to passing <code>./Setup configure</code>
an already fully constrained configuration; the <code>configure</code> step would then
re-probe the system, re-read package databases… only to re-discover exactly
what <code>cabal-install</code> already knew!</p>
<h3 id="a-new-architecture-for-cabal-install">A new architecture for <code>cabal-install</code></h3>
<p>The paradigm shift proposed in <a href="https://well-typed.com/blog/2023/10/sovereign-tech-fund-invests-in-cabal/">our Sovereign Tech Fund proposal</a>
is that <code>cabal-install</code> should be responsible for orchestrating the whole build
process instead of running the conceptually independent build systems provided by
each package. With <code>cabal-install</code> now in control, it can directly call <code>Cabal</code>
library functions, which in turn allows skipping steps in the <code>configure</code> phase
that waste time re-discovering information that <code>cabal-install</code> is already
aware of.</p>
<p>To implement such a change, we first needed to prepare the terrain: when invoking
an external executable such as the <code>Setup</code> executable – say via the
<a href="https://hackage.haskell.org/package/process"><code>process</code> library</a> as <code>Cabal</code> uses – we can set the working
directory, environment variables and redirect input/output handles.
It was not possible to do this directly via the <code>Cabal</code> library, so we first
needed to add <code>Cabal</code> library support for <a href="https://github.com/haskell/cabal/pull/9718">setting the working directory</a>
and for <a href="https://github.com/haskell/cabal/pull/11077">choosing logging handles</a>. Once this was done,
it allowed us to refactor <code>cabal-install</code> to <a href="https://github.com/haskell/cabal/pull/11703">directly call <code>Cabal</code> library functions to build packages</a>.</p>
<h3 id="performance-impact">Performance impact</h3>
<p>This architectural change provides a solid foundation for further improvements.
The two main time sinks in the <code>Cabal</code> <code>configure</code> phase were determined to be
(using a new <a href="https://github.com/haskell/cabal/pull/11769"><code>--build-timings</code> flag to <code>cabal-install</code></a>):</p>
<ol type="1">
<li>(~50% of <code>configure</code> time) Re-configuring the compiler program database.
The compiler and <code>hc-pkg</code> were already pre-configured, but other programs
such as <code>haddock</code>, <code>ar</code>, <code>ld</code> etc were re-configured anew for each package.</li>
<li>(~40% of <code>configure</code> time) Re-probing the installed package database, via <code>hc-pkg dump</code>.</li>
</ol>
<p>We can skip this extra work by <a href="https://github.com/haskell/cabal/pull/11768">pre-configuring the compiler <code>ProgramDb</code></a>
and <a href="https://github.com/haskell/cabal/pull/11767">keeping a running <code>InstalledPackageIndex</code></a>. These
two changes, taken together, reduce the time spent in the <code>configure</code> phase by
over 90%.</p>
<p>While most of the time in builds is unsurprisingly spent… actually compiling
Haskell code [citation needed], the impact on full builds is still rather
significant. For example, when compiling <code>aeson</code> with <code>-j1</code>, we saw a reduction
in total build time of ~16.6% (std.dev. 1.9pp) in our benchmarks.</p>
<p>The fact that the <code>configure</code> phase is inherently serial also means that these
improvements have a notable impact when combined with <a href="https://well-typed.com/blog/2023/08/reducing-haskell-parallel-build-times/">the <code>-jsem</code> feature</a>.
This is because the <code>-jsem</code> feature allows us to assign more capabilities to
the <code>build</code> phase. As per <a href="https://en.wikipedia.org/wiki/Amdahl%27s_law">Amdahl’s law</a>, this results in the
<code>configure</code> phase becoming more of a bottleneck. For example, when compiling
<code>pandoc</code> with <code>cabal install pandoc -j16 --semaphore</code>, we saw a reduction in
total build time of ~10% (std.dev. 0.6pp).</p>
<h3 id="further-improvements">Further improvements</h3>
<p>These improvements provide a small glimpse of what is possible after our changes
to <code>cabal-install</code>’s architecture. A more ambitious long-term goal would be for
<code>cabal-install</code> to manage a “giant build graph” on a finer granularity level
than whole Cabal components. For example, if package <code>q</code> depends only
on module <code>P1</code> from package <code>p</code>, we could imagine starting to compile <code>q</code> after
compiling <code>P1</code> but before we have finished compiling the rest of <code>p</code>. This
would unlock build-time reductions by increasing available parallelism,
and also enable more accurate progress and error reporting.</p>
</div>
    </content>
    <updated>2026-05-28T00:00:00Z</updated>
    <published>2026-05-28T00:00:00Z</published>
    <category term="build-systems"/>
    <category term="cabal"/>
    <category term="community"/>
    <category term="compile-time-performance"/>
    <category term="open-source"/>
    <category term="sovereign-tech-fund"/>
    <author>
      <name>sam</name>
    </author>
    <source>
      <id>https://well-typed.com/blog/</id>
      <logo>https://well-typed.com/img/wtnlogoplain.svg</logo>
      <link href="https://well-typed.com/blog/rss2.xml" rel="self" type="application/rss+xml"/>
      <link href="https://well-typed.com/blog/" rel="alternate" type="text/html"/>
      <subtitle>Because Well-Typed Programs Don't Go Wrong</subtitle>
      <title>Well-Typed Blog</title>
      <updated>2026-05-28T00:00:00Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://theorylunch.wordpress.com/?p=1809</id>
    <link href="https://theorylunch.wordpress.com/2019/10/17/a-remarkable-property-of-real-valued-functions-on-intervals-of-the-real-line/" rel="alternate" type="text/html"/>
    <link href="https://theorylunch.wordpress.com/2019/10/17/a-remarkable-property-of-real-valued-functions-on-intervals-of-the-real-line/#comments" rel="replies" type="text/html"/>
    <link href="https://theorylunch.wordpress.com/2019/10/17/a-remarkable-property-of-real-valued-functions-on-intervals-of-the-real-line/feed/atom/" rel="replies" type="application/atom+xml"/>
    <title xml:lang="en">A Remarkable Property of Real-Valued Functions on Intervals of the Real Line</title>
    <summary type="xhtml" xml:lang="en"><div xmlns="http://www.w3.org/1999/xhtml">Today the 17 October 2019 I discussed a very remarkable fixed point theorem discovered by the Ukrainian mathematician Oleksandr Micholayovych Sharkovsky. We recall that a periodic point of period for a function is a point such that . With this … <a href="https://theorylunch.wordpress.com/2019/10/17/a-remarkable-property-of-real-valued-functions-on-intervals-of-the-real-line/">Continue reading <span class="meta-nav">→</span></a></div>
    </summary>
    <content type="xhtml" xml:lang="en"><div xmlns="http://www.w3.org/1999/xhtml"><p class="wp-block-paragraph">Today the 17 October 2019 I discussed a very remarkable fixed point theorem discovered by the Ukrainian mathematician <a href="https://en.wikipedia.org/wiki/Oleksandr_Mykolayovych_Sharkovsky">Oleksandr Micholayovych Sharkovsky</a>.</p>



<p class="wp-block-paragraph">We recall that a <em>periodic point</em> of <em>period</em> <img alt="n\geq1" class="latex" src="https://s0.wp.com/latex.php?latex=n%5Cgeq1&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> for a function <img alt="f:X\to{X}" class="latex" src="https://s0.wp.com/latex.php?latex=f%3AX%5Cto%7BX%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> is a point <img alt="x_n" class="latex" src="https://s0.wp.com/latex.php?latex=x_n&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> such that <img alt="f^n(x_n)=x_n" class="latex" src="https://s0.wp.com/latex.php?latex=f%5En%28x_n%29%3Dx_n&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>. With this definition, a periodic point of period <img alt="n" class="latex" src="https://s0.wp.com/latex.php?latex=n&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> is also periodic of period <img alt="m" class="latex" src="https://s0.wp.com/latex.php?latex=m&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> for every <img alt="m" class="latex" src="https://s0.wp.com/latex.php?latex=m&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> which is a multiple of <img alt="n" class="latex" src="https://s0.wp.com/latex.php?latex=n&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>. If <img alt="f^n(x_n)=x_n" class="latex" src="https://s0.wp.com/latex.php?latex=f%5En%28x_n%29%3Dx_n&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> but <img alt="f^k(x_n)\neq{x_n}" class="latex" src="https://s0.wp.com/latex.php?latex=f%5Ek%28x_n%29%5Cneq%7Bx_n%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> for every <img alt="k" class="latex" src="https://s0.wp.com/latex.php?latex=k&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> from 1 to <img alt="n-1" class="latex" src="https://s0.wp.com/latex.php?latex=n-1&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>, we say that <img alt="n" class="latex" src="https://s0.wp.com/latex.php?latex=n&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> is the <em>least period</em> of <img alt="x_n" class="latex" src="https://s0.wp.com/latex.php?latex=x_n&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>.</p>



<p class="wp-block-paragraph"><strong>Theorem 1. (Sharkovsky’s “little” theorem)</strong> <em>Let <img alt="I\subseteq\mathbb{R}" class="latex" src="https://s0.wp.com/latex.php?latex=I%5Csubseteq%5Cmathbb%7BR%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> be an interval and <img alt="f:I\to\mathbb{R}" class="latex" src="https://s0.wp.com/latex.php?latex=f%3AI%5Cto%5Cmathbb%7BR%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> a continuous function. If <img alt="f" class="latex" src="https://s0.wp.com/latex.php?latex=f&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> has a point of least period 3, then it has points of arbitrary least period; in particular, it has a fixed point.</em></p>



<span id="more-1809"/>



<p class="wp-block-paragraph">Note that no hypothesis is made on <img alt="I" class="latex" src="https://s0.wp.com/latex.php?latex=I&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> being open or closed, bounded or unbounded.</p>



<p class="wp-block-paragraph">Our proof of Sharkovsky’s “little” theorem follows the one given in (Sternberg, 2010), and could even be given in a Calculus 1 course: the most advanced result will be the intermediate value theorem.</p>



<p class="wp-block-paragraph"><strong>Lemma 1.</strong> <em>Let <img alt="I=[a,b]" class="latex" src="https://s0.wp.com/latex.php?latex=I%3D%5Ba%2Cb%5D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> be a compact interval of the real line and <img alt="f:I\to\mathbb{R}" class="latex" src="https://s0.wp.com/latex.php?latex=f%3AI%5Cto%5Cmathbb%7BR%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> a continuous function. Suppose that for some compact interval <img alt="J" class="latex" src="https://s0.wp.com/latex.php?latex=J&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> it is <img alt="I\subseteq{J}\subseteq{f(I)}" class="latex" src="https://s0.wp.com/latex.php?latex=I%5Csubseteq%7BJ%7D%5Csubseteq%7Bf%28I%29%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>. Then <img alt="f" class="latex" src="https://s0.wp.com/latex.php?latex=f&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> has a fixed point in <img alt="J" class="latex" src="https://s0.wp.com/latex.php?latex=J&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>.</em></p>



<p class="wp-block-paragraph"><em>Proof.</em> Let <img alt="m" class="latex" src="https://s0.wp.com/latex.php?latex=m&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> and <img alt="M" class="latex" src="https://s0.wp.com/latex.php?latex=M&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> be the minimum and the maximum of <img alt="f" class="latex" src="https://s0.wp.com/latex.php?latex=f&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> in <img alt="I" class="latex" src="https://s0.wp.com/latex.php?latex=I&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>, respectively. As <img alt="I\subseteq{f(I)}" class="latex" src="https://s0.wp.com/latex.php?latex=I%5Csubseteq%7Bf%28I%29%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>, it is <img alt="m\leq{a}" class="latex" src="https://s0.wp.com/latex.php?latex=m%5Cleq%7Ba%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> and <img alt="M\geq{b}" class="latex" src="https://s0.wp.com/latex.php?latex=M%5Cgeq%7Bb%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>. Choose <img alt="u,v\in{I}" class="latex" src="https://s0.wp.com/latex.php?latex=u%2Cv%5Cin%7BI%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> such that <img alt="f(u)=m" class="latex" src="https://s0.wp.com/latex.php?latex=f%28u%29%3Dm&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> and <img alt="f(v)=M" class="latex" src="https://s0.wp.com/latex.php?latex=f%28v%29%3DM&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>. Then <img alt="g(x)=f(x)-x" class="latex" src="https://s0.wp.com/latex.php?latex=g%28x%29%3Df%28x%29-x&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> is nonpositive at <img alt="x=u" class="latex" src="https://s0.wp.com/latex.php?latex=x%3Du&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> and nonnegative at <img alt="x=v" class="latex" src="https://s0.wp.com/latex.php?latex=x%3Dv&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>. By the intermediate value theorem applied to <img alt="g" class="latex" src="https://s0.wp.com/latex.php?latex=g&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>, <img alt="f" class="latex" src="https://s0.wp.com/latex.php?latex=f&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> must have a fixed point in the closed and bounded interval (possibly reduced to a single point) delimited by <img alt="u" class="latex" src="https://s0.wp.com/latex.php?latex=u&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> and <img alt="v" class="latex" src="https://s0.wp.com/latex.php?latex=v&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>, which is a subset of <img alt="J" class="latex" src="https://s0.wp.com/latex.php?latex=J&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>. <img alt="\Box" class="latex" src="https://s0.wp.com/latex.php?latex=%5CBox&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/></p>



<p class="wp-block-paragraph"><strong>Lemma 2.</strong> <em>In the hypotheses of Lemma 1, let <img alt="K" class="latex" src="https://s0.wp.com/latex.php?latex=K&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> be a closed and bounded interval contained in <img alt="f(I)" class="latex" src="https://s0.wp.com/latex.php?latex=f%28I%29&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>. Then there exists a closed and bounded subinterval <img alt="J" class="latex" src="https://s0.wp.com/latex.php?latex=J&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> of <img alt="I" class="latex" src="https://s0.wp.com/latex.php?latex=I&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> such that <img alt="f(J)=K" class="latex" src="https://s0.wp.com/latex.php?latex=f%28J%29%3DK&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>.</em></p>



<p class="wp-block-paragraph">Proof. Let <img alt="K=[c,d]" class="latex" src="https://s0.wp.com/latex.php?latex=K%3D%5Bc%2Cd%5D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>. We may suppose <img alt="c&lt;d" class="latex" src="https://s0.wp.com/latex.php?latex=c%3Cd&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>, otherwise the statement is trivial. Let <img alt="u\in{I}" class="latex" src="https://s0.wp.com/latex.php?latex=u%5Cin%7BI%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> be the largest such that <img alt="f(u)=c" class="latex" src="https://s0.wp.com/latex.php?latex=f%28u%29%3Dc&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>. Two cases are possible.</p>



<ol class="wp-block-list">
<li>There exists <img alt="x\in(u,b]" class="latex" src="https://s0.wp.com/latex.php?latex=x%5Cin%28u%2Cb%5D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> such that <img alt="f(x)=d" class="latex" src="https://s0.wp.com/latex.php?latex=f%28x%29%3Dd&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>. Let <img alt="v" class="latex" src="https://s0.wp.com/latex.php?latex=v&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> be the <em>smallest</em> such <img alt="x" class="latex" src="https://s0.wp.com/latex.php?latex=x&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>, and let <img alt="J=[u,v]" class="latex" src="https://s0.wp.com/latex.php?latex=J%3D%5Bu%2Cv%5D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>. Then surely <img alt="f(J)\supset{K}" class="latex" src="https://s0.wp.com/latex.php?latex=f%28J%29%5Csupset%7BK%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>, but if for some <img alt="x\in(u,v)" class="latex" src="https://s0.wp.com/latex.php?latex=x%5Cin%28u%2Cv%29&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> we had either <img alt="f(x)&lt;c" class="latex" src="https://s0.wp.com/latex.php?latex=f%28x%29%3Cc&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> or <img alt="f(x)&gt;d" class="latex" src="https://s0.wp.com/latex.php?latex=f%28x%29%3Ed&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>, then by the intermediate value theorem, for some <img alt="y\in(u,v)" class="latex" src="https://s0.wp.com/latex.php?latex=y%5Cin%28u%2Cv%29&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>Â we would also have either <img alt="f(y)=c" class="latex" src="https://s0.wp.com/latex.php?latex=f%28y%29%3Dc&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> or <img alt="f(y)=d" class="latex" src="https://s0.wp.com/latex.php?latex=f%28y%29%3Dd&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>, against our choice of <img alt="u" class="latex" src="https://s0.wp.com/latex.php?latex=u&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> and <img alt="v" class="latex" src="https://s0.wp.com/latex.php?latex=v&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>.</li>



<li><img alt="f(x)&lt;d" class="latex" src="https://s0.wp.com/latex.php?latex=f%28x%29%3Cd&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> for every <img alt="x\in(u,b]" class="latex" src="https://s0.wp.com/latex.php?latex=x%5Cin%28u%2Cb%5D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>. Let then <img alt="w" class="latex" src="https://s0.wp.com/latex.php?latex=w&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> be the largest <img alt="x\in[a,u]" class="latex" src="https://s0.wp.com/latex.php?latex=x%5Cin%5Ba%2Cu%5D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> such that <img alt="f(x)=d" class="latex" src="https://s0.wp.com/latex.php?latex=f%28x%29%3Dd&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>, and let <img alt="J=[w,u]" class="latex" src="https://s0.wp.com/latex.php?latex=J%3D%5Bw%2Cu%5D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>. Then <img alt="f(J)=K" class="latex" src="https://s0.wp.com/latex.php?latex=f%28J%29%3DK&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> for reasons similar to those of the previous point.</li>
</ol>



<p class="has-text-align-right wp-block-paragraph"><img alt="\Box" class="latex" src="https://s0.wp.com/latex.php?latex=%5CBox&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/></p>



<p class="has-text-align-left wp-block-paragraph"><em>Proof of Sharkovsky’s “little” theorem.</em> Let <img alt="a,b,c,\in\mathbb{R}" class="latex" src="https://s0.wp.com/latex.php?latex=a%2Cb%2Cc%2C%5Cin%5Cmathbb%7BR%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> be such that <img alt="f(a)=b" class="latex" src="https://s0.wp.com/latex.php?latex=f%28a%29%3Db&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>, <img alt="f(b)=c" class="latex" src="https://s0.wp.com/latex.php?latex=f%28b%29%3Dc&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>, and <img alt="f(c)=a" class="latex" src="https://s0.wp.com/latex.php?latex=f%28c%29%3Da&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>. Up to cycling between these three values and replacing <img alt="f(x)" class="latex" src="https://s0.wp.com/latex.php?latex=f%28x%29&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> with <img alt="-f(-x)" class="latex" src="https://s0.wp.com/latex.php?latex=-f%28-x%29&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>, we may suppose <img alt="a&lt;b&lt;c" class="latex" src="https://s0.wp.com/latex.php?latex=a%3Cb%3Cc&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>. Fix a positive integer <img alt="n" class="latex" src="https://s0.wp.com/latex.php?latex=n&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>: we will prove that there exists <img alt="x_{n}\in{I}" class="latex" src="https://s0.wp.com/latex.php?latex=x_%7Bn%7D%5Cin%7BI%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> such that <img alt="f^n(x_{n})=x" class="latex" src="https://s0.wp.com/latex.php?latex=f%5En%28x_%7Bn%7D%29%3Dx&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> and <img alt="f^i(x_{n})\neq{x_{n}}" class="latex" src="https://s0.wp.com/latex.php?latex=f%5Ei%28x_%7Bn%7D%29%5Cneq%7Bx_%7Bn%7D%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> for every <img alt="i&lt;n" class="latex" src="https://s0.wp.com/latex.php?latex=i%3Cn&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>.</p>



<p class="wp-block-paragraph">Let <img alt="L=[a,b]" class="latex" src="https://s0.wp.com/latex.php?latex=L%3D%5Ba%2Cb%5D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> and <img alt="R=[b,c]" class="latex" src="https://s0.wp.com/latex.php?latex=R%3D%5Bb%2Cc%5D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> be the “left” and “right” side of the closed and bounded interval <img alt="[a,c]" class="latex" src="https://s0.wp.com/latex.php?latex=%5Ba%2Cc%5D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>: then <img alt="R\subseteq{f(L)}" class="latex" src="https://s0.wp.com/latex.php?latex=R%5Csubseteq%7Bf%28L%29%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> and <img alt="L\cup{R}\subseteq{f(R)}" class="latex" src="https://s0.wp.com/latex.php?latex=L%5Ccup%7BR%7D%5Csubseteq%7Bf%28R%29%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> by the intermediate value theorem. In particular, <img alt="R\subseteq{f(R)}" class="latex" src="https://s0.wp.com/latex.php?latex=R%5Csubseteq%7Bf%28R%29%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>, and Lemma 1 immediately tells us that <img alt="f" class="latex" src="https://s0.wp.com/latex.php?latex=f&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> has a fixed point <img alt="x_{1}" class="latex" src="https://s0.wp.com/latex.php?latex=x_%7B1%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> in <img alt="R" class="latex" src="https://s0.wp.com/latex.php?latex=R&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>. Also, <img alt="L\subseteq{f(R)}\subseteq{f^2(L)}" class="latex" src="https://s0.wp.com/latex.php?latex=L%5Csubseteq%7Bf%28R%29%7D%5Csubseteq%7Bf%5E2%28L%29%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>, so <img alt="f" class="latex" src="https://s0.wp.com/latex.php?latex=f&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> also has a point of period 2 in <img alt="L" class="latex" src="https://s0.wp.com/latex.php?latex=L&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>, again by Lemma 1: call it <img alt="x_{2}" class="latex" src="https://s0.wp.com/latex.php?latex=x_%7B2%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>. This point <img alt="x_{2}" class="latex" src="https://s0.wp.com/latex.php?latex=x_%7B2%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> cannot be a fixed point, because then it would also belong to <img alt="R" class="latex" src="https://s0.wp.com/latex.php?latex=R&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> as <img alt="L\subseteq{f(R)}" class="latex" src="https://s0.wp.com/latex.php?latex=L%5Csubseteq%7Bf%28R%29%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>, but <img alt="L\cap{R}=\{b\}" class="latex" src="https://s0.wp.com/latex.php?latex=L%5Ccap%7BR%7D%3D%5C%7Bb%5C%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> which has period 3. As we can obviously take <img alt="x_{3}=b" class="latex" src="https://s0.wp.com/latex.php?latex=x_%7B3%7D%3Db&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>, we only need to consider the case <img alt="n\geq4" class="latex" src="https://s0.wp.com/latex.php?latex=n%5Cgeq4&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>.</p>



<p class="wp-block-paragraph">By Lemma 2, there exists a closed and bounded subinterval <img alt="A_1" class="latex" src="https://s0.wp.com/latex.php?latex=A_1&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> of <img alt="R" class="latex" src="https://s0.wp.com/latex.php?latex=R&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> such that <img alt="f(A_1)=R" class="latex" src="https://s0.wp.com/latex.php?latex=f%28A_1%29%3DR&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>. In turn, as <img alt="A_1\subseteq{R}" class="latex" src="https://s0.wp.com/latex.php?latex=A_1%5Csubseteq%7BR%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>, there also exists a closed and bounded subinterval <img alt="A_2" class="latex" src="https://s0.wp.com/latex.php?latex=A_2&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> of <img alt="A_1" class="latex" src="https://s0.wp.com/latex.php?latex=A_1&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> such that <img alt="f(A_2)=A_1" class="latex" src="https://s0.wp.com/latex.php?latex=f%28A_2%29%3DA_1&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>, again by Lemma 2: but then, <img alt="f^2(A_2)=f(A_1)=R" class="latex" src="https://s0.wp.com/latex.php?latex=f%5E2%28A_2%29%3Df%28A_1%29%3DR&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>. By iterating the procedure, we find a sequence of closed and bounded intervals <img alt="A_i" class="latex" src="https://s0.wp.com/latex.php?latex=A_i&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> such that, for every <img alt="i\geq1" class="latex" src="https://s0.wp.com/latex.php?latex=i%5Cgeq1&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>, <img alt="A_{i+1}\subseteq{A_i}" class="latex" src="https://s0.wp.com/latex.php?latex=A_%7Bi%2B1%7D%5Csubseteq%7BA_i%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> and <img alt="f^i(A_i)=R" class="latex" src="https://s0.wp.com/latex.php?latex=f%5Ei%28A_i%29%3DR&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>.</p>



<p class="wp-block-paragraph">We stop at <img alt="i=n-2" class="latex" src="https://s0.wp.com/latex.php?latex=i%3Dn-2&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> and recall that <img alt="R\subseteq{f(L)}" class="latex" src="https://s0.wp.com/latex.php?latex=R%5Csubseteq%7Bf%28L%29%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>: we are still in the situation of Lemma 2, with <img alt="A_{n-2}" class="latex" src="https://s0.wp.com/latex.php?latex=A_%7Bn-2%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> in the role of <img alt="K" class="latex" src="https://s0.wp.com/latex.php?latex=K&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>. So we choose <img alt="A_{n-1}" class="latex" src="https://s0.wp.com/latex.php?latex=A_%7Bn-1%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> as a closed and bounded subinterval not of <img alt="A_{n-2}" class="latex" src="https://s0.wp.com/latex.php?latex=A_%7Bn-2%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>, but of <img alt="L" class="latex" src="https://s0.wp.com/latex.php?latex=L&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>, such that <img alt="f(A_{n-1})=A_{n-2}" class="latex" src="https://s0.wp.com/latex.php?latex=f%28A_%7Bn-1%7D%29%3DA_%7Bn-2%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>. In turn, as <img alt="L\subseteq{f(R)}" class="latex" src="https://s0.wp.com/latex.php?latex=L%5Csubseteq%7Bf%28R%29%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>, there exists a closed and bounded subinterval <img alt="A_n" class="latex" src="https://s0.wp.com/latex.php?latex=A_n&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> of <img alt="R" class="latex" src="https://s0.wp.com/latex.php?latex=R&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> such that <img alt="f(A_n)=A_{n-1}" class="latex" src="https://s0.wp.com/latex.php?latex=f%28A_n%29%3DA_%7Bn-1%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>. Following the chain of inclusions we obtain <img alt="f^n(A_n)=R" class="latex" src="https://s0.wp.com/latex.php?latex=f%5En%28A_n%29%3DR&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>. By Lemma 1, <img alt="f^n" class="latex" src="https://s0.wp.com/latex.php?latex=f%5En&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> has a fixed point <img alt="x_n" class="latex" src="https://s0.wp.com/latex.php?latex=x_n&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> in <img alt="A_n" class="latex" src="https://s0.wp.com/latex.php?latex=A_n&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>, which is a periodic point of period <img alt="n" class="latex" src="https://s0.wp.com/latex.php?latex=n&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> for <img alt="f" class="latex" src="https://s0.wp.com/latex.php?latex=f&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>.</p>



<p class="wp-block-paragraph">Can the least period of <img alt="x_n" class="latex" src="https://s0.wp.com/latex.php?latex=x_n&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> for <img alt="f" class="latex" src="https://s0.wp.com/latex.php?latex=f&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> be smaller than <img alt="n" class="latex" src="https://s0.wp.com/latex.php?latex=n&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>? No, it cannot, for the following reason. If <img alt="x_{n}" class="latex" src="https://s0.wp.com/latex.php?latex=x_%7Bn%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> has least period <img alt="m\leq{n}" class="latex" src="https://s0.wp.com/latex.php?latex=m%5Cleq%7Bn%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>, then so has <img alt="y=f(x_{n})" class="latex" src="https://s0.wp.com/latex.php?latex=y%3Df%28x_%7Bn%7D%29&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>, and in addition <img alt="n" class="latex" src="https://s0.wp.com/latex.php?latex=n&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> is divisible by <img alt="m" class="latex" src="https://s0.wp.com/latex.php?latex=m&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>. But <img alt="f(x_n)\in{L}" class="latex" src="https://s0.wp.com/latex.php?latex=f%28x_n%29%5Cin%7BL%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> while <img alt="f^i(x_n)\in{R}" class="latex" src="https://s0.wp.com/latex.php?latex=f%5Ei%28x_n%29%5Cin%7BR%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> for every <img alt="i\in[2:n]" class="latex" src="https://s0.wp.com/latex.php?latex=i%5Cin%5B2%3An%5D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>. Consequently, if <img alt="x_{n}" class="latex" src="https://s0.wp.com/latex.php?latex=x_%7Bn%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> has least period <img alt="m&lt;n" class="latex" src="https://s0.wp.com/latex.php?latex=m%3Cn&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>, then <img alt="y\in{L}\cap{R}=\{b\}" class="latex" src="https://s0.wp.com/latex.php?latex=y%5Cin%7BL%7D%5Ccap%7BR%7D%3D%5C%7Bb%5C%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>. But this is impossible, because <img alt="f^{2}(y)=f^{3}(x_{n})\in{R}" class="latex" src="https://s0.wp.com/latex.php?latex=f%5E%7B2%7D%28y%29%3Df%5E%7B3%7D%28x_%7Bn%7D%29%5Cin%7BR%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> by construction as <img alt="n\geq4" class="latex" src="https://s0.wp.com/latex.php?latex=n%5Cgeq4&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>, while <img alt="f^{2}(b)=a\not\in{R}" class="latex" src="https://s0.wp.com/latex.php?latex=f%5E%7B2%7D%28b%29%3Da%5Cnot%5Cin%7BR%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>. <img alt="\Box" class="latex" src="https://s0.wp.com/latex.php?latex=%5CBox&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/></p>



<p class="wp-block-paragraph">Theorem 1 is a special case of a much more general, and complex, result also due to Sharkovsky. Before stating it, we need to define a special ordering on positive integers.</p>



<p class="wp-block-paragraph"><strong>Definition.</strong> The <em>Sharkovsky ordering</em> <img alt="\rhd" class="latex" src="https://s0.wp.com/latex.php?latex=%5Crhd&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> between positive integers is defined as follows:</p>



<ul class="wp-block-list">
<li>Identify the number <img alt="n=2^k\cdot{m}" class="latex" src="https://s0.wp.com/latex.php?latex=n%3D2%5Ek%5Ccdot%7Bm%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>, with <img alt="m" class="latex" src="https://s0.wp.com/latex.php?latex=m&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> odd integer, with the pair <img alt="(k,m)" class="latex" src="https://s0.wp.com/latex.php?latex=%28k%2Cm%29&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>.</li>



<li>Sort the pairs with <img alt="m&gt;1" class="latex" src="https://s0.wp.com/latex.php?latex=m%3E1&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> in lexicographic order.<br/><br/>That is: first, list all the odd numbers larger than 1, in increasing order; then, all the doubles of the odd numbers larger than 1, in increasing order; then, all the quadruples of the odd numbers larger than 1, in increasing order; and so on.<br/><br/>For example, <img alt="17\rhd243" class="latex" src="https://s0.wp.com/latex.php?latex=17%5Crhd243&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> and <img alt="4095\rhd6" class="latex" src="https://s0.wp.com/latex.php?latex=4095%5Crhd6&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/></li>



<li>Set <img alt="(k,m)\rhd(h,1)" class="latex" src="https://s0.wp.com/latex.php?latex=%28k%2Cm%29%5Crhd%28h%2C1%29&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> for every <img alt="m&gt;1" class="latex" src="https://s0.wp.com/latex.php?latex=m%3E1&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> and <img alt="k,h\geq0" class="latex" src="https://s0.wp.com/latex.php?latex=k%2Ch%5Cgeq0&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>.<br/><br/>That is: the powers of 2 follow, in the Sharkovskii ordering, any number which has an odd factor.<br/><br/>For example, <img alt="17000000000000\rhd2" class="latex" src="https://s0.wp.com/latex.php?latex=17000000000000%5Crhd2&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>.</li>



<li>Sort the pairs of the form <img alt="(k,1)" class="latex" src="https://s0.wp.com/latex.php?latex=%28k%2C1%29&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>—i.e., the powers of 2—in reverse order.</li>
</ul>



<p class="wp-block-paragraph">The set of positive integer with the Sharkowsky ordering has then the form:</p>



<p class="has-text-align-center wp-block-paragraph"><img alt="3\rhd5\rhd7\rhd\ldots\rhd6\rhd10\rhd14\rhd\ldots\rhd12\rhd20\rhd28\rhd\ldots\rhd8\rhd4\rhd2\rhd1" class="latex" src="https://s0.wp.com/latex.php?latex=3%5Crhd5%5Crhd7%5Crhd%5Cldots%5Crhd6%5Crhd10%5Crhd14%5Crhd%5Cldots%5Crhd12%5Crhd20%5Crhd28%5Crhd%5Cldots%5Crhd8%5Crhd4%5Crhd2%5Crhd1&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/></p>



<p class="wp-block-paragraph">Note that <img alt="\rhd" class="latex" src="https://s0.wp.com/latex.php?latex=%5Crhd&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> is a total ordering.</p>



<p class="wp-block-paragraph"><strong>Theorem 2. (Sharkovsky’s “great” theorem)</strong> <em>Let <img alt="I" class="latex" src="https://s0.wp.com/latex.php?latex=I&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> be an interval on the real line and let <img alt="f:\mathbb{R}\to\mathbb{R}" class="latex" src="https://s0.wp.com/latex.php?latex=f%3A%5Cmathbb%7BR%7D%5Cto%5Cmathbb%7BR%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> be a continuous function.</em></p>



<ol class="wp-block-list">
<li><em>If <img alt="f" class="latex" src="https://s0.wp.com/latex.php?latex=f&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> has a point of least period <img alt="m" class="latex" src="https://s0.wp.com/latex.php?latex=m&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>, and <img alt="m\rhd{n}" class="latex" src="https://s0.wp.com/latex.php?latex=m%5Crhd%7Bn%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>, then <img alt="f" class="latex" src="https://s0.wp.com/latex.php?latex=f&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> has a point of least period <img alt="n" class="latex" src="https://s0.wp.com/latex.php?latex=n&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>. In particular, if <img alt="f" class="latex" src="https://s0.wp.com/latex.php?latex=f&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> has a periodic point, then it has a fixed point.</em></li>



<li><em>For every <img alt="m\geq1" class="latex" src="https://s0.wp.com/latex.php?latex=m%5Cgeq1&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> integer it is possible to choose <img alt="I" class="latex" src="https://s0.wp.com/latex.php?latex=I&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> and <img alt="f" class="latex" src="https://s0.wp.com/latex.php?latex=f&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> so that <img alt="f" class="latex" src="https://s0.wp.com/latex.php?latex=f&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> has a point of minimum period <img alt="m" class="latex" src="https://s0.wp.com/latex.php?latex=m&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> and no points of minimum period <img alt="k" class="latex" src="https://s0.wp.com/latex.php?latex=k&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/> for any <img alt="k\rhd{m}" class="latex" src="https://s0.wp.com/latex.php?latex=k%5Crhd%7Bm%7D&amp;bg=ffffff&amp;fg=333333&amp;s=0&amp;c=20201002"/>. In particular, there are functions whose only periodic points are fixed.</em></li>
</ol>



<p class="wp-block-paragraph">Bibliography:</p>



<ul class="wp-block-list">
<li>Keith Burns and Boris Hasselblatt. The Sharkovsky theorem: A natural direct proof. <em>The American Mathematical Monthly</em> <strong>118(3)</strong> (2011), 229–244. <a href="https://doi.org/10.4169%2Famer.math.monthly.118.03.229">doi:10.4169/amer.math.monthly.118.03.229</a></li>



<li>Robert L. Devaney, <em>An Introduction to Chaotic Dynamical Systems</em>, Second Edition, Westview Press 2003.</li>



<li>Shlomo Sternberg, <em>Dynamical Systems</em>, Dover 2010.</li>
</ul>



<p class="wp-block-paragraph"/></div>
    </content>
    <updated>2026-05-22T15:51:36Z</updated>
    <published>2019-10-17T13:41:09Z</published>
    <category scheme="https://theorylunch.wordpress.com" term="Uncategorized"/>
    <author>
      <name>Silvio Capobianco</name>
      <uri>http://anotherblogonca.wordpress.com</uri>
    </author>
    <source>
      <id>http://theorylunch.wordpress.com/feed/atom/</id>
      <link href="https://theorylunch.wordpress.com" rel="alternate" type="text/html"/>
      <link href="https://theorylunch.wordpress.com/feed/atom/" rel="self" type="application/atom+xml"/>
      <link href="https://theorylunch.wordpress.com/osd.xml" rel="search" title="Theory Lunch" type="application/opensearchdescription+xml"/>
      <link href="https://s1.wp.com/opensearch.xml" rel="search" title="WordPress.com" type="application/opensearchdescription+xml"/>
      <link href="https://theorylunch.wordpress.com/?pushpress=hub" rel="hub" type="text/html"/>
      <subtitle xml:lang="en">Institute of Cybernetics, Tallinn</subtitle>
      <title xml:lang="en">Theory Lunch</title>
      <updated>2026-05-22T15:51:36Z</updated>
    </source>
  </entry>

  <entry xml:lang="en-us">
    <id>Buzzsprout-19202127</id>
    <link href="https://www.buzzsprout.com/1817535/episodes/19202127-82-fraser-tweedale.mp3" length="34957725" rel="enclosure" type="audio/mpeg"/>
    <title>82: Fraser Tweedale</title>
    <summary>We talked to Fraser Tweedale. Fraser works at Red Hat, and is on the Haskell Security Response Team. We talked about security in the context of Haskell, both technical and organizational issues, and also the political issues involved. Fraser's work is both really important and not well-known in the Haskell ecosystem, so it was high time for him to come on the show.</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>We talked to Fraser Tweedale. Fraser works at Red Hat, and is on the Haskell Security Response Team. We talked about security in the context of Haskell, both technical and organizational issues, and also the political issues involved. Fraser's work is both really important and not well-known in the Haskell ecosystem, so it was high time for him to come on the show.</p></div>
    </content>
    <updated>2026-05-19T12:00:00Z</updated>
    <published>2026-05-19T12:00:00Z</published>
    <author>
      <name>Haskell Podcast</name>
    </author>
    <source>
      <id>https://haskell.foundation/podcast/</id>
      <logo>https://storage.buzzsprout.com/tnk1ztokn5vmeiufqmr4kkp37mw2?.jpg</logo>
      <category scheme="http://www.itunes.com/" term="Technology"/>
      <author>
        <name>Haskell Podcast</name>
      </author>
      <link href="https://rss.buzzsprout.com/1817535.rss" rel="self" type="application/rss+xml"/>
      <link href="https://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="https://haskell.foundation/podcast/" rel="alternate" type="text/html"/>
      <rights>Â© 2026 The Haskell Interlude</rights>
      <subtitle>This is the Haskell Interlude, where the five co-hosts (Wouter Swierstra, Andres LÃ¶h, Alejandro Serrano, Niki Vazou, and Joachim Breitner) chat with Haskell guests!</subtitle>
      <title>The Haskell Interlude</title>
      <updated>2026-05-19T12:36:05Z</updated>
    </source>
  </entry>

  <entry xml:lang="en-us">
    <id>https://haskellforall.com/2026/05/type-out-the-code</id>
    <link href="https://haskellforall.com/2026/05/type-out-the-code" rel="alternate" type="text/html"/>
    <title>Type out the code</title>
    <summary>Freecoding improves broader programming proficiency</summary>
    <updated>2026-05-19T00:00:00Z</updated>
    <published>2026-05-19T00:00:00Z</published>
    <source>
      <id>https://haskellforall.com</id>
      <author>
        <name>Gabriella Gonzalez</name>
      </author>
      <link href="https://haskellforall.com" rel="alternate" type="text/html"/>
      <link href="https://haskellforall.com/rss.xml" rel="self" type="application/rss+xml"/>
      <subtitle>A blog about Haskell and functional programming.</subtitle>
      <title>Haskell for all</title>
      <updated>2026-06-07T13:45:09Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://www.randomhacks.net/2026/05/17/redoubtful-agent-sandbox-progress/</id>
    <link href="http://www.randomhacks.net/2026/05/17/redoubtful-agent-sandbox-progress/" rel="alternate" type="text/html"/>
    <title>Redoubtful: Linux agent sandbox progress</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>I’ve also been experimenting with agent sandboxes lately. <a href="https://github.com/emk/redoubtful"><code class="language-plaintext highlighter-rouge">redoubtful</code></a> is a work-in-progress sandbox that supports:</p>

<ul>
  <li>
<strong>Linux-only sandboxes:</strong> I’m focusing on what Linux supports, specifically, rather than trying to support the lowest-common-denominator features that work cross platform.</li>
  <li>
<strong>Modular configuration profiles:</strong> See below.</li>
  <li>Isolation using <code class="language-plaintext highlighter-rouge">pasta</code> and <code class="language-plaintext highlighter-rouge">bwrap</code>.</li>
  <li>A shadow filesystem that <em>looks</em> like your home directory, so things like <code class="language-plaintext highlighter-rouge">git worktree</code> actually work correctly. You can also selectively mount existing parts of your filesystem in read-only or read-write mode.</li>
  <li>Network port forwarding and filtering proxy server.</li>
  <li>
<strong>TODO:</strong> Proxy credential support.</li>
</ul>

<p>But first, a warning: Nearly 100% of this code was written by coding agents, much of it by a local Qwen3.6 27B. I am, however, keeping a <em>very</em> close eye on the output—one of my goals here is to see just what a small agent like this can do. This is maybe only 80% as good as my handwritten code would be a similar point in a project.</p>

<p>And finally, <strong>this is an incomplete work-in-progress</strong>, and it has not been packaged nicely for anyone besides me yet.</p>

<h3 id="modular-configuration-profiles">Modular configuration “profiles”</h3>

<p>One of the <em>slightly</em> novel parts of all this is the ability to define modular configuration. This allows us to invoke a sandbox with a specific set of credentials:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>redoubtful run <span class="nt">--uses</span> pi <span class="nt">--uses</span> llama-server pi
</code></pre></div></div>

<p>Here, we’re running the <a href="https://pi.dev/">pi.dev</a> coding agent with a locally-served Qwen3.6 27B via <code class="language-plaintext highlighter-rouge">llama-server</code>. Qwen3.6 27B is a fantastic lightweight coding model, and it works very well with pi.dev’s minimalist prompt. And since we’re running in a sandbox, we don’t care that pi.dev provides no sandbox and no confirmation before acting.</p>

<p>To set up these two profiles, we first define a <code class="language-plaintext highlighter-rouge">node</code> profile:</p>

<div class="language-toml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Standard Node setup. If you're using `nvm`, you'll need to fix the path_add</span>
<span class="c"># entry to point to the correct nvm version.</span>
<span class="c">#</span>
<span class="c"># We might want some kind of plugin system to handle messy things like nvm.</span>
<span class="nn">[profile.node]</span>
<span class="py">mounts</span> <span class="p">=</span> <span class="p">[</span>
    <span class="err">{</span> <span class="py">host</span> <span class="p">=</span> <span class="s">"~/.npm-global"</span> <span class="err">}</span><span class="p">,</span>
    <span class="err">{</span> <span class="py">host</span> <span class="p">=</span> <span class="s">"~/.local/share/nvm"</span><span class="p">,</span> <span class="py">access</span> <span class="p">=</span> <span class="s">"rw"</span> <span class="err">}</span><span class="p">,</span>
<span class="p">]</span>
<span class="py">path_add</span> <span class="p">=</span> <span class="p">[</span><span class="s">"~/.npm-global/bin"</span><span class="p">,</span> <span class="s">"~/.local/share/nvm/v24.15.0/bin"</span><span class="p">]</span>
</code></pre></div></div>

<p>Then let’s make Rust work:</p>

<div class="language-toml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># A Rust setup, with optional rustup and advisory support.</span>
<span class="nn">[profile.rust]</span>
<span class="py">mounts</span> <span class="p">=</span> <span class="p">[</span>
    <span class="err">{</span> <span class="py">host</span> <span class="p">=</span> <span class="s">"~/.rustup"</span> <span class="err">}</span><span class="p">,</span>
    <span class="err">{</span> <span class="py">host</span> <span class="p">=</span> <span class="s">"~/.cargo"</span> <span class="err">}</span><span class="p">,</span>
    <span class="c"># Cargo audit/deny support, which needs to take a lock to update the</span>
    <span class="c"># advisory database.</span>
    <span class="err">{</span> <span class="py">host</span> <span class="p">=</span> <span class="s">"~/.cargo/advisory-dbs/"</span><span class="p">,</span> <span class="py">access</span> <span class="p">=</span> <span class="s">"rw"</span> <span class="err">}</span><span class="p">,</span>
<span class="p">]</span>
<span class="py">path_add</span> <span class="p">=</span> <span class="nn">["~/.cargo/bin"]</span>
</code></pre></div></div>

<p>And then basic <code class="language-plaintext highlighter-rouge">git</code> is easy—we just need enough config to read <code class="language-plaintext highlighter-rouge">user.name</code> and <code class="language-plaintext highlighter-rouge">user.email</code>:</p>

<div class="language-toml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Things you will likely want for git.</span>
<span class="nn">[profile.git]</span>
<span class="py">mounts</span> <span class="p">=</span> <span class="p">[</span><span class="err">{</span> <span class="py">host</span> <span class="p">=</span> <span class="s">"~/.gitconfig"</span> <span class="err">}</span><span class="p">]</span>
</code></pre></div></div>

<p>And then finally, we can set up <code class="language-plaintext highlighter-rouge">pi</code> itself:</p>

<div class="language-toml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Profile for the pi coding agent. Run with:</span>
<span class="c">#</span>
<span class="c">#     redoubtful run -u pi pi</span>
<span class="nn">[profile.pi]</span>
<span class="py">uses</span> <span class="p">=</span> <span class="p">[</span><span class="s">"node"</span><span class="p">,</span> <span class="s">"rust"</span><span class="p">,</span> <span class="s">"git"</span><span class="p">]</span>
<span class="py">mounts</span> <span class="p">=</span> <span class="p">[</span><span class="err">{</span> <span class="py">host</span> <span class="p">=</span> <span class="s">"~/.pi"</span><span class="p">,</span> <span class="py">access</span> <span class="p">=</span> <span class="s">"rw"</span> <span class="err">}</span><span class="p">]</span>
</code></pre></div></div>

<div class="language-toml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Pass through llama-server connections.</span>
<span class="nn">[profile.llama-server]</span>
<span class="py">forwards</span> <span class="p">=</span> <span class="p">[</span><span class="err">{</span> <span class="py">host_port</span> <span class="p">=</span> <span class="mi">8080</span> <span class="err">}</span><span class="p">]</span>
<span class="py">proxies</span> <span class="p">=</span> <span class="p">[</span><span class="err">{</span> <span class="py">host</span> <span class="p">=</span> <span class="s">"127.0.0.1"</span> <span class="err">}</span><span class="p">]</span>
</code></pre></div></div>

<h3 id="whats-left">What’s left?</h3>

<p>The biggest missing piece is teaching the proxy server how to inject real credentials into network connections. This isn’t a new idea. The goal is to provide access to things like GitHub without giving an agent actual credentials.</p>

<p>After that, it’s just packaging everything up nicely and writing some docs, so that other people (or agents) can easily configure it for different purposes.</p></div>
    </summary>
    <updated>2026-05-17T18:50:36Z</updated>
    <published>2026-05-17T18:50:36Z</published>
    <source>
      <id>http://www.randomhacks.net/</id>
      <author>
        <name>Eric Kidd</name>
      </author>
      <link href="http://www.randomhacks.net/" rel="alternate" type="text/html"/>
      <link href="http://www.randomhacks.net/feed.xml" rel="self" type="application/rss+xml"/>
      <subtitle>Random code snippets, projects and musings about software from Eric Kidd, a developer and occasional entrepreneur.</subtitle>
      <title>Random Hacks</title>
      <updated>2026-05-17T19:00:52Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://www.randomhacks.net/2026/05/16/lab-notebook-edit-completion-1/</id>
    <link href="http://www.randomhacks.net/2026/05/16/lab-notebook-edit-completion-1/" rel="alternate" type="text/html"/>
    <title>Lab notebook: Edit completion #1</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>I <a href="https://www.randomhacks.net/2026/05/13/edit-completion-with-qwen36/">continue to be interested</a> in late-2024-era edit completion, the “Fill in the Middle” (FIM) models. You know, what Copilot used to do, back before it started generating “mini diffs.” Why?</p>

<ul>
  <li>I like and use agentic workflows. But as many people are realizing, <a href="https://blog.k10s.dev/im-going-back-to-writing-code-by-hand/">it’s <em>super</em> easy to lose track of what’s happening in your code, with terrible consequences</a>. So I want to reinvest in human-in-the-loop tools, too. (And slightly weaker agentic models, but more on that later.)</li>
  <li>The new-school edit completion offered by Copilot and <a href="https://zed.dev/blog/zeta2">Zed’s Zeta2</a> actually slows me down. It overlays diffs on my buffer, which is visually disorienting at speed. And it proposes edits further from the current cursor, which take me longer to mentally process. Personally, the new style feels like hunt-and-peck. The older style felt like <em>really fast</em> touch typing.</li>
</ul>

<p>Mind you, I’m a very specific sort of user. I want to know how my code works. I want my code to be clean. And I can read a half-page code completion in moments, thanks to way too many years of reading PRs.</p>

<h3 id="initial-experiments">Initial experiments</h3>

<p>All experiments performed in Zed, which does less post-processing of the raw model output than some tools. All evaluations are purely subjective.</p>

<p><strong>New-school models (generating diffs).</strong> Zeta2 is honestly pretty underwhelming right now. The completions are very generic. And Zeta2 seems to be bad about taking the context into account. It will complete a function, sure. But I’d swap Zeta2 for late 2024 Copilot in a heartbeat.</p>

<p><strong>Old-school models (FIM, inserting at cursor).</strong> Let’s go down the list so far:</p>

<ul>
  <li>
<code class="language-plaintext highlighter-rouge">ggml-org/Qwen2.5-Coder-7B-Q8_0-GGUF:Q8_0</code>: The classic, default choice. This isn’t <em>terrible</em>, and it gives more context-aware completions than Zeta2. But it’s generations old, and I want to know if anything is new and shiny.</li>
  <li>
<code class="language-plaintext highlighter-rouge">mradermacher/Seed-Coder-8B-Base-i1-GGUF:Q6_K</code>. This is the raw base that went into Zeta2, I think? It doesn’t seem to be useful in Zed, because the inserted text feels pretty raw. This might work better in a smarter harness. But I’m dropping it for now.</li>
  <li>
<code class="language-plaintext highlighter-rouge">JetBrains/Mellum-4b-base-gguf:Q8_0</code>. Downloaded, but not yet tested.</li>
  <li>
<code class="language-plaintext highlighter-rouge">unsloth/Qwen3.6-35B-A3B-GGUF:IQ4_XS</code>. This is <a href="https://www.randomhacks.net/2026/05/13/edit-completion-with-qwen36/">unexpectedly good</a>! Worth further experimentation.</li>
</ul>

<h2 id="refining-qwen36-35b-a3b-changing-order-from-psm-to-spm">Refining Qwen3.6 35B A3B: Changing order from PSM to SPM</h2>

<p>Qwen typically uses FIM, “Fill in the Middle” completion. This uses 3 magic tokens:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cd">/// Qwen FIM prefix marker.</span>
<span class="k">const</span> <span class="n">PRE</span><span class="p">:</span> <span class="o">&amp;</span><span class="nb">str</span> <span class="o">=</span> <span class="s">"&lt;|fim_prefix|&gt;"</span><span class="p">;</span>
<span class="cd">/// Qwen FIM suffix marker.</span>
<span class="k">const</span> <span class="n">SUF</span><span class="p">:</span> <span class="o">&amp;</span><span class="nb">str</span> <span class="o">=</span> <span class="s">"&lt;|fim_suffix|&gt;"</span><span class="p">;</span>
<span class="cd">/// Qwen FIM middle marker (model generates after this).</span>
<span class="k">const</span> <span class="n">MID</span><span class="p">:</span> <span class="o">&amp;</span><span class="nb">str</span> <span class="o">=</span> <span class="s">"&lt;|fim_middle|&gt;"</span><span class="p">;</span>
</code></pre></div></div>

<p>We have two possible flavors. The original is “PSM” compeletion, “prefix, suffix, middle”:</p>

<pre><code class="language-txt">{PRE}{prefix}{SUF}{suffix}{MID}
</code></pre>

<p>But since the prefix grows with each keystroke, we can’t cache the entire message. We could get much better caching with “SPM” order:</p>

<pre><code class="language-txt">{SUF}{suffix}{PRE}{prefix}{MID}
</code></pre>

<p>Here, we can cache everything up to the final {MID} character, and resume generation with a longer prefix. Whooo, speed!</p>

<p>But Zed doesn’t support SPM completion, only PSM. So I fired up a copy of Claude Code (as one does), and asked, “Hey, write me a Rust proxy server (using my standard conventions) that intercepts <code class="language-plaintext highlighter-rouge">/completion</code>, and translates PSM to SPM please.”</p>

<p><strong>Results:</strong> Extremely disappointing. SPM format confuses Qwen3.6 35B A3B pretty badly. But then I thought, “Hey, even if we’re running in <code class="language-plaintext highlighter-rouge">/completion</code> mode, this is still an instruction-tuned model. Can we prompt it?” One unscientific tweak later:</p>

<pre><code class="language-txt">You are a code-completion tool. You receive input in
fim_suffix+fim_prefix+fim_middle order, and your job
is to generate what the user would be likely to type
next. When in doubt, keep it short. Think of this like
generating a diff in agentic coding mode. You're trying
to insert the right text to make a working program that
does what the user wants. If there's no obvious next
step, generate nothing.

{SUF}{suffix}{PRE}{prefix}{MID}
</code></pre>

<p>This is <em>still</em> pretty bad, but it’s better. You can tell it’s <em>trying</em> to be an SPM autocompleter, though it’s still the worst of the bunch.</p>

<p><strong>Possible next steps:</strong></p>

<ol>
  <li>What if we modify the proxy to transform <code class="language-plaintext highlighter-rouge">/completion</code> into a <code class="language-plaintext highlighter-rouge">/chat/completions</code> request, with a real prompt, real text inputs, and tool for <code class="language-plaintext highlighter-rouge">insert_at_cursor(text)</code>? Can we access more of the model’s intelligence?</li>
  <li>Qwen3.6 35B A3B is small enough to fine-tune! We could look up file completion data sets, and try to create a LoRA adapter. We could even use something like <a href="https://tree-sitter.github.io/tree-sitter/">tree-sitter</a> to generate custom completion examples. Would that give us something useful?</li>
</ol>

<p>I also notice that FIM-style models are <em>notoriously</em> bad at choosing a good stopping place. This can be fixed with a lot of regexes. But what if our fine-tuning data took care to demonstrate <em>good</em> stopping places?</p></div>
    </summary>
    <updated>2026-05-16T15:49:55Z</updated>
    <published>2026-05-16T15:49:55Z</published>
    <source>
      <id>http://www.randomhacks.net/</id>
      <author>
        <name>Eric Kidd</name>
      </author>
      <link href="http://www.randomhacks.net/" rel="alternate" type="text/html"/>
      <link href="http://www.randomhacks.net/feed.xml" rel="self" type="application/rss+xml"/>
      <subtitle>Random code snippets, projects and musings about software from Eric Kidd, a developer and occasional entrepreneur.</subtitle>
      <title>Random Hacks</title>
      <updated>2026-05-17T19:00:51Z</updated>
    </source>
  </entry>

  <entry>
    <id>https://wickstrom.tech/2026-05-16-coding-on-paper.html</id>
    <link href="https://wickstrom.tech/2026-05-16-coding-on-paper.html" rel="alternate" type="text/html"/>
    <title>Coding on Paper</title>
    <summary>About three months ago, I bought the Onyx BOOX 25.3” Mira Pro Color, an
e-ink monitor for desktop use. I’ve used it as my primary monitor since,
and I’ve had a lot of questions about it. This is my experience report,
from the perspective of a working, still mostly typing, programmer.</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>About three months ago, I bought the <a href="https://shop.boox.com/products/boox-mira-procolor-version">Onyx BOOX 25.3” Mira Pro Color</a>, an e-ink monitor for desktop use. I’ve used it as my primary monitor since, and I’ve had a lot of questions about it. This is my experience report, from the perspective of a working, still mostly typing, programmer.</p> <p>This is <em>not</em> a sponsored post, and it is <em>not</em> a product review. I wrote a very similar post about the <a href="https://wickstrom.tech/2025-10-10-programming-in-the-sun-a-year-with-the-daylight-computer.html">Daylight DC-1</a> last year.</p> <figure> <img alt="Neovim in the morning sunlight." src="https://wickstrom.tech/assets/mira-pro-1.webp"/> <figcaption>Neovim in the morning sunlight.</figcaption> </figure> <p>As explained in last year’s post, the reason I persist with these monitors is because it makes me energetic and happy. Sunlight, direct or indirect, helps me stay clear and focused during my workday. I find spaces illuminated by natural light beautiful and inspiring.</p> <p>I’m not going to recommend that you buy one of these devices. They’re expensive, about $2000, and the experience is quite different from LCD. Even if this looks cool, it seems to me very possible that most people would not like it in practice. With that said, I am happy with it, and I’ll probably keep investing in these tools as they get even better with time.</p> <figure> <img alt="Spending a workday in the garden." src="https://wickstrom.tech/assets/mira-pro-2.webp"/> <figcaption>Spending a workday in the garden.</figcaption> </figure> <p>Using the Mira Pro as a primary monitor is a continuation of the experiments with my e-ink tablets and Termux as coding environments. But now, with far fewer compromises. I’m running my regular NixOS environment on my work laptop. No SSH and tmux needed, no Android terminal emulator to customize.</p> <p>What I have done, though, is spent quite some time on making my system more suited for this monitor. The Mira Pro does not work well with dark themes. In fact, it only works well with high contrast light themes.</p> <p>Luckily, I’m bent towards minimalism, so I already used near-monochrome themes, relying more on typographic syntax highlighting rather than coloring. I now have custom themes for Neovim, Zed, and Ghostty with a few vivid colors for things like selection, comments, and constants. Otherwise it’s largely black on white.</p> <p>It’s trickier with other applications. In Firefox, I’ve started using the high contrast setting. That works pretty much like an inverse of DarkReader. I now run Spotify in the browser in order to avoid its dark theme.</p> <p>The monitor has a clunky menu system with which you can change rendering modes; things like contrast and speed. I found <a href="https://github.com/ipodnerd3019/mira-js">an open-source reverse-engineered NodeJS package</a> that I use with Hyprland keybindings to easily change rendering modes and manually refresh. No need for the built-in menu.</p> <p>In practice I use two modes:</p> <dl> <dt>Reading:</dt> <dd> <p>This mode renders colors most vividly and text sharply, but typing with it is agony. I use it when reading text documents, web pages, or code diffs.</p> </dd> <dt>Writing:</dt> <dd> <p>This is by far the most commonly used mode, which compromises colors and sharpness for way better latency. I use this for everything in the terminal, chat, general web browsing, and probably most other things not covered by the reading mode.</p> </dd> </dl> <p>See the following photos for a close-up comparison:</p> <figure> <img alt="Reading mode, where colored regions are pretty smooth and text looks sharp." src="https://wickstrom.tech/assets/mira-pro-5.webp"/> <figcaption>Reading mode, where colored regions are pretty smooth and text looks sharp.</figcaption> </figure> <figure> <img alt="Writing mode, where colored regions (light gray, red, green) are grainy and text is a bit blurry." src="https://wickstrom.tech/assets/mira-pro-6.webp"/> <figcaption>Writing mode, where colored regions (light gray, red, green) are grainy and text is a bit blurry.</figcaption> </figure> <p>What about latency? Here’s the two short clips of me typing with the reading and writing modes:</p> <figure> <video controls="" src="https://wickstrom.tech/assets/mira-pro-slow.mp4"><a href="https://wickstrom.tech/assets/mira-pro-slow.mp4">Reading mode, with horrible latency for typing.</a></video> <figcaption>Reading mode, with horrible latency for typing.</figcaption> </figure> <figure> <video controls="" src="https://wickstrom.tech/assets/mira-pro-fast.mp4"><a href="https://wickstrom.tech/assets/mira-pro-fast.mp4">Writing mode, with some but acceptable latency.</a></video> <figcaption>Writing mode, with some but acceptable latency.</figcaption> </figure> <p>Ghosting? In my writing mode it’s minimal. It really doesn’t bother me.</p> <p>About the color panel: I don’t like it very much to be honest. It was the only version of the Mira Pro available from the Swedish retailer at the time, so I went with it. I think I would’ve been happier with a monochrome panel, because the coloring technology makes it considerably darker.</p> <p>Here’s a comparison between the Palma 2 Pro (using a similar but smaller Kaleido color panel) and my old Tab Ultra (with a monochrome panel):</p> <figure> <img alt="Color vs Monochrome e-ink panels without backlight." src="https://wickstrom.tech/assets/mira-pro-7.webp"/> <figcaption>Color vs Monochrome e-ink panels without backlight.</figcaption> </figure> <p>Unless the room has great diffuse lighting, natural or otherwise, the color panel does require <em>some</em> backlight. In direct sunlight or outdoors it works without. I might spend more time optimizing the lighting in my office to make this work during the winter months.</p> <p>So, what’s to make of it? Personally, I enjoy using this monitor a lot, even if it’s not perfect. Should you buy an expensive 25” e-ink monitor? I cannot say. But if you do, let me know how it works out.</p> <p>My custom themes and keybindings can be found <a href="https://github.com/owickstrom/nixos/tree/master">here</a>.</p></div>
    </content>
    <updated>2026-05-15T22:00:00Z</updated>
    <published>2026-05-15T22:00:00Z</published>
    <source>
      <id>https://wickstrom.tech/</id>
      <author>
        <name>Oskar Wickström</name>
      </author>
      <link href="https://wickstrom.tech/feed.xml" rel="self" type="application/atom+xml"/>
      <link href="https://wickstrom.tech/" rel="alternate" type="text/html"/>
      <subtitle>Software design, testing, functional programming, and other delightful things.</subtitle>
      <title>Oskar WickstrÃ¶m</title>
      <updated>2026-05-17T06:31:58Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://www.randomhacks.net/2026/05/13/i-should-blog-more/</id>
    <link href="http://www.randomhacks.net/2026/05/13/i-should-blog-more/" rel="alternate" type="text/html"/>
    <title>I should blog more</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>This blog is ancient, in blog years. The first post was on June 30, 1998, and it featured a <a href="https://www.randomhacks.net/1998/06/30/randomhacks-online-mathmap/">randomized emboss for MathMap</a>. Back in those days, it was a mix of neat little snippets like that and interesting links. The site was a single, hand-edited HTML file in reverse chronological order. It ran on a Linux mini-tower built from parts from <a href="https://w1mx.mit.edu/flea-at-mit/">the MIT Swapfest</a>, and it lived under my desk.</p>

<p>Google hadn’t been incoporated yet. The Internet bubble was still inflating.</p>

<p>Over the years, the tech stack changed: for a while, this site used SGML-based rendering via a custom script (or was it XML?), then it was a nice interactive Typo site with comments, and then eventually it migrated to the current Jekyll architecture. Which seems to be about 12 years old. I’m pretty proud to have kept nearly all the inbound links working for decades now.</p>

<p>Around 2007 or so, I did a fun series of high effort posts about <a href="https://www.randomhacks.net/probability-monads/">probability monads</a>. But high-effort posts are a trap. Soon I started feeling like <em>every</em> post ought to be high effort. And then I wrote less and less.</p>

<p>But blogs are a bit of a retro endeavour these days. RSS readers still exist, but I imagine nearly all my subscribers have disappeared since the heady days of 2007. And apparently it’s trendy to <a href="https://notes.andymatuschak.org/Work_with_the_garage_door_up">work with the garage door up</a>.</p>

<p>So maybe it’s time to get back this site’s roots. I don’t have any <a href="https://www.complang.tuwien.ac.at/schani/mathmap/dist/">MathMap</a> snippets for you today, sadly, because the last release seems to have been in 2004. <a href="http://www.randomhacks.net/2026/05/13/edit-completion-with-qwen36/">But here’s a cool trick!</a></p></div>
    </summary>
    <updated>2026-05-13T05:04:52Z</updated>
    <published>2026-05-13T05:04:52Z</published>
    <source>
      <id>http://www.randomhacks.net/</id>
      <author>
        <name>Eric Kidd</name>
      </author>
      <link href="http://www.randomhacks.net/" rel="alternate" type="text/html"/>
      <link href="http://www.randomhacks.net/feed.xml" rel="self" type="application/rss+xml"/>
      <subtitle>Random code snippets, projects and musings about software from Eric Kidd, a developer and occasional entrepreneur.</subtitle>
      <title>Random Hacks</title>
      <updated>2026-05-17T19:00:52Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://www.randomhacks.net/2026/05/13/edit-completion-with-qwen36/</id>
    <link href="http://www.randomhacks.net/2026/05/13/edit-completion-with-qwen36/" rel="alternate" type="text/html"/>
    <title>Edit completion works with Qwen3.6 35B A3B!</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Do you miss the old-style Copilot completions? The ones where it inserted grey text at the cursor? There’s an open version of this called <a href="https://api-docs.deepseek.com/guides/fim_completion">“FIM completion”</a>. And the classic model for doing this is <a href="https://huggingface.co/Qwen/Qwen2.5-Coder-7B">Qwen2.5 Coder 7B</a>.</p>

<p>But it turns out that Qwen3.6 35B A3B is can also do autocompletion! The fact that it has 3B active parameters means that it’s fast. And the 35B total parameters means it’s smarter than the smaller models.</p>

<p>So let’s fire it up using <a href="https://github.com/ggml-org/llama.cpp"><code class="language-plaintext highlighter-rouge">llama-server</code></a>:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>llama-server <span class="nt">-hf</span> unsloth/Qwen3.6-35B-A3B-GGUF:UD-IQ4_XS <span class="se">\</span>
    <span class="nt">--cache-type-k</span> q8_0 <span class="nt">--cache-type-v</span> q8_0 <span class="nt">--no-mmproj</span> <span class="se">\</span>
    <span class="nt">--ctx-size</span> 4000
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">--no-mmproj</code> says to disable the vision mode. <code class="language-plaintext highlighter-rouge">--cache-type-k q8_0 --cache-type-v q8_0</code> reduces the cache precision, since we’re not really using the cache. You might also need to <a href="https://huggingface.co/unsloth/Qwen3.6-35B-A3B-GGUF">grab a smaller quant</a>, depending on your available VRAM.</p>

<p>Then, we can configure it using <a href="https://zed.dev/">Zed</a>:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"edit_predictions"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"provider"</span><span class="p">:</span><span class="w"> </span><span class="s2">"open_ai_compatible_api"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"open_ai_compatible_api"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"api_url"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://localhost:8080/v1/completions"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"model"</span><span class="p">:</span><span class="w"> </span><span class="s2">"unsloth/Qwen3.6-35B-A3B-GGUF:IQ4_XS"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"prompt_format"</span><span class="p">:</span><span class="w"> </span><span class="s2">"qwen"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"max_output_tokens"</span><span class="p">:</span><span class="w"> </span><span class="mi">256</span><span class="p">,</span><span class="w">
    </span><span class="p">},</span><span class="w">
  </span><span class="p">},</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>So how good is this? Well, the completions aren’t too bad at all, but Zed doesn’t seem to do much post-processing. So the completions to be too long. At lot of this could likely be improved with a proxy that did some pre- and post-processing, and maybe a bit of fine tuning.</p>

<p>But this is an actual, working, 100% local autocomplete. And it’s <em>close</em> to being actually good.</p></div>
    </summary>
    <updated>2026-05-13T05:04:52Z</updated>
    <published>2026-05-13T05:04:52Z</published>
    <source>
      <id>http://www.randomhacks.net/</id>
      <author>
        <name>Eric Kidd</name>
      </author>
      <link href="http://www.randomhacks.net/" rel="alternate" type="text/html"/>
      <link href="http://www.randomhacks.net/feed.xml" rel="self" type="application/rss+xml"/>
      <subtitle>Random code snippets, projects and musings about software from Eric Kidd, a developer and occasional entrepreneur.</subtitle>
      <title>Random Hacks</title>
      <updated>2026-05-17T19:00:52Z</updated>
    </source>
  </entry>

  <entry>
    <id>https://wickstrom.tech/2026-05-13-catching-typos-website-browser-testing.html</id>
    <link href="https://wickstrom.tech/2026-05-13-catching-typos-website-browser-testing.html" rel="alternate" type="text/html"/>
    <title>Catching Typos on My Website with Browser Testing</title>
    <summary>One neat thing about Bombadil’s specification language is that it’s
plain TypeScript, with access to external NPM packages. I’ve written a
specification that spell-checks my website — what you’re reading now —
and I want to share how that turned out.</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>One neat thing about <a href="https://antithesishq.github.io/bombadil/3-specification-language.html#specification-language">Bombadil’s specification language</a> is that it’s plain TypeScript, with access to external NPM packages. I’ve written a specification that spell-checks my website — what you’re reading now — and I want to share how that turned out.</p> <dl> <dt>The inner loop (spell-checking):</dt> <dd> <p>Bombadil randomly walks the website and collects misspelled words as property violations. The specification uses <a href="https://github.com/wooorm/nspell">nspell</a> with <a href="https://github.com/wooorm/dictionaries/tree/main/dictionaries/en">American and British English dictionaries</a> and a personal word list in the repository. This is <em>fast</em> and <em>strict</em>.</p> </dd> <dt>The outer loop (triage):</dt> <dd> <p>I’m running Claude Code with a spell-checking skill, a triage loop that goes something like this:</p> <ol type="1"> <li>Run Bombadil against the local development server for 5 minutes and capture the output. If no words flagged, we’re done.</li> <li>Collect each flagged word and the URL it appeared on.</li> <li>Triage each word into one of these buckets: <ul> <li>Real typo: fix the markdown source</li> <li>Legitimate common word: add to the custom dictionary</li> <li>Legitimate uncommon or very technical word: mark inline with <code>spellcheck="false"</code></li> <li>Extraction noise: add a unit test and fix the word extractor</li> </ul></li> <li>Run Bombadil against each failing URL to confirm the corrections.</li> <li>Go to step 1.</li> </ol> <p>This is <em>slow</em> and <em>loose</em>.</p> </dd> </dl> <p>The hybrid model seems to work well; it has flagged words in almost every blog post. It has fixed 13 real typos and added 130+ words to my personal dictionary. <span>Example typos include “forseeable”, “similiar”, “perculiar”, “occured”. Some of these were 10 years old.</span></p> <p>Claude doesn’t have to waste tokens spell-checking everything over and over. Right now I’m just running this locally, but you could imagine a more elaborate setup for large websites where the “inner loop” runs as a nightly job, invoking the “outer loop” only on violations. You could involve a human where needed, and build up a domain-specific dictionary over time.</p> <p>Note that using an LLM is entirely optional. It just saves me some time. You can do triage on your own.</p> <p>Why not spell-check the sources directly? Yes, that is often preferable, and I use <code>spell</code> in Neovim all the time. But it’s not always practical. At least in my experience, the tooling trips up on syntax and templating in more complicated setups. Maybe your editor handles this better than mine does, or maybe you’re fine with tools like <a href="https://crates.io/crates/typos-cli">typos</a> and <a href="https://github.com/codespell-project/codespell">codespell</a>, but I like the fact that this approach is external and checks the rendered output. Given that Bombadil interacts with web applications, you could even run this against dynamic applications to spell-check states deep in the UI.</p> <p>Speaking of source-level checking: since the custom dictionary is a plain word list, I point Neovim’s <code>spellfile</code> at it and use <code>zg</code> to add words while I edit. A single source of truth that both tools write to.</p> <div class="sourceCode" id="cb1"><pre class="sourceCode lua"><code class="sourceCode lua"><span id="cb1-1"><a href="https://wickstrom.tech/feed.xml#cb1-1" tabindex="-1"/><span class="va">vim</span><span class="op">.</span><span class="va">opt</span><span class="op">.</span><span class="va">spellfile</span> <span class="op">=</span> <span class="st">"/path/to/custom.utf-8.add"</span></span> <span id="cb1-2"><a href="https://wickstrom.tech/feed.xml#cb1-2" tabindex="-1"/><span class="va">vim</span><span class="op">.</span><span class="va">opt</span><span class="op">.</span><span class="va">spelllang</span> <span class="op">=</span> <span class="st">"en"</span></span></code></pre></div> <p>Being able to use NPM packages in specifications has turned out to be more useful than I expected. In addition to <code>nspell</code>, I’m using <a href="https://www.npmjs.com/package/tlds">tlds</a> to identify URLs. Bombadil is built for property-based testing of web applications, but with a specification language and package ecosystem at hand, its uses might be broader than my original vision.</p> <p>If you’re interested in setting up something like this on your own, you’ll find the sources in <a href="https://github.com/owickstrom/bombadil-playground/tree/master/wickstrom.tech">my Bombadil playground</a>.</p> <p><em>Disclosure: I’m the original author and lead for the Bombadil project at Antithesis.</em></p></div>
    </content>
    <updated>2026-05-12T22:00:00Z</updated>
    <published>2026-05-12T22:00:00Z</published>
    <source>
      <id>https://wickstrom.tech/</id>
      <author>
        <name>Oskar Wickström</name>
      </author>
      <link href="https://wickstrom.tech/feed.xml" rel="self" type="application/atom+xml"/>
      <link href="https://wickstrom.tech/" rel="alternate" type="text/html"/>
      <subtitle>Software design, testing, functional programming, and other delightful things.</subtitle>
      <title>Oskar WickstrÃ¶m</title>
      <updated>2026-05-17T06:31:58Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-9757377.post-7295609420169562477</id>
    <link href="https://wadler.blogspot.com/feeds/7295609420169562477/comments/default" rel="replies" title="Post Comments" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment/fullpage/post/9757377/7295609420169562477" rel="replies" title="0 Comments" type="text/html"/>
    <link href="https://www.blogger.com/feeds/9757377/posts/default/7295609420169562477" rel="edit" type="application/atom+xml"/>
    <link href="https://www.blogger.com/feeds/9757377/posts/default/7295609420169562477" rel="self" type="application/atom+xml"/>
    <link href="https://wadler.blogspot.com/2026/05/blog-post.html" rel="alternate" title="Smaller, cheaper Plutus scripts with the UPLC command-line tool" type="text/html"/>
    <title>Smaller, cheaper Plutus scripts with the UPLC command-line tool</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><div class="separator"><p style="margin-left: 1em; margin-right: 1em;"><img alt="Banner image for the UPLC command-line tool blog" class="w-full rounded" height="640" src="https://www.iog.io/_next/image?url=https%3A%2F%2Fcdn.sanity.io%2Fimages%2F5ro2r81m%2Fproduction%2Fa2713d2eceed00bfa5905369eadfa2c523448de3-1920x1080.png%3Frect%3D1%2C0%2C1919%2C1080%26w%3D1100%26h%3D619%26q%3D85%26auto%3Dformat%26dpr%3D2&amp;w=3840&amp;q=75&amp;dpl=dpl_5wNiLzYcYf1HthbamjgNrqYw2dG3" style="color: rgba(0, 0, 0, 0);" width="640"/></p></div><p>If you want to see a use of Agda in real life, to provide certificates validating the correctness of compiler passes, check out this <a href="https://www.iog.io/news/uplc-command-line-tool">blog post</a> from my colleague Ziyang Liu at Input Output. A simplified description of one of the passes appears in <a href="https://dl.acm.org/doi/10.1145/3759427.3760383">A Tale of Two Zippers,</a> by myself, Jacco Krijnen, and Ramsay Taylor.</p></div>
    </content>
    <updated>2026-05-12T13:19:24Z</updated>
    <published>2026-05-12T13:19:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="Agda"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="Blockchain"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="IOHK"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="Programming Languages"/>
    <author>
      <name>Philip Wadler</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/12009347515095774366</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-9757377</id>
      <category term="Politics"/>
      <category term="Programming Languages"/>
      <category term="Functional Programming"/>
      <category term="Computing"/>
      <category term="Scotland"/>
      <category term="Independence"/>
      <category term="Haskell"/>
      <category term="Yes!"/>
      <category term="Academia"/>
      <category term="UK"/>
      <category term="Edinburgh"/>
      <category term="Science"/>
      <category term="Cycling"/>
      <category term="Graphics"/>
      <category term="Types"/>
      <category term="Mathematics"/>
      <category term="US"/>
      <category term="Logic"/>
      <category term="Covid-19"/>
      <category term="Security"/>
      <category term="Web"/>
      <category term="Comics"/>
      <category term="EU"/>
      <category term="Climate Change"/>
      <category term="Israel"/>
      <category term="Theory"/>
      <category term="Blockchain"/>
      <category term="Comedy"/>
      <category term="Education"/>
      <category term="IOHK"/>
      <category term="Writing"/>
      <category term="AI"/>
      <category term="Agda"/>
      <category term="University"/>
      <category term="Cryptocurrency"/>
      <category term="Developers"/>
      <category term="Internet"/>
      <category term="SIGPLAN"/>
      <category term="Scala"/>
      <category term="Status"/>
      <category term="ACM"/>
      <category term="Concurrency"/>
      <category term="DSL"/>
      <category term="Databases"/>
      <category term="Dynamic and Static Typing"/>
      <category term="F#"/>
      <category term="Green"/>
      <category term="JavaScript"/>
      <category term="Lego"/>
      <category term="Privacy"/>
      <category term="Recursion"/>
      <category term="Session Types"/>
      <category term="Strange Loop"/>
      <category term="Category Theory"/>
      <category term="Formal Methods"/>
      <category term="Java"/>
      <category term="Object-Oriented"/>
      <category term="Technology"/>
      <category term="Architecture"/>
      <category term="Copyright"/>
      <category term="Distributed Computing"/>
      <category term="Europe"/>
      <category term="Productivity"/>
      <category term="Racket"/>
      <category term="Science Fiction"/>
      <category term="Theatre"/>
      <category term="BLM"/>
      <category term="Brexit"/>
      <category term="Communication"/>
      <category term="DRM"/>
      <category term="Environment"/>
      <category term="Erlang"/>
      <category term="Finance"/>
      <category term="Gender"/>
      <category term="Palestine"/>
      <category term="BDS"/>
      <category term="Books"/>
      <category term="Cinema"/>
      <category term="Japan"/>
      <category term="Net Neutrality"/>
      <category term="Open Access"/>
      <category term="Pyret"/>
      <category term="Scheme"/>
      <category term="Sweden"/>
      <author>
        <name>Philip Wadler</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/12009347515095774366</uri>
      </author>
      <link href="https://wadler.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="https://www.blogger.com/feeds/9757377/posts/default?alt=atom" rel="self" type="application/atom+xml"/>
      <link href="https://wadler.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="https://www.blogger.com/feeds/9757377/posts/default?alt=atom&amp;start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <title>Wadler's Blog</title>
      <updated>2026-06-04T17:46:04Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://www.well-typed.com/blog/2026/05/lay-annotation-land</id>
    <link href="https://well-typed.com/blog/2026/05/lay-annotation-land" rel="alternate" type="text/html"/>
    <title>Exception Annotations: Lay of the Land</title>
    <summary>Exception annotations were introduced in GHC 9.10, and can be an invaluable tool
for debugging thorny problems. The initial implementation had some important
limitations that made them less useful in practice than one might hope, but
fortunately the situation has since been much improved. In this blog [...]</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Exception annotations were introduced in GHC 9.10, and can be an invaluable tool
for debugging thorny problems. The initial implementation had some important
limitations that made them less useful in practice than one might hope, but
fortunately the situation has since been much improved. In this blog post we
will give a detailed overview of the status quo as of GHC 9.12/9.14, identify
some gotchas you should be aware and provide advise on how to deal with them,
and briefly look ahead to what will change in GHC 10.0. We will also dedicate a
section to discussing the problems in GHC 9.10, for those who cannot yet
upgrade.</p>

<p>Although we will recap all necessary definitions, this blog is <em>not</em> meant to be
an introduction to exception annotations; if you have never used them before,
you might first want to watch <a href="https://www.youtube.com/watch?v=SwOkh9N41Y8&amp;list=PLD8gywOEY4HaG5VSrKVnHxCptlJv2GAn7&amp;index=30">The Haskell Unfolder Episode 29: exceptions,
annotations and backtraces</a>.</p>
<h2 id="backtraces">Backtraces</h2>
<p>Before we look at the general framework for exception annotations, let’s first
briefly recap the concept of <em>backtraces</em>, which is GHC’s answer to stack
traces in other languages. The situation is more complicated in Haskell due
laziness, and there are actually four different kinds of backtraces:</p>
<ul>
<li>based on <code>HasCallStack</code> annotations</li>
<li>based on cost-centres (which will require compiling your program with
profiling enabled)</li>
<li>based on <a href="https://well-typed.com/blog/2021/01/first-look-at-hi-profiling-mode/">IPE info</a></li>
<li>based on <a href="https://well-typed.com/blog/2020/04/dwarf-1/">DWARF info</a></li>
</ul>
<p>In this blog post we will use the first two only, but for the purposes of our
main discussion here the choice actually does not matter much; see GHC
proposal
<a href="https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0330-exception-backtraces.rst">Decorate exceptions with backtrace information</a>
for details. If you’re interested in IPE backtraces specifically, you might also
be interested in our blog post
<a href="https://well-typed.com/blog/2025/09/better-haskell-stack-traces/">Better Haskell stack traces via user annotations</a>,
which discusses some recent extensions we implemented to improve these.</p>
<h3 id="hascallstack-backtraces"><code>HasCallStack</code> backtraces</h3>
<p>Consider this simple Haskell program, where <code>main</code> calls <code>top</code> calls <code>middle</code>
calls <code>bottom</code>:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb1-1"><a href="https://well-typed.com/blog/rss2.xml#cb1-1" tabindex="-1"/><span class="ot">bottom ::</span> <span class="dt">HasCallStack</span> <span class="ot">=&gt;</span> <span class="dt">IO</span> ()</span>
<span id="cb1-2"><a href="https://well-typed.com/blog/rss2.xml#cb1-2" tabindex="-1"/>bottom <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb1-3"><a href="https://well-typed.com/blog/rss2.xml#cb1-3" tabindex="-1"/>    bt <span class="ot">&lt;-</span> collectBacktraces</span>
<span id="cb1-4"><a href="https://well-typed.com/blog/rss2.xml#cb1-4" tabindex="-1"/>    <span class="fu">putStrLn</span> <span class="op">$</span> displayBacktraces bt</span>
<span id="cb1-5"><a href="https://well-typed.com/blog/rss2.xml#cb1-5" tabindex="-1"/></span>
<span id="cb1-6"><a href="https://well-typed.com/blog/rss2.xml#cb1-6" tabindex="-1"/><span class="ot">middle ::</span> <span class="dt">HasCallStack</span> <span class="ot">=&gt;</span> <span class="dt">IO</span> ()</span>
<span id="cb1-7"><a href="https://well-typed.com/blog/rss2.xml#cb1-7" tabindex="-1"/>middle <span class="ot">=</span> bottom</span>
<span id="cb1-8"><a href="https://well-typed.com/blog/rss2.xml#cb1-8" tabindex="-1"/></span>
<span id="cb1-9"><a href="https://well-typed.com/blog/rss2.xml#cb1-9" tabindex="-1"/><span class="ot">top ::</span> <span class="dt">HasCallStack</span> <span class="ot">=&gt;</span> <span class="dt">IO</span> ()</span>
<span id="cb1-10"><a href="https://well-typed.com/blog/rss2.xml#cb1-10" tabindex="-1"/>top <span class="ot">=</span> middle</span>
<span id="cb1-11"><a href="https://well-typed.com/blog/rss2.xml#cb1-11" tabindex="-1"/></span>
<span id="cb1-12"><a href="https://well-typed.com/blog/rss2.xml#cb1-12" tabindex="-1"/><span class="ot">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb1-13"><a href="https://well-typed.com/blog/rss2.xml#cb1-13" tabindex="-1"/>main <span class="ot">=</span> top</span></code></pre></div>
<p>A <code>HasCallStack</code> is essentially an additional function argument which is
automatically populated by GHC at call sites with information about where the
function was called. When we run this program, we see something like this:</p>
<pre><code>HasCallStack backtrace:
  collectBacktraces, called at exe/DemoCallStack.hs:13:11 in (..)
  bottom, called at exe/DemoCallStack.hs:18:10 in (..)
  middle, called at exe/DemoCallStack.hs:22:7 in (..)
  top, called at exe/DemoCallStack.hs:25:8 in (..)</code></pre>
<p>The only thing worth noting here is that the moment a <code>HasCallStack</code> chain is
broken, the backtrace is cut off there. For example, if <code>middle</code> does not have a
<code>HasCallStack</code> constraint, we can no longer see where <code>middle</code> was called from:</p>
<pre><code>HasCallStack backtrace:
  collectBacktraces, called at exe/DemoCallStack.hs:19:11 in (..)
  bottom, called at exe/DemoCallStack.hs:24:10 in (..)</code></pre>
<p>The fact that <code>top</code> still has a <code>HasCallStack</code> constraint does not matter: the
callstack is cut at the first missing link.</p>
<h3 id="cost-centre-backtraces">Cost centre backtraces</h3>
<p>Cost centres are how GHC implements profiling: very roughly, the cost of a
computation is attributed to its enclosing cost centre (see chapter
<a href="https://downloads.haskell.org/ghc/latest/docs/users_guide/profiling.html">Profiling</a> of the GHC manual). Like <code>HasCallStack</code>,
this relies on source code annotations:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb4-1"><a href="https://well-typed.com/blog/rss2.xml#cb4-1" tabindex="-1"/><span class="ot">{-# SCC bottom #-}</span></span>
<span id="cb4-2"><a href="https://well-typed.com/blog/rss2.xml#cb4-2" tabindex="-1"/><span class="ot">bottom ::</span> <span class="dt">HasCallStack</span> <span class="ot">=&gt;</span> <span class="dt">IO</span> ()</span>
<span id="cb4-3"><a href="https://well-typed.com/blog/rss2.xml#cb4-3" tabindex="-1"/>bottom <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb4-4"><a href="https://well-typed.com/blog/rss2.xml#cb4-4" tabindex="-1"/>    bt <span class="ot">&lt;-</span> collectBacktraces</span>
<span id="cb4-5"><a href="https://well-typed.com/blog/rss2.xml#cb4-5" tabindex="-1"/>    <span class="fu">putStrLn</span> <span class="op">$</span> displayBacktraces bt</span>
<span id="cb4-6"><a href="https://well-typed.com/blog/rss2.xml#cb4-6" tabindex="-1"/></span>
<span id="cb4-7"><a href="https://well-typed.com/blog/rss2.xml#cb4-7" tabindex="-1"/><span class="ot">{-# SCC middle #-}</span></span>
<span id="cb4-8"><a href="https://well-typed.com/blog/rss2.xml#cb4-8" tabindex="-1"/><span class="ot">middle ::</span> <span class="dt">IO</span> ()</span>
<span id="cb4-9"><a href="https://well-typed.com/blog/rss2.xml#cb4-9" tabindex="-1"/>middle <span class="ot">=</span> bottom</span>
<span id="cb4-10"><a href="https://well-typed.com/blog/rss2.xml#cb4-10" tabindex="-1"/></span>
<span id="cb4-11"><a href="https://well-typed.com/blog/rss2.xml#cb4-11" tabindex="-1"/><span class="ot">{-# SCC top #-}</span></span>
<span id="cb4-12"><a href="https://well-typed.com/blog/rss2.xml#cb4-12" tabindex="-1"/><span class="ot">top ::</span> <span class="dt">HasCallStack</span> <span class="ot">=&gt;</span> <span class="dt">IO</span> ()</span>
<span id="cb4-13"><a href="https://well-typed.com/blog/rss2.xml#cb4-13" tabindex="-1"/>top <span class="ot">=</span> middle</span>
<span id="cb4-14"><a href="https://well-typed.com/blog/rss2.xml#cb4-14" tabindex="-1"/></span>
<span id="cb4-15"><a href="https://well-typed.com/blog/rss2.xml#cb4-15" tabindex="-1"/><span class="ot">{-# SCC main #-}</span></span>
<span id="cb4-16"><a href="https://well-typed.com/blog/rss2.xml#cb4-16" tabindex="-1"/><span class="ot">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb4-17"><a href="https://well-typed.com/blog/rss2.xml#cb4-17" tabindex="-1"/>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb4-18"><a href="https://well-typed.com/blog/rss2.xml#cb4-18" tabindex="-1"/>    setBacktraceMechanismState <span class="dt">CostCentreBacktrace</span> <span class="dt">True</span></span>
<span id="cb4-19"><a href="https://well-typed.com/blog/rss2.xml#cb4-19" tabindex="-1"/>    top</span></code></pre></div>
<p>Unlike <code>HasCallStack</code>, however, GHC offers ways for inserting such annotations
automatically, which can often make cost centre based callstacks more practical
than <code>HasCallStack</code>. The most common flag to do this is <code>-fprof-auto</code> or (in
recent GHC) <code>-fprof-late</code> (see <a href="https://well-typed.com/blog/2023/03/prof-late/">Late Cost Centre
Profiling</a>). This inserts cost centres around all
top-level functions, as we did manually above.</p>
<p>Cost centre backtraces must be explicitly enabled by calling
<a href="https://hackage-content.haskell.org/package/base-4.22.0.0/docs/Control-Exception-Backtrace.html#v:setBacktraceMechanismState%5D"><code>setBacktraceMechanismState</code></a>, and you need
to compile your code with profiling enabled; the
<a href="https://cabal.readthedocs.io/en/stable/how-to-enable-profiling.html"><code>cabal</code> option <code>--enable-profiling</code></a>
both enables profiling as well as automatic cost centre insertion. The backtrace
for this example might look something like</p>
<pre><code>Cost-centre stack backtrace:
  DemoCallStack.main (exe/DemoCallStack.hs:(32,1)-(34,7))
  DemoCallStack.top (exe/DemoCallStack.hs:28:1-12)
  DemoCallStack.middle (exe/DemoCallStack.hs:24:1-15)
  DemoCallStack.bottom (exe/DemoCallStack.hs:(18,1)-(20,35))</code></pre>
<p>Be aware however that optimizations can delete cost centres, especially in
simple examples like this (<a href="https://gitlab.haskell.org/ghc/ghc/-/issues/27225">#27225</a>).</p>
<h3 id="cost-centres-vs-exception-handling">Cost centres vs exception handling</h3>
<p>Consider the following example: as before, <code>main</code> calls <code>top</code> calls <code>middle</code>
calls <code>bottom</code>, which prints a backtrace; however <code>bottom</code> then throws an
excepton. Meanwhile, <code>main</code> installs an exception handler called <code>handlerTop</code>,
which in turn calls <code>handlerMiddle</code> calls <code>handlerBottom</code>, which prints its
own backtrace:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb6-1"><a href="https://well-typed.com/blog/rss2.xml#cb6-1" tabindex="-1"/><span class="ot">bottom ::</span> <span class="dt">HasCallStack</span> <span class="ot">=&gt;</span> <span class="dt">IO</span> ()</span>
<span id="cb6-2"><a href="https://well-typed.com/blog/rss2.xml#cb6-2" tabindex="-1"/>bottom <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb6-3"><a href="https://well-typed.com/blog/rss2.xml#cb6-3" tabindex="-1"/>    bt <span class="ot">&lt;-</span> collectBacktraces</span>
<span id="cb6-4"><a href="https://well-typed.com/blog/rss2.xml#cb6-4" tabindex="-1"/>    <span class="fu">putStrLn</span> <span class="op">$</span> displayBacktraces bt</span>
<span id="cb6-5"><a href="https://well-typed.com/blog/rss2.xml#cb6-5" tabindex="-1"/>    throwIO <span class="op">$</span> <span class="fu">userError</span> <span class="st">"Uhoh"</span></span>
<span id="cb6-6"><a href="https://well-typed.com/blog/rss2.xml#cb6-6" tabindex="-1"/></span>
<span id="cb6-7"><a href="https://well-typed.com/blog/rss2.xml#cb6-7" tabindex="-1"/><span class="ot">middle ::</span> <span class="dt">HasCallStack</span> <span class="ot">=&gt;</span> <span class="dt">IO</span> ()</span>
<span id="cb6-8"><a href="https://well-typed.com/blog/rss2.xml#cb6-8" tabindex="-1"/>middle <span class="ot">=</span> bottom</span>
<span id="cb6-9"><a href="https://well-typed.com/blog/rss2.xml#cb6-9" tabindex="-1"/></span>
<span id="cb6-10"><a href="https://well-typed.com/blog/rss2.xml#cb6-10" tabindex="-1"/><span class="ot">top ::</span> <span class="dt">HasCallStack</span> <span class="ot">=&gt;</span> <span class="dt">IO</span> ()</span>
<span id="cb6-11"><a href="https://well-typed.com/blog/rss2.xml#cb6-11" tabindex="-1"/>top <span class="ot">=</span> middle</span>
<span id="cb6-12"><a href="https://well-typed.com/blog/rss2.xml#cb6-12" tabindex="-1"/></span>
<span id="cb6-13"><a href="https://well-typed.com/blog/rss2.xml#cb6-13" tabindex="-1"/><span class="ot">handlerBottom ::</span> <span class="dt">HasCallStack</span> <span class="ot">=&gt;</span> <span class="dt">SomeException</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> ()</span>
<span id="cb6-14"><a href="https://well-typed.com/blog/rss2.xml#cb6-14" tabindex="-1"/>handlerBottom _e <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb6-15"><a href="https://well-typed.com/blog/rss2.xml#cb6-15" tabindex="-1"/>    bt <span class="ot">&lt;-</span> collectBacktraces</span>
<span id="cb6-16"><a href="https://well-typed.com/blog/rss2.xml#cb6-16" tabindex="-1"/>    <span class="fu">putStrLn</span> <span class="op">$</span> displayBacktraces bt</span>
<span id="cb6-17"><a href="https://well-typed.com/blog/rss2.xml#cb6-17" tabindex="-1"/></span>
<span id="cb6-18"><a href="https://well-typed.com/blog/rss2.xml#cb6-18" tabindex="-1"/><span class="ot">handlerMiddle ::</span> <span class="dt">HasCallStack</span> <span class="ot">=&gt;</span> <span class="dt">SomeException</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> ()</span>
<span id="cb6-19"><a href="https://well-typed.com/blog/rss2.xml#cb6-19" tabindex="-1"/>handlerMiddle e <span class="ot">=</span> handlerBottom e</span>
<span id="cb6-20"><a href="https://well-typed.com/blog/rss2.xml#cb6-20" tabindex="-1"/></span>
<span id="cb6-21"><a href="https://well-typed.com/blog/rss2.xml#cb6-21" tabindex="-1"/><span class="ot">handlerTop ::</span> <span class="dt">HasCallStack</span> <span class="ot">=&gt;</span> <span class="dt">SomeException</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> ()</span>
<span id="cb6-22"><a href="https://well-typed.com/blog/rss2.xml#cb6-22" tabindex="-1"/>handlerTop e <span class="ot">=</span> handlerMiddle e</span>
<span id="cb6-23"><a href="https://well-typed.com/blog/rss2.xml#cb6-23" tabindex="-1"/></span>
<span id="cb6-24"><a href="https://well-typed.com/blog/rss2.xml#cb6-24" tabindex="-1"/><span class="ot">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb6-25"><a href="https://well-typed.com/blog/rss2.xml#cb6-25" tabindex="-1"/>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb6-26"><a href="https://well-typed.com/blog/rss2.xml#cb6-26" tabindex="-1"/>    setBacktraceMechanismState <span class="dt">CostCentreBacktrace</span> <span class="dt">True</span></span>
<span id="cb6-27"><a href="https://well-typed.com/blog/rss2.xml#cb6-27" tabindex="-1"/>    top  <span class="ot">`catch`</span> handlerTop</span></code></pre></div>
<p>The <code>HasCallStack</code> backtrace printed by <code>bottom</code> is</p>
<pre><code>HasCallStack backtrace:
  collectBacktraces, called at exe/DemoCCS.hs:24:11 in (..)
  bottom, called at exe/DemoCCS.hs:29:10 in (..)
  middle, called at exe/DemoCCS.hs:32:7 in (..)
  top, called at exe/DemoCCS.hs:41:5 in (..)</code></pre>
<p>as before; the <code>HasCallStack</code> printed by <code>handlerBottom</code> is very similar:</p>
<pre><code>HasCallStack backtrace:
  collectBacktraces, called at exe/DemoCCS.hs:13:11 in (..)
  handlerBottom, called at exe/DemoCCS.hs:17:19 in (..)
  handlerMiddle, called at exe/DemoCCS.hs:20:16 in (..)
  handlerTop, called at exe/DemoCCS.hs:41:18 in (..)</code></pre>
<p>For the cost-centre based backtrace, the one shown in <code>bottom</code> is as before:</p>
<pre><code>Cost-centre stack backtrace:
  DemoCCS.main (exe/DemoCCS.hs:(39,1)-(41,27))
  DemoCCS.top (exe/DemoCCS.hs:32:1-12)
  DemoCCS.middle (exe/DemoCCS.hs:29:1-15)
  DemoCCS.bottom (exe/DemoCCS.hs:(23,1)-(26,30))</code></pre>
<p>but the one shown in <code>handlerBottom</code> is more surprising:</p>
<pre><code>Cost-centre stack backtrace:
  DemoCCS.main (exe/DemoCCS.hs:(39,1)-(41,27))
  DemoCCS.top (exe/DemoCCS.hs:32:1-12)
  DemoCCS.middle (exe/DemoCCS.hs:29:1-15)
  DemoCCS.bottom (exe/DemoCCS.hs:(23,1)-(26,30))
  DemoCCS.handlerTop (exe/DemoCCS.hs:20:1-30)
  DemoCCS.handlerMiddle (exe/DemoCCS.hs:17:1-33)
  DemoCCS.handlerBottom (exe/DemoCCS.hs:(12,1)-(14,35))</code></pre>
<p>Whether or not this is expected/correct behaviour is arguable, but the rule is
this: the cost centre stack is not restored <em>until we leave the scope of
<code>catch</code></em>. Put another way: the cost centre stack reflects the fact that <code>bottom</code>
“calls” <code>handlerTop</code>, however indirectly. This applies transitively: if
<code>handlerTop</code> would throw an exception, which would then be caught by some other
exception handler, then <em>its</em> backtrace would reflect that <code>top</code> “called”
<code>handlerTop</code> “called” that other exception handler. This kind of situation can
arise quite naturally, for example when using handlers that deallocate some
resources and then <em>rethrow</em> the exception.</p>
<h2 id="basic-definitions">Basic definitions</h2>
<p>Before we look at the subtleties that arise from actually catching and throwing
(or rethrowing) exceptions, we’ll first get the basic definitions out of the
way. These have not changed much between recent GHC versions and are hopefully
uncontroversial.</p>
<h3 id="exception-annotations">Exception annotations</h3>
<p>Exceptions annotations can basically be anything at all; the only requirement is
that that we can display them:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb11-1"><a href="https://well-typed.com/blog/rss2.xml#cb11-1" tabindex="-1"/><span class="kw">class</span> <span class="dt">Typeable</span> a <span class="ot">=&gt;</span> <span class="dt">ExceptionAnnotation</span> a <span class="kw">where</span></span>
<span id="cb11-2"><a href="https://well-typed.com/blog/rss2.xml#cb11-2" tabindex="-1"/><span class="ot">  displayExceptionAnnotation ::</span> a <span class="ot">-&gt;</span> <span class="dt">String</span></span></code></pre></div>
<p>An important instance of this class is <a href="https://hackage-content.haskell.org/package/base-4.22.0.0/docs/Control-Exception-Backtrace.html#t:Backtraces"><code>Backtraces</code></a>, which
wraps a set of different kinds of backtraces:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb12-1"><a href="https://well-typed.com/blog/rss2.xml#cb12-1" tabindex="-1"/><span class="kw">instance</span> <span class="dt">ExceptionAnnotation</span> <span class="dt">Backtraces</span> <span class="kw">where</span></span>
<span id="cb12-2"><a href="https://well-typed.com/blog/rss2.xml#cb12-2" tabindex="-1"/>    displayExceptionAnnotation <span class="ot">=</span> Base.displayBacktraces</span></code></pre></div>
<h3 id="exception-context">Exception context</h3>
<p>An exception context is essentially just a list of exception annotations. However,
since those annotations may be of different types, we need to wrap them in an
existential:</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb13-1"><a href="https://well-typed.com/blog/rss2.xml#cb13-1" tabindex="-1"/><span class="kw">data</span> <span class="dt">ExceptionContext</span> <span class="ot">=</span> <span class="dt">ExceptionContext</span> [<span class="dt">SomeExceptionAnnotation</span>]</span>
<span id="cb13-2"><a href="https://well-typed.com/blog/rss2.xml#cb13-2" tabindex="-1"/><span class="kw">data</span> <span class="dt">SomeExceptionAnnotation</span> <span class="ot">=</span> <span class="kw">forall</span> a<span class="op">.</span> <span class="dt">ExceptionAnnotation</span> a <span class="ot">=&gt;</span> <span class="dt">SomeExceptionAnnotation</span> a</span></code></pre></div>
<p>There are functions for manipulating the exception context. The most important
are <a href="https://hackage-content.haskell.org/package/base-4.22.0.0/docs/Control-Exception-Context.html#v:emptyExceptionContext"><code>emptyExceptionContext</code></a> and
<a href="https://hackage-content.haskell.org/package/base-4.22.0.0/docs/Control-Exception.html#v:addExceptionContext"><code>addExceptionAnnotation</code></a>, for creating an
empty context and inserting an annotation into an existing context respectively.</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb14-1"><a href="https://well-typed.com/blog/rss2.xml#cb14-1" tabindex="-1"/><span class="ot">emptyExceptionContext  ::</span> <span class="dt">ExceptionContext</span></span>
<span id="cb14-2"><a href="https://well-typed.com/blog/rss2.xml#cb14-2" tabindex="-1"/><span class="ot">addExceptionAnnotation ::</span> <span class="dt">ExceptionAnnotation</span> a <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">ExceptionContext</span> <span class="ot">-&gt;</span> <span class="dt">ExceptionContext</span></span></code></pre></div>
<h3 id="pivotal-change-someexception">Pivotal change: <code>SomeException</code></h3>
<p>The pivotal change in all of this is in the definition of <code>SomeException</code> which,
starting in GHC 9.10, now has an associated list of annotations:</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb15-1"><a href="https://well-typed.com/blog/rss2.xml#cb15-1" tabindex="-1"/><span class="kw">data</span> <span class="dt">SomeException</span> <span class="ot">=</span> <span class="kw">forall</span> e<span class="op">.</span> (<span class="dt">Exception</span> e, <span class="dt">HasExceptionContext</span>) <span class="ot">=&gt;</span> <span class="dt">SomeException</span> e</span>
<span id="cb15-2"><a href="https://well-typed.com/blog/rss2.xml#cb15-2" tabindex="-1"/><span class="kw">type</span> <span class="dt">HasExceptionContext</span> <span class="ot">=</span> (<span class="op">?</span><span class="ot">exceptionContext ::</span> <span class="dt">ExceptionContext</span>)</span></code></pre></div>
<p>The use of an <a href="https://downloads.haskell.org/ghc/latest/docs/users_guide/exts/implicit_parameters.html#extension-ImplicitParams">implicit parameter</a> means that pattern
matching on <code>SomeException</code> remains possible in the same way as before (though
the annotations would be silently dropped).</p>
<p>There are various functions for extracting and manipulating the exception
context associated with an exception, such as
<a href="https://hackage-content.haskell.org/package/base-4.22.0.0/docs/Control-Exception.html#v:someExceptionContext"><code>someExceptionContext</code></a> and
<a href="https://hackage-content.haskell.org/package/base-4.22.0.0/docs/Control-Exception.html#v:addExceptionContext"><code>addExceptionContext</code></a>:</p>
<div class="sourceCode" id="cb16"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb16-1"><a href="https://well-typed.com/blog/rss2.xml#cb16-1" tabindex="-1"/><span class="ot">someExceptionContext ::</span> <span class="dt">SomeException</span> <span class="ot">-&gt;</span> <span class="dt">ExceptionContext</span></span>
<span id="cb16-2"><a href="https://well-typed.com/blog/rss2.xml#cb16-2" tabindex="-1"/><span class="ot">addExceptionContext  ::</span> <span class="dt">ExceptionAnnotation</span> a <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">SomeException</span> <span class="ot">-&gt;</span> <span class="dt">SomeException</span></span></code></pre></div>
<p>However, probably the most important function for extending exception contexts
is <a href="https://hackage-content.haskell.org/package/base-4.22.0.0/docs/Control-Exception.html#v:annotateIO"><code>annotateIO</code></a>, which installs an exception handler that
extends any exception that is thrown with the specified annotation:</p>
<div class="sourceCode" id="cb17"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb17-1"><a href="https://well-typed.com/blog/rss2.xml#cb17-1" tabindex="-1"/><span class="ot">annotateIO ::</span> <span class="kw">forall</span> e a<span class="op">.</span> <span class="dt">ExceptionAnnotation</span> e <span class="ot">=&gt;</span> e <span class="ot">-&gt;</span> <span class="dt">IO</span> a <span class="ot">-&gt;</span> <span class="dt">IO</span> a</span>
<span id="cb17-2"><a href="https://well-typed.com/blog/rss2.xml#cb17-2" tabindex="-1"/>annotateIO ann (<span class="dt">IO</span> io) <span class="ot">=</span> <span class="dt">IO</span> (PrimOp.catch<span class="op">#</span> io handler)</span>
<span id="cb17-3"><a href="https://well-typed.com/blog/rss2.xml#cb17-3" tabindex="-1"/>  <span class="kw">where</span></span>
<span id="cb17-4"><a href="https://well-typed.com/blog/rss2.xml#cb17-4" tabindex="-1"/>    handler se <span class="ot">=</span> PrimOp.raiseIO<span class="op">#</span> (addExceptionContext ann se)</span></code></pre></div>
<p>It is important to emphasize that this is implemented with
<a href="https://hackage-content.haskell.org/package/ghc-prim-0.13.0/docs/GHC-PrimopWrappers.html">primops</a>, not with the regular <code>catch</code> and <code>throwIO</code>
functions, which do considerably more than merely catching and throwing, as we
shall see.</p>
<h2 id="exception-type-class"><code>Exception</code> type class</h2>
<p>The <code>Exception</code> type class is a central abstraction in Haskell’s exception
ecosystem. As part of the exception annotation work, it has received one minor
extension, and it was changed in two not-so-minor-but-rather-subtle ways. Let’s
first get the part out of the way which has <em>not</em> changed: exceptions are no
good if we cannot see them:</p>
<div class="sourceCode" id="cb18"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb18-1"><a href="https://well-typed.com/blog/rss2.xml#cb18-1" tabindex="-1"/><span class="kw">class</span> (<span class="dt">Typeable</span> e, <span class="dt">Show</span> e) <span class="ot">=&gt;</span> <span class="dt">Exception</span> e <span class="kw">where</span></span>
<span id="cb18-2"><a href="https://well-typed.com/blog/rss2.xml#cb18-2" tabindex="-1"/><span class="ot">  displayException ::</span> e <span class="ot">-&gt;</span> <span class="dt">String</span></span>
<span id="cb18-3"><a href="https://well-typed.com/blog/rss2.xml#cb18-3" tabindex="-1"/>  displayException <span class="ot">=</span> <span class="fu">show</span></span>
<span id="cb18-4"><a href="https://well-typed.com/blog/rss2.xml#cb18-4" tabindex="-1"/></span>
<span id="cb18-5"><a href="https://well-typed.com/blog/rss2.xml#cb18-5" tabindex="-1"/>  <span class="co">-- (..)</span></span></code></pre></div>
<h3 id="backtracedesired"><code>backtraceDesired</code></h3>
<p>The minor extension is a new function called
<a href="https://hackage-content.haskell.org/package/base-4.22.0.0/docs/Control-Exception.html#v:backtraceDesired"><code>backtraceDesired</code></a>, which indicates if a backtrace
should be attached to exceptions of this type; we will see how this function is
used when we discuss the <a href="https://well-typed.com/blog/rss2.xml#implementation">implementation of <code>throwIO</code></a>.</p>
<div class="sourceCode" id="cb19"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb19-1"><a href="https://well-typed.com/blog/rss2.xml#cb19-1" tabindex="-1"/><span class="kw">class</span> (<span class="dt">Typeable</span> e, <span class="dt">Show</span> e) <span class="ot">=&gt;</span> <span class="dt">Exception</span> e <span class="kw">where</span></span>
<span id="cb19-2"><a href="https://well-typed.com/blog/rss2.xml#cb19-2" tabindex="-1"/>  <span class="co">-- (..)</span></span>
<span id="cb19-3"><a href="https://well-typed.com/blog/rss2.xml#cb19-3" tabindex="-1"/></span>
<span id="cb19-4"><a href="https://well-typed.com/blog/rss2.xml#cb19-4" tabindex="-1"/><span class="ot">  backtraceDesired ::</span> e <span class="ot">-&gt;</span> <span class="dt">Bool</span></span>
<span id="cb19-5"><a href="https://well-typed.com/blog/rss2.xml#cb19-5" tabindex="-1"/>  backtraceDesired _ <span class="ot">=</span> <span class="dt">True</span></span></code></pre></div>
<p>The argument to <code>backtraceDesired</code> is already fully constructed exception; the
question is whether a backtrace should be <em>added</em> to that exception. In most
cases the argument can simply be ignored, but it doesn’t <em>have</em> to be. For all
but a handful of specialized cases the default implementation (indicating that
yes, we want a backtrace) will be fine.</p>
<h3 id="fromexception"><code>fromException</code></h3>
<p>The not-so-minor-but-rather-subtle changes are in <code>fromException</code> and
<code>toException</code>, which remove and add the <code>SomeException</code> wrapper around
exceptions respectively. Let’s first look at <code>fromException</code>:</p>
<div class="sourceCode" id="cb20"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb20-1"><a href="https://well-typed.com/blog/rss2.xml#cb20-1" tabindex="-1"/><span class="kw">class</span> (<span class="dt">Typeable</span> e, <span class="dt">Show</span> e) <span class="ot">=&gt;</span> <span class="dt">Exception</span> e <span class="kw">where</span></span>
<span id="cb20-2"><a href="https://well-typed.com/blog/rss2.xml#cb20-2" tabindex="-1"/>  <span class="co">-- (..)</span></span>
<span id="cb20-3"><a href="https://well-typed.com/blog/rss2.xml#cb20-3" tabindex="-1"/></span>
<span id="cb20-4"><a href="https://well-typed.com/blog/rss2.xml#cb20-4" tabindex="-1"/><span class="ot">  fromException ::</span> <span class="dt">SomeException</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> e</span>
<span id="cb20-5"><a href="https://well-typed.com/blog/rss2.xml#cb20-5" tabindex="-1"/>  fromException (<span class="dt">SomeException</span> e) <span class="ot">=</span> cast e</span></code></pre></div>
<p>This may <em>look</em> no different from the implementation
<a href="https://hackage.haskell.org/package/base-4.19.2.0/docs/src/GHC.Exception.Type.html#Exception">prior to 9.10</a>,
but recall that <code>SomeException</code> now has an additional field: the exception
annotations. As mentioned above, a pattern match like this will silently discard
those annotations.</p>
<h3 id="toexception"><code>toException</code></h3>
<p>The final function in the <code>Exception</code> class is <code>toException</code>, which is intended
to add the <code>SomeException</code> wrapper.</p>
<div class="sourceCode" id="cb21"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb21-1"><a href="https://well-typed.com/blog/rss2.xml#cb21-1" tabindex="-1"/><span class="kw">class</span> (<span class="dt">Typeable</span> e, <span class="dt">Show</span> e) <span class="ot">=&gt;</span> <span class="dt">Exception</span> e <span class="kw">where</span></span>
<span id="cb21-2"><a href="https://well-typed.com/blog/rss2.xml#cb21-2" tabindex="-1"/>  <span class="co">-- (..)</span></span>
<span id="cb21-3"><a href="https://well-typed.com/blog/rss2.xml#cb21-3" tabindex="-1"/><span class="ot">  toException ::</span> e <span class="ot">-&gt;</span> <span class="dt">SomeException</span></span></code></pre></div>
<p>Prior to 9.10, the default implementation literally just added the
<code>SomeException</code> constructor:</p>
<div class="sourceCode" id="cb22"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb22-1"><a href="https://well-typed.com/blog/rss2.xml#cb22-1" tabindex="-1"/>  <span class="co">-- implementation prior to 9.10</span></span>
<span id="cb22-2"><a href="https://well-typed.com/blog/rss2.xml#cb22-2" tabindex="-1"/>  toException <span class="ot">=</span> <span class="dt">SomeException</span></span></code></pre></div>
<p>However, starting in 9.10 we also need to give an initial value for the
exception context. The default implementation, reasonably enough, chooses the
empty context:</p>
<div class="sourceCode" id="cb23"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb23-1"><a href="https://well-typed.com/blog/rss2.xml#cb23-1" tabindex="-1"/>  <span class="co">-- implementation in 9.10, 9.12, 9.14, and 10.0</span></span>
<span id="cb23-2"><a href="https://well-typed.com/blog/rss2.xml#cb23-2" tabindex="-1"/>  toException e <span class="ot">=</span> <span class="kw">let</span> <span class="op">?</span>exceptionContext <span class="ot">=</span> emptyExceptionContext <span class="kw">in</span> <span class="dt">SomeException</span> e</span></code></pre></div>
<p>Unfortunately, however, the <em>documentation</em> of <code>toException</code> has also been
modified, and now states that <code>toException</code> <a href="https://hackage-content.haskell.org/package/base-4.22.0.0/docs/Control-Exception.html#v:toException">should produce a <code>SomeException</code>
with no attached <code>ExceptionContext</code></a>. Personally, I think
that is a mistake (<a href="https://gitlab.haskell.org/ghc/ghc/-/issues/27194">#27194</a>); we will discuss this in
the next session.</p>
<h4 id="caution-instance-for-someexception-itself">⚠️ Caution: Instance for <code>SomeException</code> itself</h4>
<p><code>SomeException</code> <em>itself</em> is also an instance of <code>Exception</code>; <code>fromException</code> is
trivial, and <code>backtraceDesired</code> and <code>displayException</code> piggy-back on the
definition of whatever exception is wrapped:</p>
<div class="sourceCode" id="cb24"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb24-1"><a href="https://well-typed.com/blog/rss2.xml#cb24-1" tabindex="-1"/><span class="kw">instance</span> <span class="dt">Exception</span> <span class="dt">SomeException</span> <span class="kw">where</span></span>
<span id="cb24-2"><a href="https://well-typed.com/blog/rss2.xml#cb24-2" tabindex="-1"/>  fromException <span class="ot">=</span> <span class="dt">Just</span></span>
<span id="cb24-3"><a href="https://well-typed.com/blog/rss2.xml#cb24-3" tabindex="-1"/></span>
<span id="cb24-4"><a href="https://well-typed.com/blog/rss2.xml#cb24-4" tabindex="-1"/>  backtraceDesired (<span class="dt">SomeException</span> e) <span class="ot">=</span> backtraceDesired e</span>
<span id="cb24-5"><a href="https://well-typed.com/blog/rss2.xml#cb24-5" tabindex="-1"/>  displayException (<span class="dt">SomeException</span> e) <span class="ot">=</span> displayException e</span>
<span id="cb24-6"><a href="https://well-typed.com/blog/rss2.xml#cb24-6" tabindex="-1"/></span>
<span id="cb24-7"><a href="https://well-typed.com/blog/rss2.xml#cb24-7" tabindex="-1"/>  <span class="co">-- (..)</span></span></code></pre></div>
<p>The definition of <code>toException</code> is more problematic, however. Prior to 9.10,
calling <code>toException</code> on <code>SomeException</code> was just an identity:</p>
<div class="sourceCode" id="cb25"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb25-1"><a href="https://well-typed.com/blog/rss2.xml#cb25-1" tabindex="-1"/><span class="kw">instance</span> <span class="dt">Exception</span> <span class="dt">SomeException</span> <span class="kw">where</span></span>
<span id="cb25-2"><a href="https://well-typed.com/blog/rss2.xml#cb25-2" tabindex="-1"/>  <span class="co">-- (..)</span></span>
<span id="cb25-3"><a href="https://well-typed.com/blog/rss2.xml#cb25-3" tabindex="-1"/></span>
<span id="cb25-4"><a href="https://well-typed.com/blog/rss2.xml#cb25-4" tabindex="-1"/>  <span class="co">-- Prior to 9.10</span></span>
<span id="cb25-5"><a href="https://well-typed.com/blog/rss2.xml#cb25-5" tabindex="-1"/>  toException se <span class="ot">=</span> se</span></code></pre></div>
<p>Now, however, the implementation must <em>clear</em> the existing context in order to
satisfy the contract:</p>
<div class="sourceCode" id="cb26"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb26-1"><a href="https://well-typed.com/blog/rss2.xml#cb26-1" tabindex="-1"/><span class="kw">instance</span> <span class="dt">Exception</span> <span class="dt">SomeException</span> <span class="kw">where</span></span>
<span id="cb26-2"><a href="https://well-typed.com/blog/rss2.xml#cb26-2" tabindex="-1"/>  <span class="co">-- (..)</span></span>
<span id="cb26-3"><a href="https://well-typed.com/blog/rss2.xml#cb26-3" tabindex="-1"/></span>
<span id="cb26-4"><a href="https://well-typed.com/blog/rss2.xml#cb26-4" tabindex="-1"/>  toException (<span class="dt">SomeException</span> e) <span class="ot">=</span> <span class="kw">let</span> <span class="op">?</span>exceptionContext <span class="ot">=</span> emptyExceptionContext <span class="kw">in</span> <span class="dt">SomeException</span> e</span></code></pre></div>
<p>I think this is simply wrong; at the very least, it is highly counter-intuitive,
and it also does not match
<a href="https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0330-exception-backtraces.rst">the original proposal</a>;
I don’t know why this was changed. We will see some
<a href="https://well-typed.com/blog/rss2.xml#caution-throwing-someexception">consequences of this design choice</a>
when we discuss throwing exceptions.</p>
<h3 id="newtype-helpers">Newtype helpers</h3>
<p>There are two auxiliary types, with their own <code>Exception</code> instances, that can be
helpful when throwing or catching exceptions in specific ways. We haven’t
discussed either throwing or catching yet, but we will nonetheless discuss these
auxiliary types first as we will need them in the subsequent sessions.</p>
<h4 id="nobacktrace"><code>NoBacktrace</code></h4>
<p><code>NoBacktrace</code> can be used to override <code>backtraceDesired</code>:</p>
<div class="sourceCode" id="cb27"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb27-1"><a href="https://well-typed.com/blog/rss2.xml#cb27-1" tabindex="-1"/><span class="kw">newtype</span> <span class="dt">NoBacktrace</span> e <span class="ot">=</span> <span class="dt">NoBacktrace</span> e</span>
<span id="cb27-2"><a href="https://well-typed.com/blog/rss2.xml#cb27-2" tabindex="-1"/></span>
<span id="cb27-3"><a href="https://well-typed.com/blog/rss2.xml#cb27-3" tabindex="-1"/><span class="kw">instance</span> <span class="dt">Exception</span> e <span class="ot">=&gt;</span> <span class="dt">Exception</span> (<span class="dt">NoBacktrace</span> e) <span class="kw">where</span></span>
<span id="cb27-4"><a href="https://well-typed.com/blog/rss2.xml#cb27-4" tabindex="-1"/>  fromException <span class="ot">=</span> <span class="fu">fmap</span> <span class="dt">NoBacktrace</span> <span class="op">.</span> fromException</span>
<span id="cb27-5"><a href="https://well-typed.com/blog/rss2.xml#cb27-5" tabindex="-1"/>  toException (<span class="dt">NoBacktrace</span> e) <span class="ot">=</span> toException e</span>
<span id="cb27-6"><a href="https://well-typed.com/blog/rss2.xml#cb27-6" tabindex="-1"/>  backtraceDesired _ <span class="ot">=</span> <span class="dt">False</span></span>
<span id="cb27-7"><a href="https://well-typed.com/blog/rss2.xml#cb27-7" tabindex="-1"/>  <span class="co">-- displayException left at its default implementation</span></span></code></pre></div>
<h4 id="exceptionwithcontext"><code>ExceptionWithContext</code></h4>
<p>The other, arguably more imporant, auxiliary type is <code>ExceptionWithContext</code>.
The definition itself is straight-forward: it simply pairs some value with an
exception context:</p>
<div class="sourceCode" id="cb28"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb28-1"><a href="https://well-typed.com/blog/rss2.xml#cb28-1" tabindex="-1"/><span class="kw">data</span> <span class="dt">ExceptionWithContext</span> a <span class="ot">=</span> <span class="dt">ExceptionWithContext</span> <span class="dt">ExceptionContext</span> a</span></code></pre></div>
<p>The idea is that this type gives us a way to catch exceptions of specific types (rather than catching <code>SomeException</code>), and still get access to the exception context. For example:</p>
<div class="sourceCode" id="cb29"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb29-1"><a href="https://well-typed.com/blog/rss2.xml#cb29-1" tabindex="-1"/><span class="kw">data</span> <span class="dt">MyException</span> <span class="ot">=</span> <span class="dt">MyException</span></span>
<span id="cb29-2"><a href="https://well-typed.com/blog/rss2.xml#cb29-2" tabindex="-1"/>  <span class="kw">deriving</span> stock (<span class="dt">Show</span>)</span>
<span id="cb29-3"><a href="https://well-typed.com/blog/rss2.xml#cb29-3" tabindex="-1"/>  <span class="kw">deriving</span> anyclass (<span class="dt">Exception</span>)</span>
<span id="cb29-4"><a href="https://well-typed.com/blog/rss2.xml#cb29-4" tabindex="-1"/></span>
<span id="cb29-5"><a href="https://well-typed.com/blog/rss2.xml#cb29-5" tabindex="-1"/><span class="ot">example ::</span> <span class="dt">IO</span> ()</span>
<span id="cb29-6"><a href="https://well-typed.com/blog/rss2.xml#cb29-6" tabindex="-1"/>example <span class="ot">=</span> someAction <span class="ot">`catch`</span> \(<span class="dt">ExceptionWithContext</span> ctxt <span class="dt">MyException</span>) <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb29-7"><a href="https://well-typed.com/blog/rss2.xml#cb29-7" tabindex="-1"/>    <span class="co">-- (..)</span></span></code></pre></div>
<p>The implementation is reasonably straight-forward:</p>
<div class="sourceCode" id="cb30"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb30-1"><a href="https://well-typed.com/blog/rss2.xml#cb30-1" tabindex="-1"/><span class="kw">instance</span> <span class="dt">Exception</span> a <span class="ot">=&gt;</span> <span class="dt">Exception</span> (<span class="dt">ExceptionWithContext</span> a) <span class="kw">where</span></span>
<span id="cb30-2"><a href="https://well-typed.com/blog/rss2.xml#cb30-2" tabindex="-1"/>    toException (<span class="dt">ExceptionWithContext</span> ctxt e) <span class="ot">=</span></span>
<span id="cb30-3"><a href="https://well-typed.com/blog/rss2.xml#cb30-3" tabindex="-1"/>        <span class="kw">case</span> toException e <span class="kw">of</span></span>
<span id="cb30-4"><a href="https://well-typed.com/blog/rss2.xml#cb30-4" tabindex="-1"/>          <span class="dt">SomeException</span> c <span class="ot">-&gt;</span></span>
<span id="cb30-5"><a href="https://well-typed.com/blog/rss2.xml#cb30-5" tabindex="-1"/>            <span class="kw">let</span> <span class="op">?</span>exceptionContext <span class="ot">=</span> ctxt</span>
<span id="cb30-6"><a href="https://well-typed.com/blog/rss2.xml#cb30-6" tabindex="-1"/>            <span class="kw">in</span> <span class="dt">SomeException</span> c</span>
<span id="cb30-7"><a href="https://well-typed.com/blog/rss2.xml#cb30-7" tabindex="-1"/></span>
<span id="cb30-8"><a href="https://well-typed.com/blog/rss2.xml#cb30-8" tabindex="-1"/>    fromException se <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb30-9"><a href="https://well-typed.com/blog/rss2.xml#cb30-9" tabindex="-1"/>        e <span class="ot">&lt;-</span> fromException se</span>
<span id="cb30-10"><a href="https://well-typed.com/blog/rss2.xml#cb30-10" tabindex="-1"/>        <span class="fu">return</span> (<span class="dt">ExceptionWithContext</span> (someExceptionContext se) e)</span>
<span id="cb30-11"><a href="https://well-typed.com/blog/rss2.xml#cb30-11" tabindex="-1"/></span>
<span id="cb30-12"><a href="https://well-typed.com/blog/rss2.xml#cb30-12" tabindex="-1"/>    backtraceDesired (<span class="dt">ExceptionWithContext</span> _ e) <span class="ot">=</span> backtraceDesired e</span>
<span id="cb30-13"><a href="https://well-typed.com/blog/rss2.xml#cb30-13" tabindex="-1"/>    displayException <span class="ot">=</span> displayException <span class="op">.</span> toException</span></code></pre></div>
<p>That said, the devil is very much in the detail with these kinds of definitions,
and as we shall see, it was <a href="https://well-typed.com/blog/rss2.xml#duplicated-annotations">defined incorrectly in GHC
9.10</a>.</p>
<h2 id="throw">Throw</h2>
<p>The primary function for throwing an exception is <code>throwIO</code>, which is defined
as<a class="footnote-ref" href="https://well-typed.com/blog/rss2.xml#fn1" id="fnref1"><sup>1</sup></a></p>
<div class="sourceCode" id="cb31"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb31-1"><a href="https://well-typed.com/blog/rss2.xml#cb31-1" tabindex="-1"/><span class="ot">throwIO ::</span> (<span class="dt">HasCallStack</span>, <span class="dt">Exception</span> e) <span class="ot">=&gt;</span> e <span class="ot">-&gt;</span> <span class="dt">IO</span> a</span>
<span id="cb31-2"><a href="https://well-typed.com/blog/rss2.xml#cb31-2" tabindex="-1"/>throwIO e <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb31-3"><a href="https://well-typed.com/blog/rss2.xml#cb31-3" tabindex="-1"/>    se <span class="ot">&lt;-</span> toExceptionWithBacktrace e</span>
<span id="cb31-4"><a href="https://well-typed.com/blog/rss2.xml#cb31-4" tabindex="-1"/>    <span class="dt">IO</span> (PrimOp.raiseIO<span class="op">#</span> se)</span></code></pre></div>
<p>Most of the actual work happens in <code>toExceptionWithBacktrace</code>:</p>
<div class="sourceCode" id="cb32"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb32-1"><a href="https://well-typed.com/blog/rss2.xml#cb32-1" tabindex="-1"/><span class="ot">toExceptionWithBacktrace ::</span> (<span class="dt">HasCallStack</span>, <span class="dt">Exception</span> e) <span class="ot">=&gt;</span> e <span class="ot">-&gt;</span> <span class="dt">IO</span> <span class="dt">SomeException</span></span>
<span id="cb32-2"><a href="https://well-typed.com/blog/rss2.xml#cb32-2" tabindex="-1"/>toExceptionWithBacktrace e <span class="ot">=</span></span>
<span id="cb32-3"><a href="https://well-typed.com/blog/rss2.xml#cb32-3" tabindex="-1"/>    <span class="kw">if</span> backtraceDesired e <span class="kw">then</span> <span class="kw">do</span></span>
<span id="cb32-4"><a href="https://well-typed.com/blog/rss2.xml#cb32-4" tabindex="-1"/>      bt <span class="ot">&lt;-</span> Base.collectBacktraces</span>
<span id="cb32-5"><a href="https://well-typed.com/blog/rss2.xml#cb32-5" tabindex="-1"/>      <span class="fu">return</span> (addExceptionContext bt (toException e))</span>
<span id="cb32-6"><a href="https://well-typed.com/blog/rss2.xml#cb32-6" tabindex="-1"/>    <span class="kw">else</span></span>
<span id="cb32-7"><a href="https://well-typed.com/blog/rss2.xml#cb32-7" tabindex="-1"/>      <span class="fu">return</span> (toException e)</span></code></pre></div>
<p>That is, if a backtrace is desired, we collect one and add it as an annotation
to the exception that we’re about to throw.</p>
<h3 id="generalization">Generalization</h3>
<p>In GHC 9.14 <code>toExceptionWithBacktrace</code> was generalized to</p>
<div class="sourceCode" id="cb33"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb33-1"><a href="https://well-typed.com/blog/rss2.xml#cb33-1" tabindex="-1"/><span class="ot">toExceptionWithBacktrace ::</span> (<span class="dt">HasCallStack</span>, <span class="dt">Exception</span> e) <span class="ot">=&gt;</span> e <span class="ot">-&gt;</span> <span class="dt">IO</span> <span class="dt">SomeException</span></span>
<span id="cb33-2"><a href="https://well-typed.com/blog/rss2.xml#cb33-2" tabindex="-1"/>toExceptionWithBacktrace e <span class="ot">=</span></span>
<span id="cb33-3"><a href="https://well-typed.com/blog/rss2.xml#cb33-3" tabindex="-1"/>    <span class="kw">if</span> backtraceDesired e <span class="kw">then</span> <span class="kw">do</span></span>
<span id="cb33-4"><a href="https://well-typed.com/blog/rss2.xml#cb33-4" tabindex="-1"/>      <span class="dt">SomeExceptionAnnotation</span> ea <span class="ot">&lt;-</span> collectExceptionAnnotation</span>
<span id="cb33-5"><a href="https://well-typed.com/blog/rss2.xml#cb33-5" tabindex="-1"/>      <span class="fu">return</span> (addExceptionContext ea (toException e))</span>
<span id="cb33-6"><a href="https://well-typed.com/blog/rss2.xml#cb33-6" tabindex="-1"/>    <span class="kw">else</span></span>
<span id="cb33-7"><a href="https://well-typed.com/blog/rss2.xml#cb33-7" tabindex="-1"/>      <span class="fu">return</span> (toException e)</span></code></pre></div>
<p>This is an experimental API (not yet part of <code>base</code>); see <a href="https://github.com/haskell/core-libraries-committee/issues/348">CLC #348</a>
for details. The idea is that you can use
<a href="https://hackage-content.haskell.org/package/ghc-internal-9.1401.0/docs/GHC-Internal-Exception-Backtrace.html#v:setCollectExceptionAnnotation"><code>setCollectExceptionAnnotation</code></a> to
register your own function to be run to construct an annotation whenever an
exception is thrown anywhere. For example, if you’re worried that some IO faults
are happening due to your CPU overheating, you might use</p>
<div class="sourceCode" id="cb34"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb34-1"><a href="https://well-typed.com/blog/rss2.xml#cb34-1" tabindex="-1"/><span class="kw">newtype</span> <span class="dt">Temperature</span> <span class="ot">=</span> <span class="dt">Temperature</span> <span class="dt">Int</span></span>
<span id="cb34-2"><a href="https://well-typed.com/blog/rss2.xml#cb34-2" tabindex="-1"/>  <span class="kw">deriving</span> stock (<span class="dt">Show</span>)</span>
<span id="cb34-3"><a href="https://well-typed.com/blog/rss2.xml#cb34-3" tabindex="-1"/>  <span class="kw">deriving</span> anyclass (<span class="dt">ExceptionAnnotation</span>)</span>
<span id="cb34-4"><a href="https://well-typed.com/blog/rss2.xml#cb34-4" tabindex="-1"/></span>
<span id="cb34-5"><a href="https://well-typed.com/blog/rss2.xml#cb34-5" tabindex="-1"/><span class="ot">getTempCPU ::</span> <span class="dt">IO</span> <span class="dt">Temperature</span></span>
<span id="cb34-6"><a href="https://well-typed.com/blog/rss2.xml#cb34-6" tabindex="-1"/>getTempCPU <span class="ot">=</span> <span class="co">-- (..)</span></span>
<span id="cb34-7"><a href="https://well-typed.com/blog/rss2.xml#cb34-7" tabindex="-1"/></span>
<span id="cb34-8"><a href="https://well-typed.com/blog/rss2.xml#cb34-8" tabindex="-1"/><span class="ot">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb34-9"><a href="https://well-typed.com/blog/rss2.xml#cb34-9" tabindex="-1"/>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb34-10"><a href="https://well-typed.com/blog/rss2.xml#cb34-10" tabindex="-1"/>    setCollectExceptionAnnotation getTempCPU</span>
<span id="cb34-11"><a href="https://well-typed.com/blog/rss2.xml#cb34-11" tabindex="-1"/>    <span class="co">-- (..)</span></span></code></pre></div>
<p>By default, the collection callback is <code>collectBacktraces</code>, so unless you
register a different callback the behaviour is the same as in 9.10 and 9.12.</p>
<h3 id="caution-throwing-someexception">⚠️ Caution: Throwing <code>SomeException</code></h3>
<p>Because <code>throwIO</code> calls <code>toException</code>, and since <code>toException</code> for
<code>SomeException</code>
<a href="https://well-typed.com/blog/rss2.xml#instance-for-someexception-itself"><em>clears the exception context</em></a>,
you probably don’t want to call <code>throwIO</code> on an argument of type
<code>SomeException</code>: any exception annotations that might be embedded in that
exception will be lost.</p>
<p>The most common case for throwing <code>SomeException</code> is <em>inside</em> an exception
handler; we will cover this specific case of <em>rethrowing</em> exceptions <a href="https://well-typed.com/blog/rss2.xml#caution-rethrowing-the-same-exception">when we
discuss <code>onException</code></a>, but we can
reuse the same combinators also to define a general “throw precisely this
exception” function:</p>
<div class="sourceCode" id="cb35"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb35-1"><a href="https://well-typed.com/blog/rss2.xml#cb35-1" tabindex="-1"/><span class="ot">raiseIO ::</span> <span class="dt">SomeException</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> ()</span>
<span id="cb35-2"><a href="https://well-typed.com/blog/rss2.xml#cb35-2" tabindex="-1"/>raiseIO (<span class="dt">SomeException</span> e) <span class="ot">=</span> rethrowIO (<span class="dt">ExceptionWithContext</span> <span class="op">?</span>exceptionContext e)</span></code></pre></div>
<h2 id="catch">Catch</h2>
<p>The most important change in GHC 9.12 from 9.10 is in the definition of <code>catch</code>, which now implements the <a href="https://github.com/haskell/core-libraries-committee/issues/202"><code>WhileHandling</code></a> proposal. The idea is that
when we throw a new exception while handling another, we annotate that new
exception <em>with</em> the old exception: the new exception arose <em>while handling</em>
the old exception:</p>
<div class="sourceCode" id="cb36"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb36-1"><a href="https://well-typed.com/blog/rss2.xml#cb36-1" tabindex="-1"/><span class="kw">data</span> <span class="dt">WhileHandling</span> <span class="ot">=</span> <span class="dt">WhileHandling</span> <span class="dt">SomeException</span> <span class="kw">deriving</span> <span class="dt">Show</span></span>
<span id="cb36-2"><a href="https://well-typed.com/blog/rss2.xml#cb36-2" tabindex="-1"/></span>
<span id="cb36-3"><a href="https://well-typed.com/blog/rss2.xml#cb36-3" tabindex="-1"/><span class="fu">catch</span><span class="ot"> ::</span> <span class="dt">Exception</span> e <span class="ot">=&gt;</span> <span class="dt">IO</span> a <span class="ot">-&gt;</span> (e <span class="ot">-&gt;</span> <span class="dt">IO</span> a) <span class="ot">-&gt;</span> <span class="dt">IO</span> a</span>
<span id="cb36-4"><a href="https://well-typed.com/blog/rss2.xml#cb36-4" tabindex="-1"/><span class="fu">catch</span> (<span class="dt">IO</span> io) handler <span class="ot">=</span> <span class="dt">IO</span> <span class="op">$</span> PrimOp.catch<span class="op">#</span> io handler'</span>
<span id="cb36-5"><a href="https://well-typed.com/blog/rss2.xml#cb36-5" tabindex="-1"/>  <span class="kw">where</span></span>
<span id="cb36-6"><a href="https://well-typed.com/blog/rss2.xml#cb36-6" tabindex="-1"/>    handler' se <span class="ot">=</span></span>
<span id="cb36-7"><a href="https://well-typed.com/blog/rss2.xml#cb36-7" tabindex="-1"/>      <span class="kw">case</span> fromException se <span class="kw">of</span></span>
<span id="cb36-8"><a href="https://well-typed.com/blog/rss2.xml#cb36-8" tabindex="-1"/>        <span class="dt">Just</span> e' <span class="ot">-&gt;</span> PrimOp.catch<span class="op">#</span> (unIO (handler e')) (handler'' se)</span>
<span id="cb36-9"><a href="https://well-typed.com/blog/rss2.xml#cb36-9" tabindex="-1"/>        <span class="dt">Nothing</span> <span class="ot">-&gt;</span> PrimOp.raiseIO<span class="op">#</span> se</span>
<span id="cb36-10"><a href="https://well-typed.com/blog/rss2.xml#cb36-10" tabindex="-1"/></span>
<span id="cb36-11"><a href="https://well-typed.com/blog/rss2.xml#cb36-11" tabindex="-1"/>    handler'' se se' <span class="ot">=</span> PrimOp.raiseIO<span class="op">#</span> (addExceptionContext (<span class="dt">WhileHandling</span> se) se')</span></code></pre></div>
<h3 id="caution-rethrowing-the-same-exception">⚠️ Caution: Rethrowing the same exception</h3>
<p>An important combinator for dealing with exceptions is <code>onException</code>, which
runs some specified action when an exception occurs (typically some resource
cleanup) and then rethrows the exception again:</p>
<div class="sourceCode" id="cb37"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb37-1"><a href="https://well-typed.com/blog/rss2.xml#cb37-1" tabindex="-1"/><span class="ot">onException ::</span> <span class="dt">IO</span> a <span class="ot">-&gt;</span> <span class="dt">IO</span> b <span class="ot">-&gt;</span> <span class="dt">IO</span> a</span>
<span id="cb37-2"><a href="https://well-typed.com/blog/rss2.xml#cb37-2" tabindex="-1"/>onException io what <span class="ot">=</span> io <span class="ot">`catch`</span> \e <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb37-3"><a href="https://well-typed.com/blog/rss2.xml#cb37-3" tabindex="-1"/>    _ <span class="ot">&lt;-</span> what</span>
<span id="cb37-4"><a href="https://well-typed.com/blog/rss2.xml#cb37-4" tabindex="-1"/>    throwIO (<span class="ot">e ::</span> <span class="dt">SomeException</span>)</span></code></pre></div>
<p>As written, this is suboptimal: for every layer of <code>onException</code>, we re-throw
the annotation stripped from its original annotations (due to <code>throwIO</code> and
<code>toException</code> for <code>SomeException</code>), and with a new <code>WhileHandling</code> annotation
with the original exception (due to <code>catch</code>). This result in unnecessary noise:
all the information is still there, but it’s buried. When we <em>rethrow</em> the same
exception, there is no need for <code>WhileHanding</code>: we should just throw the
original exception as-is.</p>
<p>To solve this, <code>base</code> now offers new functions specifically to
catch-and-rethrow: <code>catchNoPropagate</code><a class="footnote-ref" href="https://well-typed.com/blog/rss2.xml#fn2" id="fnref2"><sup>2</sup></a> is like the old <code>catch</code>, without
the handler that adds the <code>WhileHandling</code> annotation; and <code>rethrowIO</code>, which
avoids adding a backtrace (using <a href="https://well-typed.com/blog/rss2.xml#nobacktrace"><code>NoBacktrace</code></a>; moreover, both
of these explicitly preserve contexts (using
<a href="https://well-typed.com/blog/exceptionwithcontext"><code>ExceptionWithContext</code></a>):</p>
<div class="sourceCode" id="cb38"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb38-1"><a href="https://well-typed.com/blog/rss2.xml#cb38-1" tabindex="-1"/><span class="ot">catchNoPropagate ::</span> <span class="dt">Exception</span> e <span class="ot">=&gt;</span> <span class="dt">IO</span> a <span class="ot">-&gt;</span> (<span class="dt">ExceptionWithContext</span> e <span class="ot">-&gt;</span> <span class="dt">IO</span> a) <span class="ot">-&gt;</span> <span class="dt">IO</span> a</span>
<span id="cb38-2"><a href="https://well-typed.com/blog/rss2.xml#cb38-2" tabindex="-1"/>catchNoPropagate (<span class="dt">IO</span> io) handler <span class="ot">=</span> <span class="dt">IO</span> <span class="op">$</span> PrimOp.catch<span class="op">#</span> io handler'</span>
<span id="cb38-3"><a href="https://well-typed.com/blog/rss2.xml#cb38-3" tabindex="-1"/>  <span class="kw">where</span></span>
<span id="cb38-4"><a href="https://well-typed.com/blog/rss2.xml#cb38-4" tabindex="-1"/>    handler' se <span class="ot">=</span></span>
<span id="cb38-5"><a href="https://well-typed.com/blog/rss2.xml#cb38-5" tabindex="-1"/>      <span class="kw">case</span> fromException se <span class="kw">of</span></span>
<span id="cb38-6"><a href="https://well-typed.com/blog/rss2.xml#cb38-6" tabindex="-1"/>        <span class="dt">Just</span> e' <span class="ot">-&gt;</span> unIO (handler e')</span>
<span id="cb38-7"><a href="https://well-typed.com/blog/rss2.xml#cb38-7" tabindex="-1"/>        <span class="dt">Nothing</span> <span class="ot">-&gt;</span> PrimOp.raiseIO<span class="op">#</span> se</span>
<span id="cb38-8"><a href="https://well-typed.com/blog/rss2.xml#cb38-8" tabindex="-1"/></span>
<span id="cb38-9"><a href="https://well-typed.com/blog/rss2.xml#cb38-9" tabindex="-1"/><span class="ot">rethrowIO ::</span> <span class="dt">Exception</span> e <span class="ot">=&gt;</span> <span class="dt">ExceptionWithContext</span> e <span class="ot">-&gt;</span> <span class="dt">IO</span> a</span>
<span id="cb38-10"><a href="https://well-typed.com/blog/rss2.xml#cb38-10" tabindex="-1"/>rethrowIO e <span class="ot">=</span> throwIO (<span class="dt">NoBacktrace</span> e)</span></code></pre></div>
<p>This then enables the following improved implementation of <code>onException</code>:</p>
<div class="sourceCode" id="cb39"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb39-1"><a href="https://well-typed.com/blog/rss2.xml#cb39-1" tabindex="-1"/><span class="ot">onException ::</span> <span class="dt">IO</span> a <span class="ot">-&gt;</span> <span class="dt">IO</span> b <span class="ot">-&gt;</span> <span class="dt">IO</span> a</span>
<span id="cb39-2"><a href="https://well-typed.com/blog/rss2.xml#cb39-2" tabindex="-1"/>onException io what <span class="ot">=</span> io <span class="ot">`catchNoPropagate`</span> \e <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb39-3"><a href="https://well-typed.com/blog/rss2.xml#cb39-3" tabindex="-1"/>    _ <span class="ot">&lt;-</span> what</span>
<span id="cb39-4"><a href="https://well-typed.com/blog/rss2.xml#cb39-4" tabindex="-1"/>    rethrowIO (<span class="ot">e ::</span> <span class="dt">ExceptionWithContext</span> <span class="dt">SomeException</span>)</span></code></pre></div>
<h2 id="caution-displaying-exceptions">⚠️ Caution: Displaying exceptions</h2>
<p>The final pitfall we need to discuss is <em>displaying</em> exceptions. Usually we call
<code>displayException</code> to do so, but this does <em>not</em> show annotations. The idea is
that <code>displayException</code> is meant to render an exception for <em>users</em>, not
necessarily <em>developers</em>.<a class="footnote-ref" href="https://well-typed.com/blog/rss2.xml#fn3" id="fnref3"><sup>3</sup></a> Starting withGHC 9.14 there is a separate function
<a href="https://hackage-content.haskell.org/package/base-4.22.0.0/docs/Control-Exception.html#v:displayExceptionWithInfo"><code>displayExceptionWithInfo</code></a>, but that is not
available in GHC 9.12; moreover, even in GHC 9.14 I would advise against using
it when you are debugging, as <em>it only shows the top-level annotations</em>, making
things like <a href="https://well-typed.com/blog/rss2.xml#catch"><code>WhileHandling</code></a> much less useful.</p>
<p>Personally, I like to use my own custom exception handler which shows the full
exception, and makes a few other improvements also: it makes the nesting
structure clearer, and reorders annotations to improve readability; you can find
an example implementation <a href="https://gist.github.com/edsko/49cc535d712048f6cac532e8a02ea374">on GitHub</a> .</p>
<h2 id="ghc-9.10">GHC 9.10</h2>
<p>If you cannot upgrade from GHC 9.10, unfortunately the exception annotation
infrastructure has some important limitations. Upgrade if you can; if not, this
section will explain what you need to be aware of.</p>
<h3 id="lost-annotations">Lost annotations</h3>
<p>As we remarked <a href="https://well-typed.com/blog/rss2.xml#catch">when we discussed <code>catch</code></a>, the <code>WhileHandling</code> proposal
only got implemented in GHC 9.12. In GHC 9.10 the definition of <code>catch</code> was still
unchanged from its definition before the exception annotation proposal:</p>
<div class="sourceCode" id="cb40"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb40-1"><a href="https://well-typed.com/blog/rss2.xml#cb40-1" tabindex="-1"/><span class="fu">catch</span><span class="ot"> ::</span> <span class="dt">Exception</span> e <span class="ot">=&gt;</span> <span class="dt">IO</span> a <span class="ot">-&gt;</span> (e <span class="ot">-&gt;</span> <span class="dt">IO</span> a) <span class="ot">-&gt;</span> <span class="dt">IO</span> a</span>
<span id="cb40-2"><a href="https://well-typed.com/blog/rss2.xml#cb40-2" tabindex="-1"/><span class="fu">catch</span> (<span class="dt">IO</span> io) handler <span class="ot">=</span> <span class="dt">IO</span> <span class="op">$</span> PrimOp.catch<span class="op">#</span> io handler'</span>
<span id="cb40-3"><a href="https://well-typed.com/blog/rss2.xml#cb40-3" tabindex="-1"/>  <span class="kw">where</span></span>
<span id="cb40-4"><a href="https://well-typed.com/blog/rss2.xml#cb40-4" tabindex="-1"/>    handler' se <span class="ot">=</span></span>
<span id="cb40-5"><a href="https://well-typed.com/blog/rss2.xml#cb40-5" tabindex="-1"/>      <span class="kw">case</span> fromException se <span class="kw">of</span></span>
<span id="cb40-6"><a href="https://well-typed.com/blog/rss2.xml#cb40-6" tabindex="-1"/>        <span class="dt">Just</span> e' <span class="ot">-&gt;</span> unIO (handler e')</span>
<span id="cb40-7"><a href="https://well-typed.com/blog/rss2.xml#cb40-7" tabindex="-1"/>        <span class="dt">Nothing</span> <span class="ot">-&gt;</span> PrimOp.raiseIO<span class="op">#</span> se</span></code></pre></div>
<p>However, the
<a href="https://well-typed.com/blog/rss2.xml#caution-instance-for-someexception-itself"><code>Exception</code> instance for <code>SomeException</code></a>
<em>was</em> already changed, so that <code>toException</code> clears the exception context.
This means that if an exception with annotations is <em>ever</em> caught and rethrown
anywhere, in a pattern such as</p>
<div class="sourceCode" id="cb41"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb41-1"><a href="https://well-typed.com/blog/rss2.xml#cb41-1" tabindex="-1"/>someAction <span class="ot">`catch`</span> \(<span class="ot">e ::</span> <span class="dt">SomeException</span>) <span class="ot">-&gt;</span> throwIO e</span></code></pre></div>
<p>those annotations will be lost. Similarly, since <code>onException</code> had not yet been
changed either, any call to <code>onException</code>, and by implification<code>bracket</code>,
anywhere in your callstack would also lose any annotations:</p>
<div class="sourceCode" id="cb42"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb42-1"><a href="https://well-typed.com/blog/rss2.xml#cb42-1" tabindex="-1"/><span class="ot">bracket ::</span> <span class="dt">IO</span> a <span class="ot">-&gt;</span> (a <span class="ot">-&gt;</span> <span class="dt">IO</span> b) <span class="ot">-&gt;</span> (a <span class="ot">-&gt;</span> <span class="dt">IO</span> c) <span class="ot">-&gt;</span> <span class="dt">IO</span> c</span>
<span id="cb42-2"><a href="https://well-typed.com/blog/rss2.xml#cb42-2" tabindex="-1"/>bracket before after thing <span class="ot">=</span></span>
<span id="cb42-3"><a href="https://well-typed.com/blog/rss2.xml#cb42-3" tabindex="-1"/>    mask <span class="op">$</span> \restore <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb42-4"><a href="https://well-typed.com/blog/rss2.xml#cb42-4" tabindex="-1"/>      a <span class="ot">&lt;-</span> before</span>
<span id="cb42-5"><a href="https://well-typed.com/blog/rss2.xml#cb42-5" tabindex="-1"/>      r <span class="ot">&lt;-</span> restore (thing a) <span class="ot">`onException`</span> after a</span>
<span id="cb42-6"><a href="https://well-typed.com/blog/rss2.xml#cb42-6" tabindex="-1"/>      _ <span class="ot">&lt;-</span> after a</span>
<span id="cb42-7"><a href="https://well-typed.com/blog/rss2.xml#cb42-7" tabindex="-1"/>      <span class="fu">return</span> r</span>
<span id="cb42-8"><a href="https://well-typed.com/blog/rss2.xml#cb42-8" tabindex="-1"/></span>
<span id="cb42-9"><a href="https://well-typed.com/blog/rss2.xml#cb42-9" tabindex="-1"/><span class="ot">onException ::</span> <span class="dt">IO</span> a <span class="ot">-&gt;</span> <span class="dt">IO</span> b <span class="ot">-&gt;</span> <span class="dt">IO</span> a</span>
<span id="cb42-10"><a href="https://well-typed.com/blog/rss2.xml#cb42-10" tabindex="-1"/>onException io what <span class="ot">=</span> io <span class="ot">`catch`</span> \e <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb42-11"><a href="https://well-typed.com/blog/rss2.xml#cb42-11" tabindex="-1"/>    _ <span class="ot">&lt;-</span> what</span>
<span id="cb42-12"><a href="https://well-typed.com/blog/rss2.xml#cb42-12" tabindex="-1"/>    throwIO (<span class="ot">e ::</span> <span class="dt">SomeException</span>)</span></code></pre></div>
<p>In both cases, <code>throwIO</code> <em>will</em> insert a new backtrace, but that backtrace will
point to where the exception was <em>rethrown</em>, not to where it was thrown
originally. What’s worse, neither <code>bracket</code> nor <code>onException</code> have a
<code>HasCallStack</code> constraint, so all we see in the callstack is the call to
<code>throwIO</code> from <code>onException</code> itself.</p>
<p>Cost centre stacks do help a bit here (provided you enable profiling): at least
you’ll get to see the full backtrace to the exception handler, and with a bit of
luck even to the original call to throw, due to the semantics of <a href="https://well-typed.com/blog/rss2.xml#cost-centres-vs-exception-handling">semantics of
cost centres in exception handlers</a>. That
won’t always be the case though (for example, in the case of asynchronous
exceptions), and you won’t see any of the additional annotations that might have
been added to the exception.</p>
<h3 id="duplicated-annotations">Duplicated annotations</h3>
<p>The <code>Exception</code> instance for <code>ExceptionWithContext</code> in GHC 9.10 has an
incorrect definition for <code>toException</code>:</p>
<div class="sourceCode" id="cb43"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb43-1"><a href="https://well-typed.com/blog/rss2.xml#cb43-1" tabindex="-1"/><span class="kw">instance</span> <span class="dt">Exception</span> a <span class="ot">=&gt;</span> <span class="dt">Exception</span> (<span class="dt">ExceptionWithContext</span> a) <span class="kw">where</span></span>
<span id="cb43-2"><a href="https://well-typed.com/blog/rss2.xml#cb43-2" tabindex="-1"/>  <span class="co">-- (..)</span></span>
<span id="cb43-3"><a href="https://well-typed.com/blog/rss2.xml#cb43-3" tabindex="-1"/></span>
<span id="cb43-4"><a href="https://well-typed.com/blog/rss2.xml#cb43-4" tabindex="-1"/>  <span class="co">-- implementation in GHC 9.10</span></span>
<span id="cb43-5"><a href="https://well-typed.com/blog/rss2.xml#cb43-5" tabindex="-1"/>  toException (<span class="dt">ExceptionWithContext</span> ctxt e) <span class="ot">=</span></span>
<span id="cb43-6"><a href="https://well-typed.com/blog/rss2.xml#cb43-6" tabindex="-1"/>      <span class="kw">let</span> <span class="op">?</span>exceptionContext <span class="ot">=</span> ctxt <span class="kw">in</span> <span class="dt">SomeException</span> e</span></code></pre></div>
<p>(We saw <a href="https://well-typed.com/blog/rss2.xml#exceptionwithcontext">the correct definition</a> above.)</p>
<p>This is wrong for two reasons:</p>
<ol type="1">
<li>It does not use <code>toException</code> of the underlying type (the <code>a</code> type
parameter); in <em>most</em> cases this does not matter, because <code>toException</code>
rarely does anything interesting. Even in the case of <code>SomeException</code>, where
<code>toException</code> does something “interesting” (if perhaps ill-advised), to wit
clear the exception context, that doesn’t matter here because we are
overriding that context <em>anyway</em>. However, there <em>might</em> be types where
<code>toException</code> genuinely does something important (even if I am not aware of
any such cases currently).</li>
<li>In the specific case that <code>a</code> <em>is</em> <code>SomeException</code>, this will create a
<em>nested</em> <code>SomeException</code>: <code>SomeException (SomeException someOtherException)</code>
with two copies of the context (the annotations).</li>
</ol>
<p>The second point here is more important: if we later have exception handlers
that manipulate the exception context, they will manipulate the outer context
but not the inner. Indeed, if that “manipulation” is “<em>clear</em> the context”
(see previous section), we might end up in the somewhat bizarre situation
where these two problems cancel out: if we have</p>
<div class="sourceCode" id="cb44"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb44-1"><a href="https://well-typed.com/blog/rss2.xml#cb44-1" tabindex="-1"/>someAction <span class="ot">`catch`</span> \(<span class="dt">ExceptionWithContext</span> ctxt (<span class="ot">e ::</span> <span class="dt">SomeException</span>))</span>
<span id="cb44-2"><a href="https://well-typed.com/blog/rss2.xml#cb44-2" tabindex="-1"/>  throwIO <span class="op">$</span> <span class="dt">ExceptionWithContext</span> ctxt e</span></code></pre></div>
<p>then this exception handler will duplicate the annotations, a later exception
handler might lose the outermost annotations (previous section) but not the
inner, and all of a sudden annotations that were lost mysteriously re-appear;
see GHC ticket <a href="https://gitlab.haskell.org/ghc/ghc/-/issues/27194">#27194</a>.</p>
<p>Unfortunately, this is not a viable workaround for the lost annotation problem,
as it changes the type of the exception nested in the (outer) <code>SomeException</code>
from whatever it really should have been to (the inner) <code>SomeException</code>, which
will break any exception handlers for that specific type.</p>
<h2 id="ghc-10.0">GHC 10.0</h2>
<p>The upcoming GHC 10.0 releases makes a few improvements to the exception
annotation infrastructure. The first important improvement is that exception
handling in <em>STM</em> was lagging behind a bit; this will be rectified
(<a href="https://gitlab.haskell.org/ghc/ghc/-/issues/25365">#25365</a>).</p>
<p>The other important fix is in <code>onException</code>. Consider again the definition
we saw <a href="https://well-typed.com/blog/rss2.xml#caution-rethrowing-the-same-exception">when we discussed rethrowing exceptions</a>:</p>
<div class="sourceCode" id="cb45"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb45-1"><a href="https://well-typed.com/blog/rss2.xml#cb45-1" tabindex="-1"/><span class="ot">onException ::</span> <span class="dt">IO</span> a <span class="ot">-&gt;</span> <span class="dt">IO</span> b <span class="ot">-&gt;</span> <span class="dt">IO</span> a</span>
<span id="cb45-2"><a href="https://well-typed.com/blog/rss2.xml#cb45-2" tabindex="-1"/>onException io what <span class="ot">=</span> io <span class="ot">`catchNoPropagate`</span> \e <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb45-3"><a href="https://well-typed.com/blog/rss2.xml#cb45-3" tabindex="-1"/>    _ <span class="ot">&lt;-</span> what</span>
<span id="cb45-4"><a href="https://well-typed.com/blog/rss2.xml#cb45-4" tabindex="-1"/>    rethrowIO (<span class="ot">e ::</span> <span class="dt">ExceptionWithContext</span> <span class="dt">SomeException</span>)</span></code></pre></div>
<p>We mentioned that that <code>catchNoPropagate</code> does <em>not</em> install an exception
handler that installs a <code>WhileHandling</code> annotation, because we are rethrowing
the very same exception. However, if <code>what</code> throws an exception that is no
longer the case! The definition of <code>onException</code> is therefore modified to</p>
<div class="sourceCode" id="cb46"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb46-1"><a href="https://well-typed.com/blog/rss2.xml#cb46-1" tabindex="-1"/>onException io what <span class="ot">=</span> io <span class="ot">`catchNoPropagate`</span> \e <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb46-2"><a href="https://well-typed.com/blog/rss2.xml#cb46-2" tabindex="-1"/>    _ <span class="ot">&lt;-</span> annotateIO (whileHandling e) what</span>
<span id="cb46-3"><a href="https://well-typed.com/blog/rss2.xml#cb46-3" tabindex="-1"/>    rethrowIO (<span class="ot">e ::</span> <span class="dt">ExceptionWithContext</span> <span class="dt">SomeException</span>)</span></code></pre></div>
<p>See <a href="https://github.com/haskell/core-libraries-committee/issues/397">CLC Proposal #397</a> for details. As an example, consider what happens if the release callback
of <code>bracket</code> itself throws an exception:</p>
<div class="sourceCode" id="cb47"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb47-1"><a href="https://well-typed.com/blog/rss2.xml#cb47-1" tabindex="-1"/><span class="kw">data</span> <span class="dt">ReleaseFailed</span> <span class="ot">=</span> <span class="dt">ReleaseFailed</span></span>
<span id="cb47-2"><a href="https://well-typed.com/blog/rss2.xml#cb47-2" tabindex="-1"/>  <span class="kw">deriving</span> stock (<span class="dt">Show</span>)</span>
<span id="cb47-3"><a href="https://well-typed.com/blog/rss2.xml#cb47-3" tabindex="-1"/>  <span class="kw">deriving</span> anyclass (<span class="dt">Exception</span>)</span>
<span id="cb47-4"><a href="https://well-typed.com/blog/rss2.xml#cb47-4" tabindex="-1"/></span>
<span id="cb47-5"><a href="https://well-typed.com/blog/rss2.xml#cb47-5" tabindex="-1"/><span class="ot">bottom ::</span> <span class="dt">HasCallStack</span> <span class="ot">=&gt;</span> <span class="dt">IO</span> ()</span>
<span id="cb47-6"><a href="https://well-typed.com/blog/rss2.xml#cb47-6" tabindex="-1"/>bottom <span class="ot">=</span> annotateIO (<span class="dt">MyAnnotation</span> <span class="dv">123456789</span>) <span class="op">$</span> throwIO <span class="dt">MyException</span></span>
<span id="cb47-7"><a href="https://well-typed.com/blog/rss2.xml#cb47-7" tabindex="-1"/></span>
<span id="cb47-8"><a href="https://well-typed.com/blog/rss2.xml#cb47-8" tabindex="-1"/><span class="ot">middle ::</span> <span class="dt">HasCallStack</span> <span class="ot">=&gt;</span> <span class="dt">IO</span> ()</span>
<span id="cb47-9"><a href="https://well-typed.com/blog/rss2.xml#cb47-9" tabindex="-1"/>middle <span class="ot">=</span> bracket (<span class="fu">return</span> ()) (\() <span class="ot">-&gt;</span> throwIO <span class="dt">ReleaseFailed</span>) <span class="op">$</span> \() <span class="ot">-&gt;</span> bottom</span>
<span id="cb47-10"><a href="https://well-typed.com/blog/rss2.xml#cb47-10" tabindex="-1"/></span>
<span id="cb47-11"><a href="https://well-typed.com/blog/rss2.xml#cb47-11" tabindex="-1"/><span class="ot">top ::</span> <span class="dt">HasCallStack</span> <span class="ot">=&gt;</span> <span class="dt">IO</span> ()</span>
<span id="cb47-12"><a href="https://well-typed.com/blog/rss2.xml#cb47-12" tabindex="-1"/>top <span class="ot">=</span> middle</span></code></pre></div>
<p>With the new definition <code>onException</code> (and my custom exception display function, which is still needed), we get</p>
<pre><code>demo-bracket-release-fail: Uncaught exception of type ReleaseFailed
  ReleaseFailed
  HasCallStack backtrace:
    throwIO, called at exe/DemoBracketReleaseFail.hs:42:38 in (..)
    middle, called at exe/DemoBracketReleaseFail.hs:46:7 in (..)
    top, called at exe/DemoBracketReleaseFail.hs:55:5 in (..)
  WhileHandling
    MyException
      MyException
      MyAnnotation 123456789
      HasCallStack backtrace:
        throwIO, called at exe/DemoBracketReleaseFail.hs:38:48 in (..)
        bottom, called at exe/DemoBracketReleaseFail.hs:42:70 in (..)
        middle, called at exe/DemoBracketReleaseFail.hs:46:7 in (..)
        top, called at exe/DemoBracketReleaseFail.hs:55:5 in (..)</code></pre>
<p>Very nice!</p>
<h2 id="conclusions">Conclusions</h2>
<p>Exception annotations can be invaluable when debugging difficult problems. While
the initial implementation in GHC 9.10 had some important limitations, the
situation has since been much improved. Provided you use GHC 9.12 or later,
there are two things to pay attention to in your own code (these apply to 9.12,
9.14 and 10.0):</p>
<ul>
<li>Define your own custom function to display exceptions, which shows <em>all</em>
annotations, not just the top-level ones (or use <a href="https://gist.github.com/edsko/49cc535d712048f6cac532e8a02ea374">mine</a>).</li>
<li>Be cautious with throwing <code>SomeException</code>: <code>toException</code> for <code>SomeException</code>
will clear the exception context, which is almost certainly not what you want.
For catch-and-rethrow, use the <a href="https://well-typed.com/blog/rss2.xml#caution-rethrowing-the-same-exception">combinators available specifically for that
purpose</a>.</li>
</ul>
<p>That said, there are still a few minor shortcomings to be aware of:</p>
<ul>
<li><p><strong>GHC 9.12 and 9.14</strong>:</p>
<ul>
<li>Exception handling <em>in STM</em> has not yet been updated: <code>throwSTM</code> does not
collect a backtrace, and <code>catchSTM</code> does not add any <code>WhileHandling</code>
annotations (<a href="https://gitlab.haskell.org/ghc/ghc/-/issues/25365">#25365</a>).</li>
<li><code>onException</code> does not add any <code>WhileHandling</code> exceptions; as a result, if
the resource deallocation callback to <code>bracket</code> <em>itself</em> throws an
exception, the original exception will be lost.</li>
</ul>
<p>Both of these will be addressed in GHC 10.0.</p></li>
<li><p><strong>exceptions-0.10.9</strong>: this is the version of <code>exceptions</code> that is bundled
with GHC 9.12, but lags behind a bit. For example, the definition
of <code>generalBracket</code> in <a href="https://hackage.haskell.org/package/exceptions-0.10.9/docs/src/Control.Monad.Catch.html#generalBracket"><code>exceptions-0.10.9</code></a>
does not use any of the abstractions for rethrowing; this is fixed in
<a href="https://hackage-content.haskell.org/package/exceptions-0.10.12/docs/src/Control.Monad.Catch.html#generalBracket"><code>exceptions-0.10.12</code></a>.
The impact is however limited: it merely means that there are some extraneous
<code>WhileHandling</code> annotations, resulting in unnecessary noise.</p></li>
<li><p>Any catch-and-rethrow patterns implemented in other packages <em>should</em> not
lose any annotations, provided that they use <code>catch</code> from <code>base</code>.</p></li>
</ul>

<section class="footnotes footnotes-end-of-document" id="footnotes">
<hr/>
<ol>
<li id="fn1"><p>We will ignore calls to <code>withFrozenCallStack</code>, which hide some internal
functions from the <code>HasCallStack</code> backtrace. This makes the backtrace slightly
more readable, but does not otherwise change anything. See
<a href="https://github.com/haskell/core-libraries-committee/issues/387">CLC #387</a>.<a class="footnote-back" href="https://well-typed.com/blog/rss2.xml#fnref1">↩︎</a></p></li>
<li id="fn2"><p>Some versions of <code>base</code> distinguish
between <code>catchExceptionNoPropagate</code> and <code>catchNoPropagate</code>, which differ only in
some strictness annotations. Strictness can make a big difference, especially
when IO actions are <code>undefined</code> rather than throwing an exception. However, this
is its own can of worms, and outside the scope of this blog post. See <a href="https://github.com/haskell/core-libraries-committee/issues/383">CLC
proposal #383</a> for some discussion.<a class="footnote-back" href="https://well-typed.com/blog/rss2.xml#fnref2">↩︎</a></p></li>
<li id="fn3"><p>In GHC 9.10, <code>displayException</code> <em>did</em> show
annotaitons, but this got rolled back in 9.12; see <a href="https://github.com/haskell/core-libraries-committee/issues/285">CLC #285</a> for a
detailed discussion.<a class="footnote-back" href="https://well-typed.com/blog/rss2.xml#fnref3">↩︎</a></p></li>
</ol>
</section></div>
    </content>
    <updated>2026-05-08T00:00:00Z</updated>
    <published>2026-05-08T00:00:00Z</published>
    <category term="coding"/>
    <category term="exceptions"/>
    <author>
      <name>edsko</name>
    </author>
    <source>
      <id>https://well-typed.com/blog/</id>
      <logo>https://well-typed.com/img/wtnlogoplain.svg</logo>
      <link href="https://well-typed.com/blog/rss2.xml" rel="self" type="application/rss+xml"/>
      <link href="https://well-typed.com/blog/" rel="alternate" type="text/html"/>
      <subtitle>Because Well-Typed Programs Don't Go Wrong</subtitle>
      <title>Well-Typed Blog</title>
      <updated>2026-05-28T00:00:00Z</updated>
    </source>
  </entry>

  <entry>
    <id>https://oleg.fi/gists/posts/2026-05-07-compatibility-packages-b.html</id>
    <link href="https://oleg.fi/gists/posts/2026-05-07-compatibility-packages-b.html" rel="alternate" type="text/html"/>
    <title>Compatibility packages in 2026</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><div class="info">
    Posted on 2026-05-07
    
        by Oleg Grenrus
    

    <a href="https://oleg.fi/tags/engineering.html" title="All pages tagged 'engineering'.">engineering</a>
</div>

<p>Seven years ago I wrote a post about compatibility packages. It is now highly outdated, so let us revisit the matter.</p>
<p>Recently there have been a small push towards <a href="https://github.com/well-typed/reinstallable-base">reinstallable base</a>. While it's still far from being a thing, it made me remember that using <code>impl(ghc &gt;= 7.9)</code>-like conditionals to guard against different <code>base</code> versions is semantically wrong.</p>
<p>Also recently there is increasing? interest in <a href="https://github.com/augustss/MicroHs">MicroHs</a>. While I personally don't care about that compiler, I realized that I can make its users experience at least slightly nicer though still somewhat ignoring MicroHs existence.</p>
<h2 id="an-example">An example</h2>
<p>Luckily there is a solution, and it was around for a long time: <em>automatic flags</em>. Here is a complete example:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode cabal"><code class="sourceCode cabal"><span id="cb1-1"><a href="https://oleg.fi/gists/atom.xml#cb1-1"/><span class="kw">flag</span> base-ge-4-16</span>
<span id="cb1-2"><a href="https://oleg.fi/gists/atom.xml#cb1-2"/>  <span class="dt">description:</span> @base <span class="dv">&gt;=4.16</span>@ (GHC-9.2)</span>
<span id="cb1-3"><a href="https://oleg.fi/gists/atom.xml#cb1-3"/>  <span class="dt">default:</span>     True</span>
<span id="cb1-4"><a href="https://oleg.fi/gists/atom.xml#cb1-4"/>  <span class="dt">manual:</span>      False</span>
<span id="cb1-5"><a href="https://oleg.fi/gists/atom.xml#cb1-5"/></span>
<span id="cb1-6"><a href="https://oleg.fi/gists/atom.xml#cb1-6"/><span class="kw">flag</span> base-ge-4-17</span>
<span id="cb1-7"><a href="https://oleg.fi/gists/atom.xml#cb1-7"/>  <span class="dt">description:</span> @base <span class="dv">&gt;=4.17</span>@ (GHC-9.4)</span>
<span id="cb1-8"><a href="https://oleg.fi/gists/atom.xml#cb1-8"/>  <span class="dt">default:</span>     True</span>
<span id="cb1-9"><a href="https://oleg.fi/gists/atom.xml#cb1-9"/>  <span class="dt">manual:</span>      False</span>
<span id="cb1-10"><a href="https://oleg.fi/gists/atom.xml#cb1-10"/></span>
<span id="cb1-11"><a href="https://oleg.fi/gists/atom.xml#cb1-11"/><span class="kw">library</span></span>
<span id="cb1-12"><a href="https://oleg.fi/gists/atom.xml#cb1-12"/>  ...</span>
<span id="cb1-13"><a href="https://oleg.fi/gists/atom.xml#cb1-13"/>  <span class="dt">build-depends:</span></span>
<span id="cb1-14"><a href="https://oleg.fi/gists/atom.xml#cb1-14"/>      base    <span class="dv">&gt;=4.12.0.0</span> <span class="ot">&amp;&amp;</span> <span class="dv">&lt;4.23</span></span>
<span id="cb1-15"><a href="https://oleg.fi/gists/atom.xml#cb1-15"/></span>
<span id="cb1-16"><a href="https://oleg.fi/gists/atom.xml#cb1-16"/>  <span class="kw">if</span> <span class="ot">!</span>flag(base-ge-4-16)</span>
<span id="cb1-17"><a href="https://oleg.fi/gists/atom.xml#cb1-17"/>    <span class="dt">build-depends:</span> OneTuple <span class="dv">&gt;=0.4.2</span> <span class="ot">&amp;&amp;</span> <span class="dv">&lt;0.5</span></span>
<span id="cb1-18"><a href="https://oleg.fi/gists/atom.xml#cb1-18"/></span>
<span id="cb1-19"><a href="https://oleg.fi/gists/atom.xml#cb1-19"/>  <span class="kw">if</span> <span class="ot">!</span>flag(base-ge-4-17)</span>
<span id="cb1-20"><a href="https://oleg.fi/gists/atom.xml#cb1-20"/>    <span class="dt">build-depends:</span> data-array-byte <span class="dv">&gt;=0.1.0.1</span> <span class="ot">&amp;&amp;</span> <span class="dv">&lt;0.2</span></span>
<span id="cb1-21"><a href="https://oleg.fi/gists/atom.xml#cb1-21"/></span>
<span id="cb1-22"><a href="https://oleg.fi/gists/atom.xml#cb1-22"/>  <span class="kw">if</span> flag(base-ge-4-16)</span>
<span id="cb1-23"><a href="https://oleg.fi/gists/atom.xml#cb1-23"/>    <span class="dt">build-depends:</span> base <span class="dv">&gt;=4.16</span></span>
<span id="cb1-24"><a href="https://oleg.fi/gists/atom.xml#cb1-24"/>  <span class="kw">else</span></span>
<span id="cb1-25"><a href="https://oleg.fi/gists/atom.xml#cb1-25"/>    <span class="dt">build-depends:</span> base <span class="dv">&lt;4.16</span></span>
<span id="cb1-26"><a href="https://oleg.fi/gists/atom.xml#cb1-26"/></span>
<span id="cb1-27"><a href="https://oleg.fi/gists/atom.xml#cb1-27"/>  <span class="kw">if</span> flag(base-ge-4-17)</span>
<span id="cb1-28"><a href="https://oleg.fi/gists/atom.xml#cb1-28"/>    <span class="dt">build-depends:</span> base <span class="dv">&gt;=4.17</span></span>
<span id="cb1-29"><a href="https://oleg.fi/gists/atom.xml#cb1-29"/>  <span class="kw">else</span></span>
<span id="cb1-30"><a href="https://oleg.fi/gists/atom.xml#cb1-30"/>    <span class="dt">build-depends:</span> base <span class="dv">&lt;4.17</span></span></code></pre></div>
<p>First we declare the flags. I chose to use a naming scheme reminiscing the condition: <code>base-ge-4-17</code> for <code>base &gt;=4.17</code>.</p>
<p>Then we make the flag selection <em>deterministic</em>:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode cabal"><code class="sourceCode cabal"><span id="cb2-1"><a href="https://oleg.fi/gists/atom.xml#cb2-1"/>  <span class="kw">if</span> flag(base-ge-4-17)</span>
<span id="cb2-2"><a href="https://oleg.fi/gists/atom.xml#cb2-2"/>    <span class="dt">build-depends:</span> base <span class="dv">&gt;=4.17</span></span>
<span id="cb2-3"><a href="https://oleg.fi/gists/atom.xml#cb2-3"/>  <span class="kw">else</span></span>
<span id="cb2-4"><a href="https://oleg.fi/gists/atom.xml#cb2-4"/>    <span class="dt">build-depends:</span> base <span class="dv">&lt;4.17</span></span></code></pre></div>
<p>Because the <code>base &gt;=4.17</code> and <code>base &lt;4.17</code> conditions are disjoint, there is at most one valid flag assignment for any given install plan which includes <code>base</code> - but because <code>base</code> is a direct dependency it has to be in the install plan. This is why I call such flag deterministic<a class="footnote-ref" href="https://oleg.fi/gists/atom.xml#fn1" id="fnref1"><sup>1</sup></a>.</p>
<p>And finally we use the flag value to add a conditional dependency:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode cabal"><code class="sourceCode cabal"><span id="cb3-1"><a href="https://oleg.fi/gists/atom.xml#cb3-1"/>  <span class="kw">if</span> <span class="ot">!</span>flag(base-ge-4-17)</span>
<span id="cb3-2"><a href="https://oleg.fi/gists/atom.xml#cb3-2"/>    <span class="dt">build-depends:</span> data-array-byte <span class="dv">&gt;=0.1.0.1</span> <span class="ot">&amp;&amp;</span> <span class="dv">&lt;0.2</span></span></code></pre></div>
<p>Previously I would written</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode cabal"><code class="sourceCode cabal"><span id="cb4-1"><a href="https://oleg.fi/gists/atom.xml#cb4-1"/>  <span class="kw">if</span> <span class="ot">!</span><span class="dt">impl</span><span class="ot">(</span><span class="st">ghc</span> &gt;=9.4<span class="ot">)</span></span>
<span id="cb4-2"><a href="https://oleg.fi/gists/atom.xml#cb4-2"/>     <span class="dt">build-depends:</span> data-array-byte <span class="dv">&gt;=0.1.0.1</span> <span class="ot">&amp;&amp;</span> <span class="dv">&lt;0.2</span></span></code></pre></div>
<p>but as I mentioned in an introduction that is semantically wrong. In this case <code>Data.Array.Byte</code> module is introduced in <code>base-4.17</code>, which just happen to be available in GHC-9.4. In the future there might not be one-to-one correspondence between (major) GHC and <code>base</code> versions.</p>
<p>Moving to use automatic flags removes the direct mention of GHC. This also (hopefully) helps MicroHS users: we don't need to edit</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb5-1"><a href="https://oleg.fi/gists/atom.xml#cb5-1"/><span class="st">-  if !impl(ghc &gt;=9.4)</span></span>
<span id="cb5-2"><a href="https://oleg.fi/gists/atom.xml#cb5-2"/><span class="va">+  if !impl(ghc &gt;=9.4) &amp;&amp; !impl(mhs)</span></span></code></pre></div>
<p>as there are no direct mention of compilers. The library compatibility conditions are expressed using library version vocabulary.</p>
<h2 id="low-level-tools-for-high-level-concept">Low-level tools for high level concept</h2>
<p>It is worth mentioning that the three parts: defining the flag, making flag selection deterministic and using the flag value as a condition is indirect way to say something like</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb6-1"><a href="https://oleg.fi/gists/atom.xml#cb6-1"/><span class="kw">if</span> <span class="op">!</span>depends(base <span class="op">&gt;=</span><span class="fl">4.17</span>)</span>
<span id="cb6-2"><a href="https://oleg.fi/gists/atom.xml#cb6-2"/>  build<span class="op">-</span>depends<span class="op">:</span> <span class="kw">data</span><span class="op">-</span>array<span class="op">-</span>byte <span class="op">&gt;=</span><span class="fl">0.1</span><span class="op">.</span><span class="fl">0.1</span> <span class="op">&amp;&amp;</span> <span class="op">&lt;</span><span class="fl">0.2</span></span></code></pre></div>
<p>In other words we use "low-level" tools to express a high level concept.</p>
<p>Maybe some future version of <code>.cabal</code> format would include the high-level way directly. However, the low-level "desugaring" makes it impossible to scrutinize flag selection on indirect dependencies, e.g. we do add dependency to <code>base</code></p>
<div class="sourceCode" id="cb7"><pre class="sourceCode cabal"><code class="sourceCode cabal"><span id="cb7-1"><a href="https://oleg.fi/gists/atom.xml#cb7-1"/>  <span class="kw">if</span> flag(base-ge-4-17)</span>
<span id="cb7-2"><a href="https://oleg.fi/gists/atom.xml#cb7-2"/>    <span class="dt">build-depends:</span> base <span class="dv">&gt;=4.17</span></span>
<span id="cb7-3"><a href="https://oleg.fi/gists/atom.xml#cb7-3"/></span>
<span id="cb7-4"><a href="https://oleg.fi/gists/atom.xml#cb7-4"/>  <span class="kw">else</span></span>
<span id="cb7-5"><a href="https://oleg.fi/gists/atom.xml#cb7-5"/>    <span class="dt">build-depends:</span> base <span class="dv">&lt;4.17</span></span></code></pre></div>
<p>Viewing it from that perspective if a consturct like <code>depends(base &gt;=4.17)</code> is added to <code>.cabal</code> format, it should also add a constraint for install plan to include <code>base</code>, though not necessarily adding it direct dependency. That way the conditional will be deterministic. But such implicit dependency might feel unnatural.</p>
<h2 id="conclusion">Conclusion</h2>
<p>I already rewrote <code>impl(ghc)</code> conditionals to use automatic flags in few packages, and will continue to do that as I'm doing other maintenance tasks.</p>
<p>It seems that <code>OneTuple</code> and <code>data-array-byte</code> are the only few relevant compatibility packages at the moment (using GHC 9); there were a lot of compatibility packages in the last decade (<code>tagged</code>, <code>nats</code>, <code>void</code>, <code>fail</code>, <code>semigroups</code>, <code>bifunctors</code>, <code>contravariant</code>, <code>bifunctor-classes-compat</code>, <code>type-equality</code>, <code>foldable1-classes-compat</code>), but if you don't need to support very old <code>base</code>s &amp; GHCs, we don't need to depend on them for their compatibility shims anymore.</p>
<p>The library part of compatibility story is relatively good, even without having higher level construct like <code>if depends (lib &gt;= x.y)</code> construct. However, the compatibility of language level constructs is lacking. There is no way to ask in <code>.cabal</code> file whether compiler support <code>DeriveGeneric</code> or <code>TemplateHaskell</code>. We can <em>require</em> these extensions, but we cannot ask whether they exist at all. Neither we can differentiate between different versions. Is compiler's <code>ImpredicativeTypes</code> "broken" or not, does <code>LambdaCase</code> include <code>\cases</code> etc. Some part of me wishes the MicroHs a great success, so those issues become more pressing and eventually solved. Solved in some other ways than maintainers hardcoding compiler versions in the package definitions.</p>
<section class="footnotes">
<hr/>
<ol>
<li id="fn1"><p>In my opinion all automatic flags have to be deterministic. For example having <em>automatic</em> <code>debug</code> flag is IMO just wrong. There are also a bit edge cases related to <code>pkg-config</code>, and I think it's a "bug" in <code>.cabal</code> format that we cannot make <code>pkg-config</code> based library version selection deterministic.<a class="footnote-back" href="https://oleg.fi/gists/atom.xml#fnref1">↩︎</a></p></li>
</ol>
</section></div>
    </summary>
    <updated>2026-05-07T00:00:00Z</updated>
    <published>2026-05-07T00:00:00Z</published>
    <source>
      <id>https://oleg.fi/gists/atom.xml</id>
      <author>
        <name>Oleg Grenrus</name>
        <email>oleg.grenrus@iki.fi</email>
      </author>
      <link href="https://oleg.fi/gists/atom.xml" rel="self" type="application/atom+xml"/>
      <link href="https://oleg.fi/gists" rel="alternate" type="text/html"/>
      <title>Oleg's gists</title>
      <updated>2026-05-07T00:00:00Z</updated>
    </source>
  </entry>

  <entry xml:lang="en-us">
    <id>https://haskellforall.com/2026/05/a-bidirectional-typechecking-puzzle</id>
    <link href="https://haskellforall.com/2026/05/a-bidirectional-typechecking-puzzle" rel="alternate" type="text/html"/>
    <title>A bidirectional typechecking puzzle</title>
    <summary>Type inference challenges for real-world JSON</summary>
    <updated>2026-05-05T00:00:00Z</updated>
    <published>2026-05-05T00:00:00Z</published>
    <source>
      <id>https://haskellforall.com</id>
      <author>
        <name>Gabriella Gonzalez</name>
      </author>
      <link href="https://haskellforall.com" rel="alternate" type="text/html"/>
      <link href="https://haskellforall.com/rss.xml" rel="self" type="application/rss+xml"/>
      <subtitle>A blog about Haskell and functional programming.</subtitle>
      <title>Haskell for all</title>
      <updated>2026-06-07T13:45:09Z</updated>
    </source>
  </entry>

  <entry>
    <id>https://magnus.therning.org/2026-05-04-jumping-to-errors-in-evil.html</id>
    <link href="https://magnus.therning.org/2026-05-04-jumping-to-errors-in-evil.html" rel="alternate" type="text/html"/>
    <title>Jumping to errors in Evil</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>
Recently I realised that it'd be really nice if jumping to errors would store
the previous location in the Evil jump list. These definitions do just that
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><code><span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">evil-define-motion</span> <span class="org-function-name">mes/evil-goto-next-error</span> <span class="org-rainbow-delimiters-depth-2">(</span>count<span class="org-rainbow-delimiters-depth-2">)</span>
  <span class="org-builtin">:jump</span> t
  <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-keyword">unless</span> <span class="org-rainbow-delimiters-depth-3">(</span><span class="org-keyword">bound-and-true-p</span> flymake-mode<span class="org-rainbow-delimiters-depth-3">)</span> <span class="org-rainbow-delimiters-depth-3">(</span><span class="org-warning">signal</span> 'search-failed nil<span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span>
  <span class="org-rainbow-delimiters-depth-2">(</span>flymake-goto-next-error count<span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span>
<span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">evil-define-motion</span> <span class="org-function-name">mes/evil-goto-prev-error</span> <span class="org-rainbow-delimiters-depth-2">(</span>count<span class="org-rainbow-delimiters-depth-2">)</span>
  <span class="org-builtin">:jump</span> t
  <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-keyword">unless</span> <span class="org-rainbow-delimiters-depth-3">(</span><span class="org-keyword">bound-and-true-p</span> flymake-mode<span class="org-rainbow-delimiters-depth-3">)</span> <span class="org-rainbow-delimiters-depth-3">(</span><span class="org-warning">signal</span> 'search-failed nil<span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span>
  <span class="org-rainbow-delimiters-depth-2">(</span>flymake-goto-prev-error count<span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span>
</code></pre>
</div>

<p>
and for now I've bound them to <code>C-j</code> and <code>C-k</code> (because that's what
<a href="https://github.com/emacs-evil/evil-collection/blob/master/modes/flymake/evil-collection-flymake.el">evil-collection</a> does)
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><code><span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">general-def</span> flymake-mode-map
  <span class="org-builtin">:states</span> 'normal
  <span class="org-string">"C-j"</span> 'mes/evil-goto-next-error
  <span class="org-string">"C-k"</span> 'mes/evil-goto-prev-error<span class="org-rainbow-delimiters-depth-1">)</span>
</code></pre>
</div>

<p>
This makes it easier to make a change, fix the errors caused by the change and
then return to where I was.
</p>
<div class="taglist"><a href="https://magnus.therning.org/tags.html"><span class="tag-label">Tags</span></a><span class="tag-separator">: </span><span class="taglist__tags"><a class="tag" href="https://magnus.therning.org/tag-emacs.html">emacs</a> <a class="tag" href="https://magnus.therning.org/tag-evil.html">evil</a> </span></div></div>
    </summary>
    <updated>2026-05-04T06:16:00Z</updated>
    <published>2026-05-04T06:16:00Z</published>
    <category term="emacs"/>
    <category term="evil"/>
    <source>
      <id>https://magnus.therning.org/</id>
      <author>
        <name>Magnus Therning</name>
      </author>
      <link href="https://magnus.therning.org/" rel="alternate" type="text/html"/>
      <link href="https://magnus.therning.org/feed.xml" rel="self" type="application/rss+xml"/>
      <subtitle>Magnus web site</subtitle>
      <title>Magnus web site</title>
      <updated>2026-05-04T06:17:54Z</updated>
    </source>
  </entry>

  <entry>
    <id>https://magnus.therning.org/2026-05-02-follow-up-on-switching-to-eglot.html</id>
    <link href="https://magnus.therning.org/2026-05-02-follow-up-on-switching-to-eglot.html" rel="alternate" type="text/html"/>
    <title>Follow-up on switching to eglot</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>
Jan G sent me a two-part comment.
</p>
<div class="outline-2" id="outline-container-org3a78e0b">
<h2 id="org3a78e0b">Part one</h2>
<div class="outline-text-2" id="text-org3a78e0b">
<blockquote>
<p>
I was under the impression that when using elpaca you needed to disable
use-package, and that when using elpaca-use-package, you were redefining the
macro. Iâ€™m not 100% sure about this, but the documentation has an example of
use-package and how it actually expands to an elpaca command.
</p>
</blockquote>

<p>
I wouldn't know. All I can say is that it would be nice if package managers that
hook into, or completely redefines <code>use-package</code>, would document if they deviate
from the behaviour of "vanilla <code>use-package</code>" in some way.
</p>
</div>
</div>
<div class="outline-2" id="outline-container-orgac4cab1">
<h2 id="orgac4cab1">Part two</h2>
<div class="outline-text-2" id="text-orgac4cab1">
<blockquote>
<p>
Given that, use-packageâ€™s documentation is always going to be a little off,
since elpaca is doing everything async. The only way Iâ€™ve found to reliably
manage some dependencies is to use the elpaca-after-init hook, so they donâ€™t
even try to run until elpaca is finished loading everything.
</p>
</blockquote>

<p>
I'd say it sometimes seems like the documentation for <code>use-package</code> is a little
off for <code>use-package</code> itself ðŸ™‚
</p>

<p>
The README for Elpaca says that
</p>

<blockquote>
<p>
Add configuration which relies on after-init-hook, emacs-startup-hook, etc to
elpaca-after-init-hook so it runs after Elpaca has activated all queued
packages.
</p>
</blockquote>

<p>
but that seems like a very big hammer and as I understand it I'd have to move
the whole <code>:init</code> block for <code>python-mode</code> into the hook in that case. Playing
around with the various blocks for <code>use-package</code> isn't too time consuming and I
think it's a good first thing to try.
</p>
</div>
</div>
<div class="taglist"><a href="https://magnus.therning.org/tags.html">Tags</a>: <a href="https://magnus.therning.org/tag-emacs.html">emacs</a> </div></div>
    </summary>
    <updated>2026-05-02T11:20:00Z</updated>
    <published>2026-05-02T11:20:00Z</published>
    <category term="emacs"/>
    <source>
      <id>https://magnus.therning.org/</id>
      <author>
        <name>Magnus Therning</name>
      </author>
      <link href="https://magnus.therning.org/" rel="alternate" type="text/html"/>
      <link href="https://magnus.therning.org/feed.xml" rel="self" type="application/rss+xml"/>
      <subtitle>Magnus web site</subtitle>
      <title>Magnus web site</title>
      <updated>2026-05-04T06:17:54Z</updated>
    </source>
  </entry>

  <entry>
    <id>https://magnus.therning.org/2026-05-02-secrets-when-connecting-to-dbs.html</id>
    <link href="https://magnus.therning.org/2026-05-02-secrets-when-connecting-to-dbs.html" rel="alternate" type="text/html"/>
    <title>Secrets when connecting to DBs</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>
I should have dealt with comments I got to my posts on how I deal with secrets
in my work notes, <a href="https://magnus.therning.org/2024-09-01-improving-how-i-handle-secrets-in-my-work-notes.html">here</a>, and <a href="https://magnus.therning.org/2024-09-09-followup-on-secrets-in-my-work-notes.html">here</a>. Better late than never though, I hope.
</p>
<div class="outline-2" id="outline-container-orgad48ff7">
<h2 id="orgad48ff7">Comment from Stefano R</h2>
<div class="outline-text-2" id="text-orgad48ff7">
<p>
The first one is a link to post titled <a href="https://stefanorodighiero.net/blog/how-i-use-dbconnection-in-org.html">How I use :dbconnection in org files</a>. It
describes a nice way of setting <code>sql-connection-alist</code> based on the contents of
a file, in his case <code>~/.pgppass</code>.
</p>
</div>
</div>
<div class="outline-2" id="outline-container-org4a61064">
<h2 id="org4a61064">Comment from Harald J</h2>
<div class="outline-text-2" id="text-org4a61064">
<p>
The other starts with a function for searching <code>~/.authinfo.gpg</code> for entries of
the form
</p>

<div class="org-src-container">
<pre class="src src-authinfo"><code><span class="org-variable-name">machine</span> <span class="org-builtin">&lt;host&gt;/&lt;dbname&gt;</span> <span class="org-comment-delimiter">login</span> <span class="org-keyword">&lt;username&gt;</span> <span class="org-comment-delimiter">password</span> <span class="org-doc">&lt;password&gt;</span> <span class="org-comment-delimiter">port</span> <span class="org-type">&lt;port&gt;</span>
</code></pre>
</div>

<p>
and then setting <code>sql-password-search-wallet-function</code> and <code>sql-password-wallet</code>
to tell <code>sql-mode</code> to use it
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><code><span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">defun</span> <span class="org-function-name">my/sql-auth-source-search-wallet</span> <span class="org-rainbow-delimiters-depth-2">(</span>wallet product user server database port<span class="org-rainbow-delimiters-depth-2">)</span>
  <span class="org-doc">"Read auth source WALLET to locate the USER secret.
Sets `</span><span class="org-doc"><span class="org-constant">auth-sources</span></span><span class="org-doc">' to WALLET and uses `</span><span class="org-doc"><span class="org-constant">auth-source-search</span></span><span class="org-doc">' to locate the entry.
The DATABASE and SERVER are concatenated with a slash between them as the
host key."</span>
  <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-keyword">when-let</span> <span class="org-rainbow-delimiters-depth-3">(</span>results <span class="org-rainbow-delimiters-depth-4">(</span>auth-source-search <span class="org-builtin">:host</span> <span class="org-rainbow-delimiters-depth-5">(</span>concat server <span class="org-string">"/"</span> database<span class="org-rainbow-delimiters-depth-5">)</span>
                                         <span class="org-builtin">:user</span> user
                                         <span class="org-builtin">:port</span> <span class="org-rainbow-delimiters-depth-5">(</span>number-to-string port<span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span>
    <span class="org-rainbow-delimiters-depth-3">(</span><span class="org-keyword">when</span> <span class="org-rainbow-delimiters-depth-4">(</span><span class="org-keyword">and</span> <span class="org-rainbow-delimiters-depth-5">(</span>= <span class="org-rainbow-delimiters-depth-6">(</span>length results<span class="org-rainbow-delimiters-depth-6">)</span> 1<span class="org-rainbow-delimiters-depth-5">)</span>
               <span class="org-rainbow-delimiters-depth-5">(</span>plist-member <span class="org-rainbow-delimiters-depth-6">(</span>car results<span class="org-rainbow-delimiters-depth-6">)</span> <span class="org-builtin">:secret</span><span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span>
      <span class="org-rainbow-delimiters-depth-4">(</span>plist-get <span class="org-rainbow-delimiters-depth-5">(</span>car results<span class="org-rainbow-delimiters-depth-5">)</span> <span class="org-builtin">:secret</span><span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span>

<span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">setq</span> sql-password-search-wallet-function #'my/sql-auth-source-search-wallet<span class="org-rainbow-delimiters-depth-1">)</span>
<span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">setq</span> sql-password-wallet <span class="org-string">"~/.authinfo.gpg"</span><span class="org-rainbow-delimiters-depth-1">)</span>
</code></pre>
</div>

<p>
The value for <code>sql-connection-alist</code> is then as normal
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><code><span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">setq</span> sql-connection-alist
  '<span class="org-rainbow-delimiters-depth-2">(</span><span class="org-rainbow-delimiters-depth-3">(</span>some-dbname <span class="org-rainbow-delimiters-depth-4">(</span>sql-product 'oracle<span class="org-rainbow-delimiters-depth-4">)</span>
                 <span class="org-rainbow-delimiters-depth-4">(</span>sql-port 1521<span class="org-rainbow-delimiters-depth-4">)</span>
                 <span class="org-rainbow-delimiters-depth-4">(</span>sql-server ...<span class="org-rainbow-delimiters-depth-4">)</span>
                 ...<span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span>
</code></pre>
</div>

<p>
and the blocks in orgmode looks like this
</p>

<div class="org-src-container">
<pre class="src src-org"><code><span class="org-org-modern-block-name"><span class="org-org-block-begin-line">SRC</span></span><span class="org-org-block-begin-line"> sql-mode :product oracle :dbconnection i3v1e-ro :results raw
</span><span class="org-org-block">SELECT to_char(sysdate, 'YYYY-MM-DD HH24:ii:ss') AS today,
       to_char(sysdate + 1, 'YYYY-MM-DD HH24:ii:ss') AS tomorrow
FROM dual;
</span><span class="org-org-modern-block-name"><span class="org-org-block-end-line">SRC</span></span>
</code></pre>
</div>
</div>
</div>
<div class="outline-2" id="outline-container-org6448d06">
<h2 id="org6448d06">Thoughts</h2>
<div class="outline-text-2" id="text-org6448d06">
<p>
Both of these feel closer to the intent of <code>sql-mode</code> in a way. I'll have to try
using <code>sql-connection-alist</code> at some point.
</p>
</div>
</div>
<div class="taglist"><a href="https://magnus.therning.org/tags.html">Tags</a>: <a href="https://magnus.therning.org/tag-emacs.html">emacs</a> </div></div>
    </summary>
    <updated>2026-05-02T10:41:00Z</updated>
    <published>2026-05-02T10:41:00Z</published>
    <category term="emacs"/>
    <source>
      <id>https://magnus.therning.org/</id>
      <author>
        <name>Magnus Therning</name>
      </author>
      <link href="https://magnus.therning.org/" rel="alternate" type="text/html"/>
      <link href="https://magnus.therning.org/feed.xml" rel="self" type="application/rss+xml"/>
      <subtitle>Magnus web site</subtitle>
      <title>Magnus web site</title>
      <updated>2026-05-04T06:17:54Z</updated>
    </source>
  </entry>

  <entry>
    <id>https://wickstrom.tech/2026-04-30-bombadil-terminal-experiment.html</id>
    <link href="https://wickstrom.tech/2026-04-30-bombadil-terminal-experiment.html" rel="alternate" type="text/html"/>
    <title>The Bombadil Terminal Experiment</title>
    <summary>Last week at Bug Bash 2026, I had a bunch of interesting discussions
about testing non-web interfaces with Bombadil, our new property-based
testing framework for user interfaces. One direction that I already
wanted to explore is terminal user interfaces (TUIs), and the hallway
discussions gave me a nudge to get going. I started hacking on the
flight back home, and a few days later that embryo of a TUI fuzzer
started to emerge.</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Last week at <a href="https://antithesis.com/bugbash/conference2026/">Bug Bash 2026</a>, I had a bunch of interesting discussions about testing non-web interfaces with <a href="http://bombadil.bot/">Bombadil</a>, our new property-based testing framework for user interfaces. One direction that I already wanted to explore is <em>terminal user interfaces</em> (TUIs), and the hallway discussions gave me a nudge to get going. I started hacking on the flight back home, and a few days later that embryo of a TUI fuzzer started to emerge.</p> <figure> <video controls="" src="https://wickstrom.tech/assets/tetris-stuck.mp4"><a href="https://wickstrom.tech/assets/tetris-stuck.mp4">The fuzzer in action, finding a bug in vitetris. (CW: flashing!)</a></video> <figcaption>The fuzzer in action, finding a bug in vitetris. (CW: flashing!)</figcaption> </figure> <p>It’s built on top of two key crates:</p> <ol type="1"> <li><a href="https://crates.io/crates/portable-pty">portable-pty</a>, a pseudo-teletype in Rust that runs the program under test, and</li> <li><a href="https://crates.io/crates/libghostty-vt">libghostty-vt</a>, a Rust wrapper around the Zig library, which interprets the output of the PTY and provides a virtual terminal API from which you can read cell contents, styles, scroll through the scrollback, etc.</li> </ol> <p>With these two in place, I built a <em>very</em> basic fuzzer for TUIs: it runs the command you give it, polls its output, and writes interleaved random input sequences (printable ASCII characters and ANSI escape sequences). It also scrolls and resizes the terminal occasionally. Timing is a bit tricky, but it seems the current approach works fine: polling reads until the terminal is idle, capture state, then apply new inputs. Regarding speed, it depends a lot on the program being tested, but it looks capable of capturing at least 300 states per second.</p> <p>I tried finding some basic TUI programs and terminal games to test. Much to my surprise, within the first few days I had found four seemingly real bugs in real software:</p> <ul> <li><a href="https://github.com/vicgeralds/vitetris">vitetris</a> has a bug where if you enter just a number in the host name (e.g. <code>6</code>) and try to connect to a remote game, the UI freezes.</li> <li><a href="https://github.com/aristocratos/btop">btop</a> has two different bugs, <a href="https://github.com/aristocratos/btop/issues/1010">one recently fixed</a> that I confirmed fixed with the latest version (1.4.6), and <a href="https://github.com/aristocratos/btop/issues/1627">one that I just reported</a>. Both were triggered by this fuzzer.</li> <li><a href="https://github.com/hanslub42/rlwrap">rlwrap</a> got into a segfault which I haven’t yet been able to troubleshoot.</li> </ul> <p>Pretty cool. Today, I merged this work to <code>main</code> in Bombadil. It’s not yet released, but if you’re curious you can try it already by downloading a <code>bombadil-terminal</code> binary from the <a href="https://github.com/antithesishq/bombadil/actions/workflows/ci.yml">CI</a> artifacts. On macOS you’ll need to remove the quarantine bit to bypass GateKeeper.</p> <p>Now, the work remains to make this a solid tool. Here are some future goals:</p> <ul> <li>Integrate it with the specification framework in Bombadil, so that you can define custom properties and action generators. It’d be neat to provide an API akin to <code>querySelector</code> that could parse and traverse panels drawn with box-drawing characters. You probably also want to validate that those borders line up correctly.</li> <li>Generate a lot more diverse input and terminal actions. For instance, generate sequences from the <a href="https://sw.kovidgoyal.net/kitty/keyboard-protocol/">Kitty keyboard protocol</a>.</li> <li>Make the test runner’s user interface better. Perhaps a TUI?!</li> <li>Make this part of the ordinary <code>bombadil</code> binary, I think. There could be subcommands for <code>browser</code> and <code>terminal</code> testing tools.</li> <li>Run it in Antithesis to see what that fuzzer can find.</li> </ul> <p>All right, short post today — I just wanted to share my excitement and early results.</p> <p><em>A huge thanks to <a href="https://github.com/Uzaaft">Uzair Aftab</a>, maintainer of <a href="https://github.com/Uzaaft/libghostty-rs">libghostty-rs</a>, for helping me get libghostty-vt building under Nix!</em></p></div>
    </content>
    <updated>2026-04-29T22:00:00Z</updated>
    <published>2026-04-29T22:00:00Z</published>
    <source>
      <id>https://wickstrom.tech/</id>
      <author>
        <name>Oskar Wickström</name>
      </author>
      <link href="https://wickstrom.tech/feed.xml" rel="self" type="application/atom+xml"/>
      <link href="https://wickstrom.tech/" rel="alternate" type="text/html"/>
      <subtitle>Software design, testing, functional programming, and other delightful things.</subtitle>
      <title>Oskar WickstrÃ¶m</title>
      <updated>2026-05-17T06:31:58Z</updated>
    </source>
  </entry>

  <entry>
    <id>https://doisinkidney.com/posts/2026-04-28-poly-trie.html</id>
    <link href="https://doisinkidney.com/posts/2026-04-28-poly-trie.html" rel="alternate" type="text/html"/>
    <title>Tries for Polynomials</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><div class="info">
    Posted on April 28, 2026
</div>
<div class="info">
    
</div>
<div class="info">
    
        Tags: <a href="https://doisinkidney.com/tags/Haskell.html" rel="tag" title="All pages tagged 'Haskell'.">Haskell</a>
    
</div>

<p>One of my favourite Haskell papers is McIlroyâ€™s wonderful â€œPower
Series, Power Seriousâ€� <span class="citation">(<a href="https://doisinkidney.com/rss.xml#ref-mcilroy_power_1999">1999</a>)</span>. The paper is about <em>power
series</em>, which are a type of infinite sums that behave like
(infinite) polynomials. For example,
<math display="inline">&lt;semantics&gt;<mi>cos</mi>&lt;annotation encoding="application/x-tex"&gt;\cos&lt;/annotation&gt;&lt;/semantics&gt;</math>
can be represented by the following power series:</p>
<p><math display="inline">&lt;semantics&gt;<mrow><mrow><mi>cos</mi><mo>⁡</mo></mrow><mo form="prefix" stretchy="false">(</mo><mi>x</mi><mo form="postfix" stretchy="false">)</mo><mo>=</mo><mn>1</mn><mo>âˆ’</mo><mfrac><msup><mi>x</mi><mn>2</mn></msup><mrow><mn>2</mn><mi>!</mi></mrow></mfrac><mo>+</mo><mfrac><msup><mi>x</mi><mn>4</mn></msup><mrow><mn>4</mn><mi>!</mi></mrow></mfrac><mo>âˆ’</mo><mfrac><msup><mi>x</mi><mn>6</mn></msup><mrow><mn>6</mn><mi>!</mi></mrow></mfrac><mo>+</mo><mfrac><msup><mi>x</mi><mn>8</mn></msup><mrow><mn>8</mn><mi>!</mi></mrow></mfrac><mo>âˆ’</mo><mfrac><msup><mi>x</mi><mn>10</mn></msup><mrow><mn>10</mn><mi>!</mi></mrow></mfrac><mo>+</mo><mi>â‹¯</mi></mrow>&lt;annotation encoding="application/x-tex"&gt;\cos(x) = 1 - \frac{x^2}{2!} + \frac{x^4}{4!} - \frac{x^6}{6!} + \frac{x^8}{8!} - \frac{x^{10}}{10!} + \cdots&lt;/annotation&gt;&lt;/semantics&gt;</math></p>
<p>A power series is characterised fully by its coefficients, meaning
that we can represent one as an infinite stream of rational numbers. In
Haskell, we often use lazy lists to represent streams, so we can encode
a power series with the following type:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="https://doisinkidney.com/rss.xml#cb1-1" tabindex="-1"/><span class="kw">type</span> <span class="dt">PowerSeries</span> <span class="ot">=</span> [<span class="dt">Rational</span>]</span></code></pre></div>
<p>In this encoding, we can write
<math display="inline">&lt;semantics&gt;<mi>cos</mi>&lt;annotation encoding="application/x-tex"&gt;\cos&lt;/annotation&gt;&lt;/semantics&gt;</math>
as the following:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb2-1"><a href="https://doisinkidney.com/rss.xml#cb2-1" tabindex="-1"/><span class="fu">cos</span><span class="ot"> ::</span> <span class="dt">PowerSeries</span></span>
<span id="cb2-2"><a href="https://doisinkidney.com/rss.xml#cb2-2" tabindex="-1"/><span class="fu">cos</span> <span class="ot">=</span> <span class="fu">zipWith</span> (<span class="op">*</span>) (<span class="fu">cycle</span> [<span class="dv">1</span>,<span class="dv">0</span>,<span class="op">-</span><span class="dv">1</span>,<span class="dv">0</span>]) (<span class="fu">scanl</span> (<span class="op">/</span>) <span class="dv">1</span> [<span class="dv">1</span><span class="op">..</span>])</span>
<span id="cb2-3"><a href="https://doisinkidney.com/rss.xml#cb2-3" tabindex="-1"/></span>
<span id="cb2-4"><a href="https://doisinkidney.com/rss.xml#cb2-4" tabindex="-1"/><span class="op">&gt;&gt;&gt;</span> <span class="fu">cos</span></span>
<span id="cb2-5"><a href="https://doisinkidney.com/rss.xml#cb2-5" tabindex="-1"/>[<span class="dv">1</span>,<span class="dv">0</span>,<span class="op">-</span><span class="dv">1</span><span class="op">/</span><span class="dv">2</span>,<span class="dv">0</span>,<span class="dv">1</span><span class="op">/</span><span class="dv">24</span>,<span class="dv">0</span>,<span class="op">-</span><span class="dv">1</span><span class="op">/</span><span class="dv">720</span>,<span class="op">...</span></span></code></pre></div>
<p>We can also build
<math display="inline">&lt;semantics&gt;<mi>sin</mi>&lt;annotation encoding="application/x-tex"&gt;\sin&lt;/annotation&gt;&lt;/semantics&gt;</math>:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb3-1"><a href="https://doisinkidney.com/rss.xml#cb3-1" tabindex="-1"/><span class="fu">sin</span> <span class="ot">=</span> <span class="fu">zipWith</span> (<span class="op">*</span>) (<span class="fu">cycle</span> [<span class="dv">0</span>,<span class="dv">1</span>,<span class="dv">0</span>,<span class="op">-</span><span class="dv">1</span>]) (<span class="fu">scanl</span> (<span class="op">/</span>) <span class="dv">1</span> [<span class="dv">1</span><span class="op">..</span>])</span></code></pre></div>
<p>While it can be difficult and unintuitive to work with infinite
series like the ones above, happily we can define all of the normal
numeric operations on power series as (lazy) list-manipulation
programs:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb4-1"><a href="https://doisinkidney.com/rss.xml#cb4-1" tabindex="-1"/><span class="kw">instance</span> <span class="dt">Num</span> <span class="dt">PowerSeries</span> <span class="kw">where</span></span>
<span id="cb4-2"><a href="https://doisinkidney.com/rss.xml#cb4-2" tabindex="-1"/></span>
<span id="cb4-3"><a href="https://doisinkidney.com/rss.xml#cb4-3" tabindex="-1"/>  (x<span class="op">:</span>xs) <span class="op">+</span> (y<span class="op">:</span>ys) <span class="ot">=</span> (x<span class="op">+</span>y) <span class="op">:</span> (xs <span class="op">+</span> ys)</span>
<span id="cb4-4"><a href="https://doisinkidney.com/rss.xml#cb4-4" tabindex="-1"/></span>
<span id="cb4-5"><a href="https://doisinkidney.com/rss.xml#cb4-5" tabindex="-1"/>  (x<span class="op">:</span>xs) <span class="op">*</span> ys <span class="ot">=</span> <span class="fu">map</span> (x<span class="op">*</span>) ys <span class="op">+</span> (<span class="dv">0</span> <span class="op">:</span> xs <span class="op">*</span> ys)</span>
<span id="cb4-6"><a href="https://doisinkidney.com/rss.xml#cb4-6" tabindex="-1"/></span>
<span id="cb4-7"><a href="https://doisinkidney.com/rss.xml#cb4-7" tabindex="-1"/>  <span class="fu">negate</span> <span class="ot">=</span> <span class="fu">map</span> <span class="fu">negate</span></span>
<span id="cb4-8"><a href="https://doisinkidney.com/rss.xml#cb4-8" tabindex="-1"/></span>
<span id="cb4-9"><a href="https://doisinkidney.com/rss.xml#cb4-9" tabindex="-1"/>  <span class="fu">fromInteger</span> n <span class="ot">=</span> <span class="fu">fromInteger</span> n <span class="op">:</span> <span class="fu">repeat</span> <span class="dv">0</span></span></code></pre></div>
<p>(if you try and put this code into a Haskell interpreter youâ€™ll get
all sorts of warnings; Iâ€™ll put the full code for this post below with
all of the imports and pragmas you need to get it to work)</p>
<p><span class="citation">McIlroy (<a href="https://doisinkidney.com/rss.xml#ref-mcilroy_power_1999">1999</a>)</span>
goes through the various algorithms and numeric operations that can be
implemented on this representation, but at this point I would like to
diverge from the paper and turn our focus to finite polynomials. Like a
power series, a finite polynomial can be represented by a list of
coefficients:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb5-1"><a href="https://doisinkidney.com/rss.xml#cb5-1" tabindex="-1"/><span class="kw">type</span> <span class="dt">Polynomial</span> <span class="ot">=</span> [<span class="dt">Rational</span>]</span></code></pre></div>
<p>And, even though the underlying list is finite rather than infinite,
the numeric operations work basically the same way as they do on power
series. We just need to add clauses in each function to handle the empty
list:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb6-1"><a href="https://doisinkidney.com/rss.xml#cb6-1" tabindex="-1"/><span class="kw">instance</span> <span class="dt">Num</span> <span class="dt">Polynomial</span> <span class="kw">where</span></span>
<span id="cb6-2"><a href="https://doisinkidney.com/rss.xml#cb6-2" tabindex="-1"/></span>
<span id="cb6-3"><a href="https://doisinkidney.com/rss.xml#cb6-3" tabindex="-1"/>  []     <span class="op">+</span> ys     <span class="ot">=</span> ys</span>
<span id="cb6-4"><a href="https://doisinkidney.com/rss.xml#cb6-4" tabindex="-1"/>  xs     <span class="op">+</span> []     <span class="ot">=</span> xs</span>
<span id="cb6-5"><a href="https://doisinkidney.com/rss.xml#cb6-5" tabindex="-1"/>  (x<span class="op">:</span>xs) <span class="op">+</span> (y<span class="op">:</span>ys) <span class="ot">=</span> (x<span class="op">+</span>y) <span class="op">:</span> (xs <span class="op">+</span> ys)</span>
<span id="cb6-6"><a href="https://doisinkidney.com/rss.xml#cb6-6" tabindex="-1"/></span>
<span id="cb6-7"><a href="https://doisinkidney.com/rss.xml#cb6-7" tabindex="-1"/>  []     <span class="op">*</span> _  <span class="ot">=</span> []</span>
<span id="cb6-8"><a href="https://doisinkidney.com/rss.xml#cb6-8" tabindex="-1"/>  (x<span class="op">:</span>xs) <span class="op">*</span> ys <span class="ot">=</span> <span class="fu">map</span> (x<span class="op">*</span>) ys <span class="op">+</span> (<span class="dv">0</span> <span class="op">:</span> xs <span class="op">*</span> ys)</span>
<span id="cb6-9"><a href="https://doisinkidney.com/rss.xml#cb6-9" tabindex="-1"/></span>
<span id="cb6-10"><a href="https://doisinkidney.com/rss.xml#cb6-10" tabindex="-1"/>  <span class="fu">negate</span> <span class="ot">=</span> <span class="fu">map</span> <span class="fu">negate</span></span>
<span id="cb6-11"><a href="https://doisinkidney.com/rss.xml#cb6-11" tabindex="-1"/></span>
<span id="cb6-12"><a href="https://doisinkidney.com/rss.xml#cb6-12" tabindex="-1"/>  <span class="fu">fromInteger</span> n <span class="ot">=</span> [<span class="fu">fromInteger</span> n]</span></code></pre></div>
<p>The only semantic trickiness with this representation is that itâ€™s
important to quotient by trailing zeroes.</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb7-1"><a href="https://doisinkidney.com/rss.xml#cb7-1" tabindex="-1"/><span class="kw">instance</span> <span class="dt">Eq</span> <span class="dt">Polynomial</span> <span class="kw">where</span></span>
<span id="cb7-2"><a href="https://doisinkidney.com/rss.xml#cb7-2" tabindex="-1"/>  [] <span class="op">==</span> ys <span class="ot">=</span> <span class="fu">all</span> (<span class="dv">0</span><span class="op">==</span>) ys</span>
<span id="cb7-3"><a href="https://doisinkidney.com/rss.xml#cb7-3" tabindex="-1"/>  xs <span class="op">==</span> [] <span class="ot">=</span> <span class="fu">all</span> (<span class="dv">0</span><span class="op">==</span>) xs</span>
<span id="cb7-4"><a href="https://doisinkidney.com/rss.xml#cb7-4" tabindex="-1"/>  (x<span class="op">:</span>xs) <span class="op">==</span> (y<span class="op">:</span>ys) <span class="ot">=</span> (x <span class="op">==</span> y) <span class="op">&amp;&amp;</span> (xs <span class="op">==</span> ys)</span></code></pre></div>
<h2 id="evaluation-and-horners-rule">Evaluation and Hornerâ€™s Rule</h2>
<p>The definition of a power series above suggests that we should
implement evaluation using exponentiation and indices:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb8-1"><a href="https://doisinkidney.com/rss.xml#cb8-1" tabindex="-1"/><span class="ot">eval ::</span> <span class="dt">Polynomial</span> <span class="ot">-&gt;</span> <span class="dt">Rational</span> <span class="ot">-&gt;</span> <span class="dt">Rational</span></span>
<span id="cb8-2"><a href="https://doisinkidney.com/rss.xml#cb8-2" tabindex="-1"/>eval p x <span class="ot">=</span> <span class="fu">sum</span> (<span class="fu">zipWith</span> (\a i <span class="ot">-&gt;</span> a <span class="op">*</span> x<span class="op">^</span>i) p [<span class="dv">0</span><span class="op">..</span>])</span></code></pre></div>
<p>And this does in fact give us the correct answer. Consider the
polynomial
<math display="inline">&lt;semantics&gt;<mrow><mn>4</mn><mo>+</mo><mn>2</mn><mi>x</mi><mo>+</mo><mn>5</mn><msup><mi>x</mi><mn>2</mn></msup><mo>âˆ’</mo><msup><mi>x</mi><mn>3</mn></msup></mrow>&lt;annotation encoding="application/x-tex"&gt;4 + 2x + 5x^2 - x^3&lt;/annotation&gt;&lt;/semantics&gt;</math>:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb9-1"><a href="https://doisinkidney.com/rss.xml#cb9-1" tabindex="-1"/>poly <span class="ot">=</span> [<span class="dv">4</span>,<span class="dv">2</span>,<span class="dv">5</span>,<span class="op">-</span><span class="dv">1</span>] <span class="co">-- 4 + 2x + 5xÂ² - xÂ³</span></span>
<span id="cb9-2"><a href="https://doisinkidney.com/rss.xml#cb9-2" tabindex="-1"/>eval poly x <span class="ot">=</span> eval [<span class="dv">4</span>,<span class="dv">2</span>,<span class="dv">5</span>,<span class="op">-</span><span class="dv">1</span>] x</span>
<span id="cb9-3"><a href="https://doisinkidney.com/rss.xml#cb9-3" tabindex="-1"/>            <span class="ot">=</span> <span class="fu">sum</span> (<span class="fu">zipWith</span> (\a i <span class="ot">-&gt;</span> a <span class="op">*</span> x <span class="op">^</span> i) [<span class="dv">4</span>,<span class="dv">2</span>,<span class="dv">5</span>,<span class="op">-</span><span class="dv">1</span>] [<span class="dv">0</span><span class="op">..</span>])</span>
<span id="cb9-4"><a href="https://doisinkidney.com/rss.xml#cb9-4" tabindex="-1"/>            <span class="ot">=</span> <span class="dv">4</span><span class="op">*</span>x<span class="op">^</span><span class="dv">0</span> <span class="op">+</span> <span class="dv">2</span><span class="op">*</span>x<span class="op">^</span><span class="dv">1</span> <span class="op">+</span> <span class="dv">5</span><span class="op">*</span>x<span class="op">^</span><span class="dv">2</span> <span class="op">+</span> (<span class="op">-</span><span class="dv">1</span>)<span class="op">*</span>x<span class="op">^</span><span class="dv">3</span></span>
<span id="cb9-5"><a href="https://doisinkidney.com/rss.xml#cb9-5" tabindex="-1"/>            <span class="ot">=</span> <span class="dv">4</span> <span class="op">+</span> <span class="dv">2</span><span class="op">*</span>x <span class="op">+</span> <span class="dv">5</span><span class="op">*</span>x<span class="op">^</span><span class="dv">2</span> <span class="op">-</span> x<span class="op">^</span><span class="dv">3</span></span></code></pre></div>
<p>However, this evaluation algorithm is unsatisfactory in one respect:
it performs a <em>lot</em> of multiplication. In numeric programs, we
generally want to minimise the number of multiplications performed,
since multiplication is a relatively expensive operation (when compared
to addition or subtraction). In the example above, it takes six
multiplications to compute the result: one for
<math display="inline">&lt;semantics&gt;<mrow><mn>2</mn><mi>x</mi><mo>=</mo><mn>2</mn><mo>Ã—</mo><mi>x</mi></mrow>&lt;annotation encoding="application/x-tex"&gt;2x = 2 \times x&lt;/annotation&gt;&lt;/semantics&gt;</math>,
two for
<math display="inline">&lt;semantics&gt;<mrow><mn>5</mn><msup><mi>x</mi><mn>2</mn></msup><mo>=</mo><mn>5</mn><mo>Ã—</mo><mi>x</mi><mo>Ã—</mo><mi>x</mi></mrow>&lt;annotation encoding="application/x-tex"&gt;5x^2 = 5 \times x \times x&lt;/annotation&gt;&lt;/semantics&gt;</math>,
and three for
<math display="inline">&lt;semantics&gt;<mrow><mi>âˆ’</mi><msup><mi>x</mi><mn>3</mn></msup><mo>=</mo><mi>âˆ’</mi><mn>1</mn><mo>Ã—</mo><mi>x</mi><mo>Ã—</mo><mi>x</mi><mo>Ã—</mo><mi>x</mi></mrow>&lt;annotation encoding="application/x-tex"&gt;-x^3 = -1 \times x \times x \times x&lt;/annotation&gt;&lt;/semantics&gt;</math>.
In general, for a polynomial of degree
<math display="inline">&lt;semantics&gt;<mi>n</mi>&lt;annotation encoding="application/x-tex"&gt;n&lt;/annotation&gt;&lt;/semantics&gt;</math>,
the above implementation of <code class="sourceCode haskell">eval</code>
will perform
<math display="inline">&lt;semantics&gt;<mrow><mi>ğ�’ª</mi><mo form="prefix" stretchy="false">(</mo><msup><mi>n</mi><mn>2</mn></msup><mo form="postfix" stretchy="false">)</mo></mrow>&lt;annotation encoding="application/x-tex"&gt;\mathcal{O}(n^2)&lt;/annotation&gt;&lt;/semantics&gt;</math>
multiplications.</p>
<p>There is, however, a trick that can bring the number of
multiplications down to
<math display="inline">&lt;semantics&gt;<mrow><mi>ğ�’ª</mi><mo form="prefix" stretchy="false">(</mo><mi>n</mi><mo form="postfix" stretchy="false">)</mo></mrow>&lt;annotation encoding="application/x-tex"&gt;\mathcal{O}(n)&lt;/annotation&gt;&lt;/semantics&gt;</math>:
Hornerâ€™s rule. The basic idea is to rewrite the expanded polynomial
<math display="inline">&lt;semantics&gt;<mrow><mn>4</mn><mo>+</mo><mn>2</mn><mi>x</mi><mo>+</mo><mn>5</mn><msup><mi>x</mi><mn>2</mn></msup><mo>âˆ’</mo><msup><mi>x</mi><mn>3</mn></msup></mrow>&lt;annotation encoding="application/x-tex"&gt;4 + 2x + 5x^2 - x^3&lt;/annotation&gt;&lt;/semantics&gt;</math>
into a factorised form:
<math display="inline">&lt;semantics&gt;<mrow><mn>4</mn><mo>+</mo><mi>x</mi><mo form="prefix" stretchy="false">(</mo><mn>2</mn><mo>+</mo><mi>x</mi><mo form="prefix" stretchy="false">(</mo><mn>5</mn><mo>+</mo><mi>x</mi><mo form="prefix" stretchy="false">(</mo><mi>âˆ’</mi><mn>1</mn><mo form="postfix" stretchy="false">)</mo><mo form="postfix" stretchy="false">)</mo><mo form="postfix" stretchy="false">)</mo></mrow>&lt;annotation encoding="application/x-tex"&gt;4 + x(2 + x(5 + x(-1)))&lt;/annotation&gt;&lt;/semantics&gt;</math>.
If we evaluate <em>this</em> expression directly, we will only have to
perform three multiplications (and we donâ€™t even have to perform any
extra additions as compensation). While Hornerâ€™s rule is really quite a
simple trick, the generalised pattern is surprisingly powerful <span class="citation">(<a href="https://doisinkidney.com/rss.xml#ref-gibbons_horners_2011">Gibbons
2011</a>)</span>. Indeed, the representation I develop in this post is
basically a data structure encoding of Hornerâ€™s rule.</p>
<p>Before getting there, however, letâ€™s return to our list-based
polynomial, and look at using Hornerâ€™s rule to implement <code class="sourceCode haskell">eval</code>. Interestingly, the list-based
representation has kind of already performed our factorisation for us.
As a result, Hornerâ€™s rule evaluation is actually more natural to
implement than the expanded version above.</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb10-1"><a href="https://doisinkidney.com/rss.xml#cb10-1" tabindex="-1"/><span class="ot">eval ::</span> <span class="dt">Polynomial</span> <span class="ot">-&gt;</span> <span class="dt">Rational</span> <span class="ot">-&gt;</span> <span class="dt">Rational</span></span>
<span id="cb10-2"><a href="https://doisinkidney.com/rss.xml#cb10-2" tabindex="-1"/>eval xs x <span class="ot">=</span> <span class="fu">foldr</span> (\a p <span class="ot">-&gt;</span> a <span class="op">+</span> x <span class="op">*</span> p) <span class="dv">0</span> xs</span></code></pre></div>
<h2 id="multiple-variables">Multiple Variables</h2>
<p>A cool trick with this representation is that if you want to support
multiple variables you can smuggle them in through the coefficients. A
polynomial in two variables is the same as a polynomial with
coefficients drawn from another polynomial.</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb11-1"><a href="https://doisinkidney.com/rss.xml#cb11-1" tabindex="-1"/><span class="kw">type</span> <span class="dt">TwoVar</span> <span class="ot">=</span> [<span class="dt">Polynomial</span>]</span></code></pre></div>
<p>To save us having to write a separate <code class="sourceCode haskell"><span class="dt">Num</span></code> instance
for <code class="sourceCode haskell"><span class="dt">TwoVar</span></code>, we can
instead generalise the <code class="sourceCode haskell"><span class="dt">Num</span></code> instance
on <code class="sourceCode haskell"><span class="dt">Polynomial</span></code>
above:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb12-1"><a href="https://doisinkidney.com/rss.xml#cb12-1" tabindex="-1"/><span class="kw">instance</span> <span class="dt">Num</span> a <span class="ot">=&gt;</span> <span class="dt">Num</span> [a] <span class="kw">where</span></span></code></pre></div>
<p>The rest of the instance is the same. Now, we can write <code class="sourceCode haskell"><span class="dv">5</span> <span class="op">^</span> <span class="dv">2</span><span class="ot"> ::</span> <span class="dt">Polynomial</span></code>
or <code class="sourceCode haskell"><span class="dv">6</span><span class="ot"> ::</span> <span class="dt">TwoVar</span></code>
and it will just work.</p>
<p>We also have to generalise the type of <code class="sourceCode haskell">eval</code> slightly:</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb13-1"><a href="https://doisinkidney.com/rss.xml#cb13-1" tabindex="-1"/><span class="ot">eval ::</span> <span class="dt">Num</span> a <span class="ot">=&gt;</span> [a] <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> a</span></code></pre></div>
<p>but again, the implementation remains the same.</p>
<p>With this machinery, we can now write and evaluate polynomials in 2
variables:</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb14-1"><a href="https://doisinkidney.com/rss.xml#cb14-1" tabindex="-1"/><span class="ot">eval2 ::</span> <span class="dt">TwoVar</span> <span class="ot">-&gt;</span> <span class="dt">Rational</span> <span class="ot">-&gt;</span> <span class="dt">Rational</span> <span class="ot">-&gt;</span> <span class="dt">Rational</span></span>
<span id="cb14-2"><a href="https://doisinkidney.com/rss.xml#cb14-2" tabindex="-1"/>eval2 p x y <span class="ot">=</span> eval (eval p [x]) y</span>
<span id="cb14-3"><a href="https://doisinkidney.com/rss.xml#cb14-3" tabindex="-1"/></span>
<span id="cb14-4"><a href="https://doisinkidney.com/rss.xml#cb14-4" tabindex="-1"/><span class="ot">var ::</span> <span class="dt">Num</span> a <span class="ot">=&gt;</span> [a]</span>
<span id="cb14-5"><a href="https://doisinkidney.com/rss.xml#cb14-5" tabindex="-1"/>var <span class="ot">=</span> [<span class="dv">0</span>,<span class="dv">1</span>]</span>
<span id="cb14-6"><a href="https://doisinkidney.com/rss.xml#cb14-6" tabindex="-1"/></span>
<span id="cb14-7"><a href="https://doisinkidney.com/rss.xml#cb14-7" tabindex="-1"/>x <span class="ot">=</span> var</span>
<span id="cb14-8"><a href="https://doisinkidney.com/rss.xml#cb14-8" tabindex="-1"/>y <span class="ot">=</span> [var]</span>
<span id="cb14-9"><a href="https://doisinkidney.com/rss.xml#cb14-9" tabindex="-1"/></span>
<span id="cb14-10"><a href="https://doisinkidney.com/rss.xml#cb14-10" tabindex="-1"/>poly <span class="ot">=</span> <span class="dv">2</span> <span class="op">*</span> x <span class="op">^</span> <span class="dv">2</span> <span class="op">-</span> y <span class="op">^</span> <span class="dv">3</span> <span class="op">+</span> <span class="dv">4</span></span>
<span id="cb14-11"><a href="https://doisinkidney.com/rss.xml#cb14-11" tabindex="-1"/></span>
<span id="cb14-12"><a href="https://doisinkidney.com/rss.xml#cb14-12" tabindex="-1"/><span class="op">&gt;&gt;&gt;</span> poly</span>
<span id="cb14-13"><a href="https://doisinkidney.com/rss.xml#cb14-13" tabindex="-1"/>[[<span class="dv">4</span>,<span class="dv">0</span>,<span class="dv">0</span>,<span class="op">-</span><span class="dv">1</span>],[<span class="dv">0</span>],[<span class="dv">2</span>]]</span>
<span id="cb14-14"><a href="https://doisinkidney.com/rss.xml#cb14-14" tabindex="-1"/></span>
<span id="cb14-15"><a href="https://doisinkidney.com/rss.xml#cb14-15" tabindex="-1"/><span class="op">&gt;&gt;&gt;</span> eval2 poly <span class="dv">2</span> <span class="dv">3</span></span>
<span id="cb14-16"><a href="https://doisinkidney.com/rss.xml#cb14-16" tabindex="-1"/><span class="op">-</span><span class="dv">15</span></span></code></pre></div>
<p>We can even use some typeclass shenanigans to build a generalised
evaluator that works with any fixed number of variables.</p>
<details>

Implementation of an Evaluator for Polynomials in Arbitrary Variables

<div class="sourceCode" id="cb15"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb15-1"><a href="https://doisinkidney.com/rss.xml#cb15-1" tabindex="-1"/><span class="kw">instance</span> <span class="dt">Num</span> n <span class="ot">=&gt;</span> <span class="dt">Num</span> (e <span class="ot">-&gt;</span> n) <span class="kw">where</span></span>
<span id="cb15-2"><a href="https://doisinkidney.com/rss.xml#cb15-2" tabindex="-1"/>  <span class="fu">fromInteger</span> <span class="ot">=</span> <span class="fu">const</span> <span class="op">.</span> <span class="fu">fromInteger</span></span>
<span id="cb15-3"><a href="https://doisinkidney.com/rss.xml#cb15-3" tabindex="-1"/>  (f <span class="op">+</span> g) x <span class="ot">=</span> f x <span class="op">+</span> g x</span>
<span id="cb15-4"><a href="https://doisinkidney.com/rss.xml#cb15-4" tabindex="-1"/>  (f <span class="op">*</span> g) x <span class="ot">=</span> f x <span class="op">*</span> g x</span>
<span id="cb15-5"><a href="https://doisinkidney.com/rss.xml#cb15-5" tabindex="-1"/></span>
<span id="cb15-6"><a href="https://doisinkidney.com/rss.xml#cb15-6" tabindex="-1"/>  <span class="fu">abs</span> <span class="ot">=</span> (<span class="fu">abs</span> <span class="op">.</span>)</span>
<span id="cb15-7"><a href="https://doisinkidney.com/rss.xml#cb15-7" tabindex="-1"/>  <span class="fu">signum</span> <span class="ot">=</span> (<span class="fu">signum</span> <span class="op">.</span>)</span>
<span id="cb15-8"><a href="https://doisinkidney.com/rss.xml#cb15-8" tabindex="-1"/>  <span class="fu">negate</span> <span class="ot">=</span> (<span class="fu">negate</span> <span class="op">.</span>)</span>
<span id="cb15-9"><a href="https://doisinkidney.com/rss.xml#cb15-9" tabindex="-1"/></span>
<span id="cb15-10"><a href="https://doisinkidney.com/rss.xml#cb15-10" tabindex="-1"/><span class="kw">class</span> <span class="dt">Num</span> r <span class="ot">=&gt;</span> <span class="dt">Poly</span> p r <span class="op">|</span> p <span class="ot">-&gt;</span> r, r <span class="ot">-&gt;</span> p <span class="kw">where</span></span>
<span id="cb15-11"><a href="https://doisinkidney.com/rss.xml#cb15-11" tabindex="-1"/><span class="ot">  evalN ::</span> p <span class="ot">-&gt;</span> r</span>
<span id="cb15-12"><a href="https://doisinkidney.com/rss.xml#cb15-12" tabindex="-1"/></span>
<span id="cb15-13"><a href="https://doisinkidney.com/rss.xml#cb15-13" tabindex="-1"/><span class="kw">instance</span> <span class="dt">Poly</span> <span class="dt">Integer</span> <span class="dt">Integer</span> <span class="kw">where</span></span>
<span id="cb15-14"><a href="https://doisinkidney.com/rss.xml#cb15-14" tabindex="-1"/>  evalN <span class="ot">=</span> <span class="fu">id</span></span>
<span id="cb15-15"><a href="https://doisinkidney.com/rss.xml#cb15-15" tabindex="-1"/></span>
<span id="cb15-16"><a href="https://doisinkidney.com/rss.xml#cb15-16" tabindex="-1"/><span class="kw">instance</span> <span class="dt">Poly</span> p r <span class="ot">=&gt;</span> <span class="dt">Poly</span> [p] (<span class="dt">Integer</span> <span class="ot">-&gt;</span> r) <span class="kw">where</span></span>
<span id="cb15-17"><a href="https://doisinkidney.com/rss.xml#cb15-17" tabindex="-1"/>  evalN xs x <span class="ot">=</span> <span class="fu">foldr</span> (\a s <span class="ot">-&gt;</span> evalN a <span class="op">+</span> <span class="fu">fromInteger</span> x <span class="op">*</span> s) <span class="dv">0</span> xs</span></code></pre></div>
</details>
<div class="sourceCode" id="cb16"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb16-1"><a href="https://doisinkidney.com/rss.xml#cb16-1" tabindex="-1"/><span class="op">&gt;&gt;&gt;</span> evalN poly <span class="dv">2</span> <span class="dv">3</span></span>
<span id="cb16-2"><a href="https://doisinkidney.com/rss.xml#cb16-2" tabindex="-1"/><span class="op">-</span><span class="dv">15</span></span>
<span id="cb16-3"><a href="https://doisinkidney.com/rss.xml#cb16-3" tabindex="-1"/></span>
<span id="cb16-4"><a href="https://doisinkidney.com/rss.xml#cb16-4" tabindex="-1"/>z <span class="ot">=</span> [[var]]</span>
<span id="cb16-5"><a href="https://doisinkidney.com/rss.xml#cb16-5" tabindex="-1"/></span>
<span id="cb16-6"><a href="https://doisinkidney.com/rss.xml#cb16-6" tabindex="-1"/><span class="op">&gt;&gt;&gt;</span> evalN (poly <span class="op">+</span> z) <span class="dv">2</span> <span class="dv">3</span> <span class="dv">1</span></span>
<span id="cb16-7"><a href="https://doisinkidney.com/rss.xml#cb16-7" tabindex="-1"/><span class="op">-</span><span class="dv">14</span></span></code></pre></div>
<h2 id="sums-of-products">Sums of Products</h2>
<p>While the above representation is elegant, it is inefficient, and
perhaps a little unintuitive. In most implementations I have seen,
variables are represented simply with a type for names, rather than the
kind of implicit de Bruijn indices used above. One natural
representation uses a list of terms:</p>
<div class="sourceCode" id="cb17"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb17-1"><a href="https://doisinkidney.com/rss.xml#cb17-1" tabindex="-1"/><span class="kw">newtype</span> <span class="dt">Poly</span> v c <span class="ot">=</span> <span class="dt">Poly</span> {<span class="ot"> terms ::</span> [([v], c)] }</span></code></pre></div>
<p>Here, a value of type <code class="sourceCode haskell"><span class="dt">Poly</span> v c</code> is a
polynomial with coefficients drawn from <code class="sourceCode haskell">c</code> and variables from <code class="sourceCode haskell">v</code>. It is a list of monomials, where
the outer list represents a sum, and each monomial represents a product
of variables with a single coefficient.</p>
<div class="sourceCode" id="cb18"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb18-1"><a href="https://doisinkidney.com/rss.xml#cb18-1" tabindex="-1"/><span class="kw">data</span> <span class="dt">Var</span> <span class="ot">=</span> <span class="dt">X</span> <span class="op">|</span> <span class="dt">Y</span> <span class="op">|</span> <span class="dt">Z</span></span>
<span id="cb18-2"><a href="https://doisinkidney.com/rss.xml#cb18-2" tabindex="-1"/></span>
<span id="cb18-3"><a href="https://doisinkidney.com/rss.xml#cb18-3" tabindex="-1"/><span class="ot">poly ::</span> <span class="dt">Poly</span> <span class="dt">Var</span> <span class="dt">Integer</span></span>
<span id="cb18-4"><a href="https://doisinkidney.com/rss.xml#cb18-4" tabindex="-1"/>poly <span class="ot">=</span> <span class="dt">Poly</span> [([<span class="dt">X</span>,<span class="dt">Y</span>,<span class="dt">Y</span>],<span class="dv">5</span>),([<span class="dt">Z</span>],<span class="dv">3</span>),([<span class="dt">Y</span>,<span class="dt">Z</span>],<span class="dv">2</span>)]</span>
<span id="cb18-5"><a href="https://doisinkidney.com/rss.xml#cb18-5" tabindex="-1"/><span class="co">-- 5xyÂ² + 3z + 2yz</span></span></code></pre></div>
<p>Note that this representation requires some normalisation:</p>
<div class="sourceCode" id="cb19"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb19-1"><a href="https://doisinkidney.com/rss.xml#cb19-1" tabindex="-1"/><span class="ot">norm ::</span> (<span class="dt">Ord</span> v, <span class="dt">Num</span> c, <span class="dt">Eq</span> c) <span class="ot">=&gt;</span> [([v],c)] <span class="ot">-&gt;</span> [([v],c)]</span>
<span id="cb19-2"><a href="https://doisinkidney.com/rss.xml#cb19-2" tabindex="-1"/>norm <span class="ot">=</span> Map.toList <span class="op">.</span> Map.fromListWith (<span class="op">+</span>) <span class="op">.</span> <span class="fu">filter</span> ((<span class="op">/=</span><span class="dv">0</span>)<span class="op">.</span><span class="fu">snd</span>)</span>
<span id="cb19-3"><a href="https://doisinkidney.com/rss.xml#cb19-3" tabindex="-1"/></span>
<span id="cb19-4"><a href="https://doisinkidney.com/rss.xml#cb19-4" tabindex="-1"/><span class="kw">instance</span> (<span class="dt">Num</span> c, <span class="dt">Ord</span> v, <span class="dt">Eq</span> c) <span class="ot">=&gt;</span> <span class="dt">Eq</span> (<span class="dt">Poly</span> v c) <span class="kw">where</span></span>
<span id="cb19-5"><a href="https://doisinkidney.com/rss.xml#cb19-5" tabindex="-1"/>  (<span class="op">==</span>) <span class="ot">=</span> (<span class="op">==</span>) <span class="ot">`on`</span> norm <span class="op">.</span> terms</span></code></pre></div>
<p>And we have the following <code class="sourceCode haskell"><span class="dt">Num</span></code>
instance:</p>
<div class="sourceCode" id="cb20"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb20-1"><a href="https://doisinkidney.com/rss.xml#cb20-1" tabindex="-1"/><span class="kw">instance</span> <span class="dt">Num</span> c <span class="ot">=&gt;</span> <span class="dt">Num</span> (<span class="dt">Poly</span> v c) <span class="kw">where</span></span>
<span id="cb20-2"><a href="https://doisinkidney.com/rss.xml#cb20-2" tabindex="-1"/>  <span class="fu">fromInteger</span> n <span class="ot">=</span> <span class="dt">Poly</span> [([],<span class="fu">fromInteger</span> n)]</span>
<span id="cb20-3"><a href="https://doisinkidney.com/rss.xml#cb20-3" tabindex="-1"/>  <span class="dt">Poly</span> xs <span class="op">+</span> <span class="dt">Poly</span> ys <span class="ot">=</span> <span class="dt">Poly</span> (xs <span class="op">++</span> ys)</span>
<span id="cb20-4"><a href="https://doisinkidney.com/rss.xml#cb20-4" tabindex="-1"/>  xs <span class="op">*</span> ys <span class="ot">=</span> <span class="dt">Poly</span> [ (xv <span class="op">++</span> yv, xc <span class="op">*</span> yc) <span class="op">|</span> (xv,xc) <span class="ot">&lt;-</span> terms xs, (yv,yc) <span class="ot">&lt;-</span> terms ys ]</span>
<span id="cb20-5"><a href="https://doisinkidney.com/rss.xml#cb20-5" tabindex="-1"/>  <span class="fu">negate</span> <span class="ot">=</span> <span class="dt">Poly</span> <span class="op">.</span> <span class="fu">map</span> (<span class="fu">fmap</span> <span class="fu">negate</span>) <span class="op">.</span> terms</span></code></pre></div>
<p>This representation perhaps maps more closely to the description of
multivariate polynomials that many of us will have encountered in
secondary school: itâ€™s straightforward to see how a polynomial like
<math display="inline">&lt;semantics&gt;<mrow><mn>2</mn><mi>x</mi><mi>y</mi><mo>+</mo><msup><mi>y</mi><mn>2</mn></msup><mo>âˆ’</mo><mn>3</mn></mrow>&lt;annotation encoding="application/x-tex"&gt;2xy + y^2 - 3&lt;/annotation&gt;&lt;/semantics&gt;</math>
corresponds to the value <code class="sourceCode haskell"><span class="dt">Poly</span> [([<span class="dt">X</span>,<span class="dt">Y</span>],<span class="dv">2</span>),([<span class="dt">Y</span>,<span class="dt">Y</span>],<span class="dv">1</span>),([],<span class="op">-</span><span class="dv">3</span>)]</code>.
The previous representation (<code class="sourceCode haskell"><span class="dt">TwoVar</span></code>) would
represent the same expression as the enigmatic <code class="sourceCode haskell">[[<span class="op">-</span><span class="dv">3</span>,<span class="dv">0</span>,<span class="dv">1</span>],[<span class="dv">0</span>,<span class="dv">2</span>]]</code>.</p>
<p>However, there are some wrinkles to this type that are worth noting.
First we can see that multiplication is <em>not</em> commutative (even
after normalisation).</p>
<div class="sourceCode" id="cb21"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb21-1"><a href="https://doisinkidney.com/rss.xml#cb21-1" tabindex="-1"/>x <span class="ot">=</span> <span class="dt">Poly</span> [([<span class="dt">X</span>],<span class="dv">1</span>)]</span>
<span id="cb21-2"><a href="https://doisinkidney.com/rss.xml#cb21-2" tabindex="-1"/>y <span class="ot">=</span> <span class="dt">Poly</span> [([<span class="dt">Y</span>],<span class="dv">1</span>)]</span>
<span id="cb21-3"><a href="https://doisinkidney.com/rss.xml#cb21-3" tabindex="-1"/></span>
<span id="cb21-4"><a href="https://doisinkidney.com/rss.xml#cb21-4" tabindex="-1"/>x <span class="op">*</span> y <span class="op">==</span> <span class="dt">Poly</span> [([<span class="dt">X</span>,<span class="dt">Y</span>],<span class="dv">1</span>)]</span>
<span id="cb21-5"><a href="https://doisinkidney.com/rss.xml#cb21-5" tabindex="-1"/>y <span class="op">*</span> x <span class="op">==</span> <span class="dt">Poly</span> [([<span class="dt">Y</span>,<span class="dt">X</span>],<span class="dv">1</span>)]</span>
<span id="cb21-6"><a href="https://doisinkidney.com/rss.xml#cb21-6" tabindex="-1"/>x <span class="op">*</span> y <span class="op">/=</span> y <span class="op">*</span> x</span></code></pre></div>
<p>This is in contrast to <code class="sourceCode haskell"><span class="dt">TwoVar</span></code>, where
both
<math display="inline">&lt;semantics&gt;<mrow><mi>x</mi><mi>y</mi></mrow>&lt;annotation encoding="application/x-tex"&gt;xy&lt;/annotation&gt;&lt;/semantics&gt;</math>
and
<math display="inline">&lt;semantics&gt;<mrow><mi>y</mi><mi>x</mi></mrow>&lt;annotation encoding="application/x-tex"&gt;yx&lt;/annotation&gt;&lt;/semantics&gt;</math>
would be represented as <code class="sourceCode haskell">[[<span class="dv">0</span>,<span class="dv">0</span>],[<span class="dv">0</span>,<span class="dv">1</span>]]</code>.</p>
<p>Conceptually, polynomials are a kind of <em>free</em> structure: they
represent the normalised and quotiented syntax of an algebraic theory.
The fact that <code class="sourceCode haskell"><span class="dt">Poly</span></code> above
doesnâ€™t have commutative multiplication just tells us that the
underlying algebraic theory in question here is <em>non</em>commutative
rings, rather than commutative rings.</p>
<p>The second thing to note about this type is actually two related
observations about inefficiency. Because I didnâ€™t implement
normalisation on any of the numeric operations, we might expect the size
of the underlying list of <code class="sourceCode haskell"><span class="dt">Poly</span></code> to blow
up:</p>
<div class="sourceCode" id="cb22"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb22-1"><a href="https://doisinkidney.com/rss.xml#cb22-1" tabindex="-1"/>poly <span class="ot">=</span> (<span class="dv">1</span> <span class="op">+</span> x) <span class="op">*</span> (<span class="dv">3</span> <span class="op">+</span> <span class="dv">4</span>) <span class="op">*</span> (y <span class="op">+</span> <span class="dv">2</span>)</span>
<span id="cb22-2"><a href="https://doisinkidney.com/rss.xml#cb22-2" tabindex="-1"/></span>
<span id="cb22-3"><a href="https://doisinkidney.com/rss.xml#cb22-3" tabindex="-1"/><span class="op">&gt;&gt;&gt;</span> terms poly</span>
<span id="cb22-4"><a href="https://doisinkidney.com/rss.xml#cb22-4" tabindex="-1"/>[([<span class="dt">Y</span>],<span class="dv">3</span>),([],<span class="dv">6</span>),([<span class="dt">Y</span>],<span class="dv">4</span>),([],<span class="dv">8</span>),([<span class="dt">X</span>,<span class="dt">Y</span>],<span class="dv">3</span>),([<span class="dt">X</span>],<span class="dv">6</span>),([<span class="dt">X</span>,<span class="dt">Y</span>],<span class="dv">4</span>),([<span class="dt">X</span>],<span class="dv">8</span>)]</span>
<span id="cb22-5"><a href="https://doisinkidney.com/rss.xml#cb22-5" tabindex="-1"/></span>
<span id="cb22-6"><a href="https://doisinkidney.com/rss.xml#cb22-6" tabindex="-1"/><span class="op">&gt;&gt;&gt;</span> norm (terms poly)</span>
<span id="cb22-7"><a href="https://doisinkidney.com/rss.xml#cb22-7" tabindex="-1"/>[([],<span class="dv">14</span>),([<span class="dt">X</span>],<span class="dv">14</span>),([<span class="dt">X</span>,<span class="dt">Y</span>],<span class="dv">7</span>),([<span class="dt">Y</span>],<span class="dv">7</span>)]</span></code></pre></div>
<p>And indeed it does, as you can see above. To counteract this, we can
represent our polynomial as a <em>mapping</em> from monics (strings of
variables) to coefficients:</p>
<div class="sourceCode" id="cb23"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb23-1"><a href="https://doisinkidney.com/rss.xml#cb23-1" tabindex="-1"/><span class="kw">newtype</span> <span class="dt">Poly</span> v c <span class="ot">=</span> <span class="dt">Poly</span> {<span class="ot"> terms ::</span> <span class="dt">Map</span> [v] c }</span></code></pre></div>
<details>

<code class="sourceCode haskell"><span class="dt">Num</span></code>
instance for <code class="sourceCode haskell"><span class="dt">Map</span></code>-based
polynomial

<div class="sourceCode" id="cb24"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb24-1"><a href="https://doisinkidney.com/rss.xml#cb24-1" tabindex="-1"/><span class="kw">instance</span> (<span class="dt">Ord</span> v, <span class="dt">Num</span> c) <span class="ot">=&gt;</span> <span class="dt">Num</span> (<span class="dt">Poly</span> v c) <span class="kw">where</span></span>
<span id="cb24-2"><a href="https://doisinkidney.com/rss.xml#cb24-2" tabindex="-1"/>  <span class="fu">fromInteger</span> n <span class="ot">=</span> <span class="dt">Poly</span> (Map.singleton [] (<span class="fu">fromInteger</span> n))</span>
<span id="cb24-3"><a href="https://doisinkidney.com/rss.xml#cb24-3" tabindex="-1"/>  <span class="dt">Poly</span> xs <span class="op">+</span> <span class="dt">Poly</span> ys <span class="ot">=</span> <span class="dt">Poly</span> (Map.unionWith (<span class="op">+</span>) xs ys)</span>
<span id="cb24-4"><a href="https://doisinkidney.com/rss.xml#cb24-4" tabindex="-1"/>  xs <span class="op">*</span> ys <span class="ot">=</span> <span class="dt">Poly</span> (Map.fromListWith (<span class="op">+</span>) [ (xv <span class="op">++</span> yv, xc <span class="op">*</span> yc)</span>
<span id="cb24-5"><a href="https://doisinkidney.com/rss.xml#cb24-5" tabindex="-1"/>                                       <span class="op">|</span> (xv,xc) <span class="ot">&lt;-</span> Map.toList (terms xs)</span>
<span id="cb24-6"><a href="https://doisinkidney.com/rss.xml#cb24-6" tabindex="-1"/>                                       , (yv,yc) <span class="ot">&lt;-</span> Map.toList (terms ys) ])</span>
<span id="cb24-7"><a href="https://doisinkidney.com/rss.xml#cb24-7" tabindex="-1"/>  <span class="fu">negate</span> <span class="ot">=</span> <span class="dt">Poly</span> <span class="op">.</span> <span class="fu">fmap</span> <span class="fu">negate</span> <span class="op">.</span> terms</span></code></pre></div>
</details>
<p>While this new representation is an improvement over the
un-normalised list, itâ€™s still not really â€œefficientâ€�. In particular,
weâ€™re using lists as keys in the map; Haskellâ€™s <code class="sourceCode haskell"><span class="dt">Map</span></code> is a
binary search tree (though this caveat applies to most mapping
structures), so search is always going to have to perform comparisons on
the keys. When those keys are lists, that comparison takes time
proportional to the length of each list. This is wasted effort that
could be cached with a cleverer data structure.</p>
<p>This also brings the second observation about inefficiency into
focus: we have lost our neat evaluation with Hornerâ€™s rule.</p>
<div class="sourceCode" id="cb25"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb25-1"><a href="https://doisinkidney.com/rss.xml#cb25-1" tabindex="-1"/><span class="ot">eval ::</span> <span class="dt">Num</span> c <span class="ot">=&gt;</span> <span class="dt">Poly</span> v c <span class="ot">-&gt;</span> (v <span class="ot">-&gt;</span> c) <span class="ot">-&gt;</span> c</span>
<span id="cb25-2"><a href="https://doisinkidney.com/rss.xml#cb25-2" tabindex="-1"/>eval (<span class="dt">Poly</span> mp) v <span class="ot">=</span> Map.foldrWithKey (\vs c s <span class="ot">-&gt;</span> <span class="fu">foldr</span> ((<span class="op">*</span>) <span class="op">.</span> v) c vs <span class="op">+</span> s) <span class="dv">0</span> mp</span></code></pre></div>
<p>Weâ€™re back to performing
<math display="inline">&lt;semantics&gt;<mi>n</mi>&lt;annotation encoding="application/x-tex"&gt;n&lt;/annotation&gt;&lt;/semantics&gt;</math>
multiplications per term.</p>
<p>Both of these inefficiencies are actually the same pattern, and can
be solved with a general form of Hornerâ€™s rule. We need to cache
prefixes: the data structure that does that best is a <em>trie</em>.</p>
<h2 id="a-trie">A Trie</h2>
<p>Hornerâ€™s rule saved us from performing redundant multiplications by
factoring out common terms to the left. That was simple to implement in
the single-variable case, but it can still apply for multiple variables.
Take an expression like
<math display="inline">&lt;semantics&gt;<mrow><mo form="prefix" stretchy="false">(</mo><mn>2</mn><mo>+</mo><mn>3</mn><mi>x</mi><mo>âˆ’</mo><mn>5</mn><mi>y</mi><msup><mo form="postfix" stretchy="false">)</mo><mn>2</mn></msup></mrow>&lt;annotation encoding="application/x-tex"&gt;(2 + 3x - 5y) ^ 2&lt;/annotation&gt;&lt;/semantics&gt;</math>,
and multiply it out to
<math display="inline">&lt;semantics&gt;<mrow><mn>4</mn><mo>+</mo><mn>12</mn><mi>x</mi><mo>+</mo><mn>9</mn><msup><mi>x</mi><mn>2</mn></msup><mo>âˆ’</mo><mn>15</mn><mi>x</mi><mi>y</mi><mo>âˆ’</mo><mn>20</mn><mi>y</mi><mo>âˆ’</mo><mn>15</mn><mi>y</mi><mi>x</mi><mo>+</mo><mn>25</mn><msup><mi>y</mi><mn>2</mn></msup></mrow>&lt;annotation encoding="application/x-tex"&gt;4 + 12x + 9x^2 - 15xy - 20y - 15yx + 25y^2&lt;/annotation&gt;&lt;/semantics&gt;</math>.
We can still factor this expression to remove common prefixes, like
so:</p>
<p><math display="inline">&lt;semantics&gt;<mrow><mn>4</mn><mo>+</mo><mi>x</mi><mo form="prefix" stretchy="false">(</mo><mn>12</mn><mo>+</mo><mn>9</mn><mi>x</mi><mo>âˆ’</mo><mn>15</mn><mi>y</mi><mo form="postfix" stretchy="false">)</mo><mo>+</mo><mi>y</mi><mo form="prefix" stretchy="false">(</mo><mi>âˆ’</mi><mn>20</mn><mo>âˆ’</mo><mn>15</mn><mi>x</mi><mo>+</mo><mn>25</mn><mi>y</mi><mo form="postfix" stretchy="false">)</mo></mrow>&lt;annotation encoding="application/x-tex"&gt;4 + x(12 + 9x - 15y) + y(-20 - 15x + 25y)&lt;/annotation&gt;&lt;/semantics&gt;</math></p>
<p>The difference between this factorisation and the list-based
polynomial we started with is that the tree representing the polynomial
only had one child. Here, we have a child for each leading term. In
terms of the data structure, where a <em>list</em> has a single tail in
the cons case,</p>
<div class="sourceCode" id="cb26"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb26-1"><a href="https://doisinkidney.com/rss.xml#cb26-1" tabindex="-1"/><span class="kw">data</span> <span class="dt">List</span> a <span class="ot">=</span> <span class="dt">Nil</span></span>
<span id="cb26-2"><a href="https://doisinkidney.com/rss.xml#cb26-2" tabindex="-1"/>            <span class="op">|</span> <span class="dt">Cons</span> a (<span class="dt">List</span> a)</span></code></pre></div>
<p>The multivariate version of the same thing will be a
<em>tree</em></p>
<div class="sourceCode" id="cb27"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb27-1"><a href="https://doisinkidney.com/rss.xml#cb27-1" tabindex="-1"/><span class="kw">data</span> <span class="dt">Tree</span> a <span class="ot">=</span> <span class="dt">Nil</span></span>
<span id="cb27-2"><a href="https://doisinkidney.com/rss.xml#cb27-2" tabindex="-1"/>            <span class="op">|</span> <span class="dt">Cons</span> a [<span class="dt">Tree</span> a]</span></code></pre></div>
<p>Or, more specifically, a <em>trie</em>, where the subtree mapping is
based on variables.</p>
<div class="sourceCode" id="cb28"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb28-1"><a href="https://doisinkidney.com/rss.xml#cb28-1" tabindex="-1"/><span class="kw">data</span> <span class="dt">Poly</span> v c <span class="ot">=</span> c <span class="op">:&lt;+</span> <span class="dt">Map</span> v (<span class="dt">Poly</span> v c)</span></code></pre></div>
<p>A polynomial is a constant coefficient <code class="sourceCode haskell">c</code> plus the sum of variables drawn from
<code class="sourceCode haskell">v</code> each multiplied by another
polynomial. The polynomial above is represented with this type as the
following:</p>
<div class="sourceCode" id="cb29"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb29-1"><a href="https://doisinkidney.com/rss.xml#cb29-1" tabindex="-1"/><span class="dv">4</span> <span class="op">:&lt;+</span> {(<span class="dt">X</span>,<span class="dv">12</span> <span class="op">:&lt;+</span> {(<span class="dt">X</span>,<span class="dv">9</span> <span class="op">:&lt;+</span> {}),(<span class="dt">Y</span>,(<span class="op">-</span><span class="dv">15</span>) <span class="op">:&lt;+</span> {})}),(<span class="dt">Y</span>,(<span class="op">-</span><span class="dv">20</span>) <span class="op">:&lt;+</span> {(<span class="dt">X</span>,(<span class="op">-</span><span class="dv">15</span>) <span class="op">:&lt;+</span> {}),(<span class="dt">Y</span>,<span class="dv">25</span> <span class="op">:&lt;+</span> {})})}</span></code></pre></div>
<p>This trie type (with some improvements Iâ€™ll describe below) is the
focus of this post; I think itâ€™s a cool data structure for representing
polynomials.</p>
<h2 id="the-numeric-functions-on-tries">The numeric functions on
Tries</h2>
<p>Letâ€™s first write evaluation:</p>
<div class="sourceCode" id="cb30"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb30-1"><a href="https://doisinkidney.com/rss.xml#cb30-1" tabindex="-1"/><span class="ot">eval ::</span> <span class="dt">Num</span> c <span class="ot">=&gt;</span> (v <span class="ot">-&gt;</span> c) <span class="ot">-&gt;</span> <span class="dt">Poly</span> v c <span class="ot">-&gt;</span> c</span>
<span id="cb30-2"><a href="https://doisinkidney.com/rss.xml#cb30-2" tabindex="-1"/>eval f (c <span class="op">:&lt;+</span> vs) <span class="ot">=</span> c <span class="op">+</span> Map.foldrWithKey (\v p s <span class="ot">-&gt;</span> f v <span class="op">*</span> eval f p <span class="op">+</span> s) <span class="dv">0</span> vs</span></code></pre></div>
<p>Notice that we have retrieved Hornerâ€™s rule: the evaluation of each
term only performs a single multiplication; we donâ€™t have to repeat
multiplications for terms that share prefixes any more.</p>
<p>(for those concerned with performance, it might be worth swapping out
<code class="sourceCode haskell">foldrWithKey</code> with a strict
variant. (also, this is somewhat unrelated but a bit of a pet peeve of
mine: this is <em>not</em> a place where <code class="sourceCode haskell">foldl'</code> is the best option! <code class="sourceCode haskell">foldl'</code> is not a panacea!))</p>
<p>The numeric operations on this data structure can be implemented as
follows:</p>
<div class="sourceCode" id="cb31"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb31-1"><a href="https://doisinkidney.com/rss.xml#cb31-1" tabindex="-1"/><span class="kw">deriving</span> <span class="kw">instance</span> <span class="dt">Functor</span> (<span class="dt">Poly</span> v)</span>
<span id="cb31-2"><a href="https://doisinkidney.com/rss.xml#cb31-2" tabindex="-1"/></span>
<span id="cb31-3"><a href="https://doisinkidney.com/rss.xml#cb31-3" tabindex="-1"/><span class="kw">instance</span> (<span class="dt">Ord</span> v, <span class="dt">Num</span> c, <span class="dt">Eq</span> c) <span class="ot">=&gt;</span> <span class="dt">Num</span> (<span class="dt">Poly</span> v c) <span class="kw">where</span></span>
<span id="cb31-4"><a href="https://doisinkidney.com/rss.xml#cb31-4" tabindex="-1"/>  <span class="fu">fromInteger</span> n <span class="ot">=</span> <span class="fu">fromInteger</span> n <span class="op">:&lt;+</span> Map.empty</span>
<span id="cb31-5"><a href="https://doisinkidney.com/rss.xml#cb31-5" tabindex="-1"/>  (n <span class="op">:&lt;+</span> ns) <span class="op">+</span> (m <span class="op">:&lt;+</span> ms) <span class="ot">=</span> (n <span class="op">+</span> m) <span class="op">:&lt;+</span> Map.unionWith (<span class="op">+</span>) ns ms</span>
<span id="cb31-6"><a href="https://doisinkidney.com/rss.xml#cb31-6" tabindex="-1"/>  (n <span class="op">:&lt;+</span> ns) <span class="op">*</span> ms <span class="ot">=</span> <span class="fu">fmap</span> (n<span class="op">*</span>) ms <span class="op">+</span> (<span class="dv">0</span> <span class="op">:&lt;+</span> <span class="fu">fmap</span> (<span class="op">*</span>ms) ns)</span>
<span id="cb31-7"><a href="https://doisinkidney.com/rss.xml#cb31-7" tabindex="-1"/>  <span class="fu">negate</span> <span class="ot">=</span> <span class="fu">fmap</span> <span class="fu">negate</span></span></code></pre></div>
<p>Itâ€™s worth taking a moment to note how efficient these operations are
(for a pointer-ridden high-level language like Haskell, that is). We
donâ€™t have to compare any strings; we can use <code class="sourceCode haskell"><span class="dt">Data.Map</span></code>â€™s
efficient <code class="sourceCode haskell">unionWith</code> on single
variables; and multiplication doesnâ€™t have to expand out any Cartesian
product.</p>
<p>I will note that we do have to perform a little bit of normalisation
for the derived <code class="sourceCode haskell"><span class="dt">Eq</span></code> instance to
be correct: we have to remove terms that multiply to zeros. Pruning dead
branches like this is a pretty standard procedure on tries; in
polynomial terms, that just means we have to get rid of entries in the
map that evaluate to zero (so
<math display="inline">&lt;semantics&gt;<mrow><mi>x</mi><mo form="prefix" stretchy="false">(</mo><mn>2</mn><mo>+</mo><mi>y</mi><mo form="postfix" stretchy="false">)</mo><mo>+</mo><mi>y</mi><mo form="prefix" stretchy="false">(</mo><mn>0</mn><mo form="postfix" stretchy="false">)</mo></mrow>&lt;annotation encoding="application/x-tex"&gt;x(2 + y) + y(0)&lt;/annotation&gt;&lt;/semantics&gt;</math>
should be pruned to
<math display="inline">&lt;semantics&gt;<mrow><mi>x</mi><mo form="prefix" stretchy="false">(</mo><mn>2</mn><mo>+</mo><mi>y</mi><mo form="postfix" stretchy="false">)</mo></mrow>&lt;annotation encoding="application/x-tex"&gt;x(2 + y)&lt;/annotation&gt;&lt;/semantics&gt;</math>).
This can be done without really changing the efficiency of the
operations above, but it does make them slightly more verbose.</p>
<details>

Normalising <code class="sourceCode haskell"><span class="dt">Num</span></code> instance

<p>For this version, we will rely on the extremely efficient <a href="https://hackage.haskell.org/package/containers-0.8/docs/Data-Map-Merge-Strict.html">custom
merge operations in containers</a>.</p>
<div class="sourceCode" id="cb32"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb32-1"><a href="https://doisinkidney.com/rss.xml#cb32-1" tabindex="-1"/><span class="dv">0</span> <span class="op">&lt;+?</span> ns <span class="op">|</span> Map.null ns <span class="ot">=</span> <span class="dt">Nothing</span></span>
<span id="cb32-2"><a href="https://doisinkidney.com/rss.xml#cb32-2" tabindex="-1"/>n <span class="op">&lt;+?</span> ns <span class="ot">=</span> <span class="dt">Just</span> (n <span class="op">:&lt;+</span> ns)</span>
<span id="cb32-3"><a href="https://doisinkidney.com/rss.xml#cb32-3" tabindex="-1"/></span>
<span id="cb32-4"><a href="https://doisinkidney.com/rss.xml#cb32-4" tabindex="-1"/><span class="kw">instance</span> (<span class="dt">Ord</span> v, <span class="dt">Num</span> c, <span class="dt">Eq</span> c) <span class="ot">=&gt;</span> <span class="dt">Num</span> (<span class="dt">Poly</span> v c) <span class="kw">where</span></span>
<span id="cb32-5"><a href="https://doisinkidney.com/rss.xml#cb32-5" tabindex="-1"/>  <span class="fu">fromInteger</span> n <span class="ot">=</span> <span class="fu">fromInteger</span> n <span class="op">:&lt;+</span> Map.empty</span>
<span id="cb32-6"><a href="https://doisinkidney.com/rss.xml#cb32-6" tabindex="-1"/></span>
<span id="cb32-7"><a href="https://doisinkidney.com/rss.xml#cb32-7" tabindex="-1"/>  a <span class="op">+</span> b <span class="ot">=</span> fromMaybe <span class="dv">0</span> (add a b)</span>
<span id="cb32-8"><a href="https://doisinkidney.com/rss.xml#cb32-8" tabindex="-1"/>    <span class="kw">where</span></span>
<span id="cb32-9"><a href="https://doisinkidney.com/rss.xml#cb32-9" tabindex="-1"/>      add (n <span class="op">:&lt;+</span> ns) (m <span class="op">:&lt;+</span> ms) <span class="ot">=</span></span>
<span id="cb32-10"><a href="https://doisinkidney.com/rss.xml#cb32-10" tabindex="-1"/>        (n <span class="op">+</span> m) <span class="op">&lt;+?</span></span>
<span id="cb32-11"><a href="https://doisinkidney.com/rss.xml#cb32-11" tabindex="-1"/>          Map.merge</span>
<span id="cb32-12"><a href="https://doisinkidney.com/rss.xml#cb32-12" tabindex="-1"/>            Map.preserveMissing</span>
<span id="cb32-13"><a href="https://doisinkidney.com/rss.xml#cb32-13" tabindex="-1"/>            Map.preserveMissing</span>
<span id="cb32-14"><a href="https://doisinkidney.com/rss.xml#cb32-14" tabindex="-1"/>            (Map.zipWithMaybeMatched (<span class="fu">const</span> add))</span>
<span id="cb32-15"><a href="https://doisinkidney.com/rss.xml#cb32-15" tabindex="-1"/>            ns ms</span>
<span id="cb32-16"><a href="https://doisinkidney.com/rss.xml#cb32-16" tabindex="-1"/></span>
<span id="cb32-17"><a href="https://doisinkidney.com/rss.xml#cb32-17" tabindex="-1"/>  _ <span class="op">*</span> (<span class="dv">0</span> <span class="op">:&lt;+</span> ms) <span class="op">|</span> Map.null ms <span class="ot">=</span> <span class="dv">0</span> <span class="op">:&lt;+</span> Map.empty</span>
<span id="cb32-18"><a href="https://doisinkidney.com/rss.xml#cb32-18" tabindex="-1"/>  (<span class="dv">0</span> <span class="op">:&lt;+</span> ns) <span class="op">*</span> ms <span class="ot">=</span> <span class="dv">0</span> <span class="op">:&lt;+</span> <span class="fu">fmap</span> (<span class="op">*</span>ms) ns</span>
<span id="cb32-19"><a href="https://doisinkidney.com/rss.xml#cb32-19" tabindex="-1"/>  (n <span class="op">:&lt;+</span> ns) <span class="op">*</span> ms <span class="ot">=</span> <span class="fu">fmap</span> (n<span class="op">*</span>) ms <span class="op">+</span> (<span class="dv">0</span> <span class="op">:&lt;+</span> <span class="fu">fmap</span> (<span class="op">*</span>ms) ns)</span>
<span id="cb32-20"><a href="https://doisinkidney.com/rss.xml#cb32-20" tabindex="-1"/></span>
<span id="cb32-21"><a href="https://doisinkidney.com/rss.xml#cb32-21" tabindex="-1"/></span>
<span id="cb32-22"><a href="https://doisinkidney.com/rss.xml#cb32-22" tabindex="-1"/>  <span class="fu">negate</span> <span class="ot">=</span> <span class="fu">fmap</span> <span class="fu">negate</span></span>
<span id="cb32-23"><a href="https://doisinkidney.com/rss.xml#cb32-23" tabindex="-1"/>  <span class="fu">abs</span> <span class="ot">=</span> <span class="fu">fmap</span> <span class="fu">abs</span></span>
<span id="cb32-24"><a href="https://doisinkidney.com/rss.xml#cb32-24" tabindex="-1"/>  <span class="fu">signum</span> (n <span class="op">:&lt;+</span> _) <span class="ot">=</span> <span class="fu">signum</span> n <span class="op">:&lt;+</span> Map.empty</span></code></pre></div>
</details>
<p>Anyways, when we have all of the above instances, we can manipulate
polynomials using the API you might expect, and the normalisation
behaviour happens automatically.</p>
<div class="sourceCode" id="cb33"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb33-1"><a href="https://doisinkidney.com/rss.xml#cb33-1" tabindex="-1"/><span class="kw">data</span> <span class="dt">Var</span> <span class="ot">=</span> <span class="dt">X</span> <span class="op">|</span> <span class="dt">Y</span> <span class="kw">deriving</span> (<span class="dt">Eq</span>, <span class="dt">Ord</span>, <span class="dt">Show</span>)</span>
<span id="cb33-2"><a href="https://doisinkidney.com/rss.xml#cb33-2" tabindex="-1"/></span>
<span id="cb33-3"><a href="https://doisinkidney.com/rss.xml#cb33-3" tabindex="-1"/><span class="ot">var ::</span> <span class="dt">Num</span> c <span class="ot">=&gt;</span> v <span class="ot">-&gt;</span> <span class="dt">Poly</span> v c</span>
<span id="cb33-4"><a href="https://doisinkidney.com/rss.xml#cb33-4" tabindex="-1"/>var v <span class="ot">=</span> <span class="dv">0</span> <span class="op">:&lt;+</span> Map.singleton v (<span class="dv">1</span> <span class="op">:&lt;+</span> Map.empty)</span>
<span id="cb33-5"><a href="https://doisinkidney.com/rss.xml#cb33-5" tabindex="-1"/></span>
<span id="cb33-6"><a href="https://doisinkidney.com/rss.xml#cb33-6" tabindex="-1"/>x,<span class="ot">y ::</span> <span class="dt">Poly</span> <span class="dt">Var</span> <span class="dt">Integer</span></span>
<span id="cb33-7"><a href="https://doisinkidney.com/rss.xml#cb33-7" tabindex="-1"/>x <span class="ot">=</span> var <span class="dt">X</span></span>
<span id="cb33-8"><a href="https://doisinkidney.com/rss.xml#cb33-8" tabindex="-1"/>y <span class="ot">=</span> var <span class="dt">Y</span></span>
<span id="cb33-9"><a href="https://doisinkidney.com/rss.xml#cb33-9" tabindex="-1"/></span>
<span id="cb33-10"><a href="https://doisinkidney.com/rss.xml#cb33-10" tabindex="-1"/>poly <span class="ot">=</span> (<span class="dv">2</span> <span class="op">+</span> <span class="dv">3</span> <span class="op">*</span> x <span class="op">-</span> <span class="dv">5</span> <span class="op">*</span> y) <span class="op">^</span> <span class="dv">2</span></span>
<span id="cb33-11"><a href="https://doisinkidney.com/rss.xml#cb33-11" tabindex="-1"/><span class="op">&gt;&gt;&gt;</span> poly</span>
<span id="cb33-12"><a href="https://doisinkidney.com/rss.xml#cb33-12" tabindex="-1"/><span class="dv">4</span> <span class="op">+</span> <span class="dt">Y</span><span class="op">*</span>(<span class="op">-</span><span class="dv">20</span> <span class="op">+</span> <span class="dt">Y</span><span class="op">*</span><span class="dv">25</span> <span class="op">+</span> <span class="dt">X</span><span class="op">*</span>(<span class="op">-</span><span class="dv">15</span>)) <span class="op">+</span> <span class="dt">X</span><span class="op">*</span>(<span class="dv">12</span> <span class="op">+</span> <span class="dt">Y</span><span class="op">*</span>(<span class="op">-</span><span class="dv">15</span>) <span class="op">+</span> <span class="dt">X</span><span class="op">*</span><span class="dv">9</span>)</span></code></pre></div>
<h2 id="lenses-and-division">Lenses and Division</h2>
<p><a href="https://www.youtube.com/watch?v=cefnmjtAolY">Lenses</a> in
Haskell are very cool, and personally I think one of the best
demonstrations of their power is tries. A few years ago, when I was
still on Twitter, I posted an implementation of a trie that fit in a
tweet (<a href="https://gist.github.com/oisdk/0306b5849207e1e03fc23d79148d4c3d">gist
link</a>).</p>
<details>

Tweet Trie

<div class="sourceCode" id="cb34"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb34-1"><a href="https://doisinkidney.com/rss.xml#cb34-1" tabindex="-1"/><span class="ot">{-# LANGUAGE RankNTypes #-}</span></span>
<span id="cb34-2"><a href="https://doisinkidney.com/rss.xml#cb34-2" tabindex="-1"/></span>
<span id="cb34-3"><a href="https://doisinkidney.com/rss.xml#cb34-3" tabindex="-1"/><span class="kw">import</span> <span class="dt">Control.Comonad.Cofree</span></span>
<span id="cb34-4"><a href="https://doisinkidney.com/rss.xml#cb34-4" tabindex="-1"/><span class="kw">import</span> <span class="dt">Control.Lens</span> <span class="kw">hiding</span> ((:&lt;))</span>
<span id="cb34-5"><a href="https://doisinkidney.com/rss.xml#cb34-5" tabindex="-1"/><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Data.Map</span> <span class="kw">as</span> <span class="dt">Map</span></span>
<span id="cb34-6"><a href="https://doisinkidney.com/rss.xml#cb34-6" tabindex="-1"/><span class="kw">import</span> <span class="dt">Data.Map</span> (<span class="dt">Map</span>)</span>
<span id="cb34-7"><a href="https://doisinkidney.com/rss.xml#cb34-7" tabindex="-1"/><span class="kw">import</span> <span class="dt">Prelude</span> <span class="kw">hiding</span> (lookup)</span>
<span id="cb34-8"><a href="https://doisinkidney.com/rss.xml#cb34-8" tabindex="-1"/><span class="kw">import</span> <span class="dt">Data.Maybe</span> (isJust)</span>
<span id="cb34-9"><a href="https://doisinkidney.com/rss.xml#cb34-9" tabindex="-1"/><span class="kw">import</span> <span class="dt">Test.QuickCheck</span></span>
<span id="cb34-10"><a href="https://doisinkidney.com/rss.xml#cb34-10" tabindex="-1"/></span>
<span id="cb34-11"><a href="https://doisinkidney.com/rss.xml#cb34-11" tabindex="-1"/><span class="kw">type</span> <span class="dt">Trie</span> a b <span class="ot">=</span> <span class="dt">Cofree</span> (<span class="dt">Map</span> a) (<span class="dt">Maybe</span> b)</span>
<span id="cb34-12"><a href="https://doisinkidney.com/rss.xml#cb34-12" tabindex="-1"/></span>
<span id="cb34-13"><a href="https://doisinkidney.com/rss.xml#cb34-13" tabindex="-1"/><span class="ot">string ::</span> <span class="dt">Ord</span> a <span class="ot">=&gt;</span> [a] <span class="ot">-&gt;</span> <span class="dt">Lens'</span> (<span class="dt">Trie</span> a b) (<span class="dt">Maybe</span> b)</span>
<span id="cb34-14"><a href="https://doisinkidney.com/rss.xml#cb34-14" tabindex="-1"/>string <span class="ot">=</span></span>
<span id="cb34-15"><a href="https://doisinkidney.com/rss.xml#cb34-15" tabindex="-1"/> <span class="fu">foldr</span></span>
<span id="cb34-16"><a href="https://doisinkidney.com/rss.xml#cb34-16" tabindex="-1"/>   (\x r <span class="ot">-&gt;</span> _unwrap <span class="op">.</span> at x <span class="op">.</span> anon (<span class="dt">Nothing</span> <span class="op">:&lt;</span> <span class="fu">mempty</span>)</span>
<span id="cb34-17"><a href="https://doisinkidney.com/rss.xml#cb34-17" tabindex="-1"/>                                  (\(v <span class="op">:&lt;</span> m) <span class="ot">-&gt;</span> <span class="fu">null</span> v <span class="op">&amp;&amp;</span> <span class="fu">null</span> m) <span class="op">.</span> r)</span>
<span id="cb34-18"><a href="https://doisinkidney.com/rss.xml#cb34-18" tabindex="-1"/>   _extract</span>
<span id="cb34-19"><a href="https://doisinkidney.com/rss.xml#cb34-19" tabindex="-1"/></span>
<span id="cb34-20"><a href="https://doisinkidney.com/rss.xml#cb34-20" tabindex="-1"/></span>
<span id="cb34-21"><a href="https://doisinkidney.com/rss.xml#cb34-21" tabindex="-1"/><span class="ot">insert ::</span> <span class="dt">Ord</span> a <span class="ot">=&gt;</span> [a] <span class="ot">-&gt;</span> b <span class="ot">-&gt;</span> <span class="dt">Trie</span> a b <span class="ot">-&gt;</span> <span class="dt">Trie</span> a b</span>
<span id="cb34-22"><a href="https://doisinkidney.com/rss.xml#cb34-22" tabindex="-1"/>insert xs x <span class="ot">=</span> string xs <span class="op">.~</span> <span class="dt">Just</span> x</span>
<span id="cb34-23"><a href="https://doisinkidney.com/rss.xml#cb34-23" tabindex="-1"/></span>
<span id="cb34-24"><a href="https://doisinkidney.com/rss.xml#cb34-24" tabindex="-1"/><span class="fu">lookup</span><span class="ot"> ::</span> <span class="dt">Ord</span> a <span class="ot">=&gt;</span> [a] <span class="ot">-&gt;</span> <span class="dt">Trie</span> a b <span class="ot">-&gt;</span> <span class="dt">Maybe</span> b</span>
<span id="cb34-25"><a href="https://doisinkidney.com/rss.xml#cb34-25" tabindex="-1"/><span class="fu">lookup</span> <span class="ot">=</span> view <span class="op">.</span> string</span>
<span id="cb34-26"><a href="https://doisinkidney.com/rss.xml#cb34-26" tabindex="-1"/></span>
<span id="cb34-27"><a href="https://doisinkidney.com/rss.xml#cb34-27" tabindex="-1"/><span class="ot">delete ::</span> <span class="dt">Ord</span> a <span class="ot">=&gt;</span> [a] <span class="ot">-&gt;</span> <span class="dt">Trie</span> a b <span class="ot">-&gt;</span> <span class="dt">Trie</span> a b</span>
<span id="cb34-28"><a href="https://doisinkidney.com/rss.xml#cb34-28" tabindex="-1"/>delete xs <span class="ot">=</span> string xs <span class="op">.~</span> <span class="dt">Nothing</span></span></code></pre></div>
</details>
<p>Lenses are what allowed this very terse implementation. The original
purpose of lenses was to facilitate deep access in nested records and
data structures: a trie is effectively a nested map, so itâ€™s no great
surprise that lenses are a good fit.</p>
<p>It turns out that lenses are also useful for manipulating polynomial
tries. At first, it might be difficult to see why: in the trie
implementation above, a lens was used to build getters and setters for a
mapping from strings to payloads. But what does that translate to in the
context of a polynomial? What does it mean to â€œlook upâ€� a string of
variables in some expression like
<math display="inline">&lt;semantics&gt;<mrow><mn>2</mn><msup><mi>x</mi><mn>2</mn></msup><mo>+</mo><mi>y</mi></mrow>&lt;annotation encoding="application/x-tex"&gt;2x^2 + y&lt;/annotation&gt;&lt;/semantics&gt;</math>?</p>
<p>It turns out that lookups corresponds to <em>division</em>. For
example, dividing the polynomial
<math display="inline">&lt;semantics&gt;<mrow><mn>2</mn><msup><mi>x</mi><mn>2</mn></msup><mo>+</mo><mi>y</mi></mrow>&lt;annotation encoding="application/x-tex"&gt;2x^2 + y&lt;/annotation&gt;&lt;/semantics&gt;</math>
by the monic
<math display="inline">&lt;semantics&gt;<mrow><mi>x</mi><mi>x</mi></mrow>&lt;annotation encoding="application/x-tex"&gt;xx&lt;/annotation&gt;&lt;/semantics&gt;</math>
gives us a quotient
<math display="inline">&lt;semantics&gt;<mn>2</mn>&lt;annotation encoding="application/x-tex"&gt;2&lt;/annotation&gt;&lt;/semantics&gt;</math>
and remainder
<math display="inline">&lt;semantics&gt;<mi>y</mi>&lt;annotation encoding="application/x-tex"&gt;y&lt;/annotation&gt;&lt;/semantics&gt;</math>.</p>
<div class="sourceCode" id="cb35"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb35-1"><a href="https://doisinkidney.com/rss.xml#cb35-1" tabindex="-1"/><span class="op">&gt;&gt;&gt;</span> <span class="fu">divMod</span> (<span class="dv">2</span> <span class="op">*</span> x <span class="op">^</span> <span class="dv">2</span> <span class="op">+</span> y) [<span class="dt">X</span>,<span class="dt">X</span>]</span>
<span id="cb35-2"><a href="https://doisinkidney.com/rss.xml#cb35-2" tabindex="-1"/>(<span class="dv">2</span>, y)</span></code></pre></div>
<p>This is already quite similar to a lens: before the van Laarhoven
encoding, lenses were usually thought of as functions that took a data
structure and returned a pair of the â€œfocusâ€� of the lens and the â€œrestâ€�
of the structure. In polynomial terms, that â€œfocusâ€� is the quotient, and
the â€œrestâ€� is the remainder.</p>
<p>But thatâ€™s a little vague. Letâ€™s construct the actual lenses here, in
the van Laarhoven style:</p>
<div class="sourceCode" id="cb36"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb36-1"><a href="https://doisinkidney.com/rss.xml#cb36-1" tabindex="-1"/><span class="ot">constant ::</span> <span class="dt">Lens'</span> (<span class="dt">Poly</span> v c) c</span>
<span id="cb36-2"><a href="https://doisinkidney.com/rss.xml#cb36-2" tabindex="-1"/>constant f (c <span class="op">:&lt;+</span> vs) <span class="ot">=</span> <span class="fu">fmap</span> (<span class="op">:&lt;+</span> vs) (f c)</span>
<span id="cb36-3"><a href="https://doisinkidney.com/rss.xml#cb36-3" tabindex="-1"/></span>
<span id="cb36-4"><a href="https://doisinkidney.com/rss.xml#cb36-4" tabindex="-1"/><span class="ot">vars ::</span> <span class="dt">Lens</span> (<span class="dt">Poly</span> v c) (<span class="dt">Poly</span> v' c) (<span class="dt">Map</span> v (<span class="dt">Poly</span> v c)) (<span class="dt">Map</span> v' (<span class="dt">Poly</span> v' c))</span>
<span id="cb36-5"><a href="https://doisinkidney.com/rss.xml#cb36-5" tabindex="-1"/>vars f (c <span class="op">:&lt;+</span> vs) <span class="ot">=</span> <span class="fu">fmap</span> (c <span class="op">:&lt;+</span>) (f vs)</span>
<span id="cb36-6"><a href="https://doisinkidney.com/rss.xml#cb36-6" tabindex="-1"/></span>
<span id="cb36-7"><a href="https://doisinkidney.com/rss.xml#cb36-7" tabindex="-1"/><span class="ot">isZero ::</span> (<span class="dt">Num</span> c, <span class="dt">Eq</span> c) <span class="ot">=&gt;</span> <span class="dt">Poly</span> v c <span class="ot">-&gt;</span> <span class="dt">Bool</span></span>
<span id="cb36-8"><a href="https://doisinkidney.com/rss.xml#cb36-8" tabindex="-1"/>isZero (n <span class="op">:&lt;+</span> ns) <span class="ot">=</span> (<span class="dv">0</span> <span class="op">==</span> n) <span class="op">&amp;&amp;</span> Map.null ns</span>
<span id="cb36-9"><a href="https://doisinkidney.com/rss.xml#cb36-9" tabindex="-1"/></span>
<span id="cb36-10"><a href="https://doisinkidney.com/rss.xml#cb36-10" tabindex="-1"/><span class="ot">factored ::</span> (<span class="dt">Ord</span> v, <span class="dt">Num</span> c, <span class="dt">Eq</span> c) <span class="ot">=&gt;</span> [v] <span class="ot">-&gt;</span> <span class="dt">Lens'</span> (<span class="dt">Poly</span> v c) (<span class="dt">Poly</span> v c)</span>
<span id="cb36-11"><a href="https://doisinkidney.com/rss.xml#cb36-11" tabindex="-1"/>factored <span class="ot">=</span> <span class="fu">foldr</span> (\v vs <span class="ot">-&gt;</span> vars <span class="op">.</span> at v <span class="op">.</span> anon <span class="dv">0</span> isZero <span class="op">.</span> vs) <span class="fu">id</span></span></code></pre></div>
<p>This last lens does indeed give us an interface that looks like
division:</p>
<div class="sourceCode" id="cb37"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb37-1"><a href="https://doisinkidney.com/rss.xml#cb37-1" tabindex="-1"/><span class="op">&gt;&gt;&gt;</span> view (factored [<span class="dt">X</span>,<span class="dt">X</span>]) (<span class="dv">2</span><span class="op">*</span>x<span class="op">^</span><span class="dv">2</span> <span class="op">+</span> y)</span>
<span id="cb37-2"><a href="https://doisinkidney.com/rss.xml#cb37-2" tabindex="-1"/><span class="dv">2</span></span>
<span id="cb37-3"><a href="https://doisinkidney.com/rss.xml#cb37-3" tabindex="-1"/></span>
<span id="cb37-4"><a href="https://doisinkidney.com/rss.xml#cb37-4" tabindex="-1"/><span class="op">&gt;&gt;&gt;</span> set (factored [<span class="dt">X</span>,<span class="dt">X</span>]) <span class="dv">0</span> (<span class="dv">2</span><span class="op">*</span>x<span class="op">^</span><span class="dv">2</span> <span class="op">+</span> y)</span>
<span id="cb37-5"><a href="https://doisinkidney.com/rss.xml#cb37-5" tabindex="-1"/><span class="dt">Y</span></span></code></pre></div>
<p>If we want to define an actual division function, we can define it in
terms of <code class="sourceCode haskell">factored</code>, in a fun
example of the kind of golfy code that lens enables.</p>
<div class="sourceCode" id="cb38"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb38-1"><a href="https://doisinkidney.com/rss.xml#cb38-1" tabindex="-1"/><span class="fu">divMod</span><span class="ot"> ::</span> (<span class="dt">Ord</span> v, <span class="dt">Num</span> c, <span class="dt">Eq</span> c) <span class="ot">=&gt;</span> <span class="dt">Poly</span> v c <span class="ot">-&gt;</span> [v] <span class="ot">-&gt;</span> (<span class="dt">Poly</span> v c,<span class="dt">Poly</span> v c)</span>
<span id="cb38-2"><a href="https://doisinkidney.com/rss.xml#cb38-2" tabindex="-1"/><span class="fu">divMod</span> p vs <span class="ot">=</span> factored vs (,<span class="dv">0</span>) p</span>
<span id="cb38-3"><a href="https://doisinkidney.com/rss.xml#cb38-3" tabindex="-1"/></span>
<span id="cb38-4"><a href="https://doisinkidney.com/rss.xml#cb38-4" tabindex="-1"/><span class="op">&gt;&gt;&gt;</span> (<span class="dv">2</span><span class="op">*</span>x<span class="op">^</span><span class="dv">2</span> <span class="op">+</span> y) <span class="ot">`divMod`</span> [<span class="dt">X</span>,<span class="dt">X</span>]</span>
<span id="cb38-5"><a href="https://doisinkidney.com/rss.xml#cb38-5" tabindex="-1"/>(<span class="dv">2</span>,<span class="dt">Y</span>)</span></code></pre></div>
<h2 id="gr&#xC3;&#xB6;bner-bases">GrÃ¶bner Bases</h2>
<p>While the interface above lets us do some basic computer algebra, to
do any serious work with polynomials we will have to at some point
compute GrÃ¶bner bases. A GrÃ¶bner basis isâ€¦ somewhat hard to define,
actually. Iâ€™ll quote an explainer on the topic by <span class="citation">Sturmfels (<a href="https://doisinkidney.com/rss.xml#ref-sturmfels_what_2005">2005</a>)</span>:</p>
<blockquote>
<p>A GrÃ¶bner basis is a set of multivariate polynomials that has
desirable algorithmic properties</p>
</blockquote>
<p>Basically, in several algorithms over polynomials (division, Gaussian
elimination, etc.) it becomes necessary at some point to compute this
thing called a GrÃ¶bner Basis.</p>
<p>There is a lot of published literature on computing GrÃ¶bner bases in
different settings. However, the trie polynomial I have built above is
fundamentally <em>non</em>commutative, and the literature on computing
GrÃ¶bner bases for noncommutative rings is comparatively smaller. I have
been following Xiuâ€™s thesis <span class="citation">(<a href="https://doisinkidney.com/rss.xml#ref-xiu_noncommutative_2012">2012</a>)</span> for this project. It outlines a
noncommutative version of Buchbergerâ€™s algorithm, and a few
optimisations that I was able to implement.</p>
<p>One slightly annoying aspect of these algorithms is that they tend to
use <em>monomials</em> as a primitive. In other words, instead of
working with the polynomial directly, the algorithms tend to describe
operations with the assumption that your representation is basically a
list of monomials. In particular, the algorithms will frequently extract
the â€œleadingâ€� monomial, and it becomes important for performance that
the polynomial representation can provide that leading monomial quickly.
Unfortunately, extraction of the leading monomial is slightly awkward on
the trie representation (or certainly less natural than the
implementation on a listed representation); so we will need to do some
work to implement it.</p>
<h2 id="monomial-orderings">Monomial Orderings</h2>
<p>The first important concept to implement for GrÃ¶bner bases is an
admissible monomial ordering. This is a total order on strings of
variables that is â€œadmissibleâ€�; meaning that it respects concatenation
on both sides, and it also is a well-ordering, meaning that any strictly
descending chain is finite.</p>
<p><math display="inline">&lt;semantics&gt;<mrow><mi>a</mi><mo>&lt;</mo><mi>b</mi><mo>âŸ¹</mo><mi>a</mi><mo>â€¢</mo><mi>c</mi><mo>&lt;</mo><mi>b</mi><mo>â€¢</mo><mi>c</mi></mrow>&lt;annotation encoding="application/x-tex"&gt;a &lt; b \implies a \bullet c &lt; b \bullet c&lt;/annotation&gt;&lt;/semantics&gt;</math></p>
<p><math display="inline">&lt;semantics&gt;<mrow><mi>a</mi><mo>&lt;</mo><mi>b</mi><mo>âŸ¹</mo><mi>c</mi><mo>â€¢</mo><mi>a</mi><mo>&lt;</mo><mi>c</mi><mo>â€¢</mo><mi>b</mi></mrow>&lt;annotation encoding="application/x-tex"&gt;a &lt; b \implies c \bullet a &lt; c \bullet b&lt;/annotation&gt;&lt;/semantics&gt;</math></p>
<p>These constraints rule out the usual lexicographic ordering on
strings. Instead, weâ€™ll go with <em>graded</em> lexicographic. This
means we first compare strings for length, and only in the case where
theyâ€™re equal do we move to the normal lexicographic comparison.</p>
<div class="sourceCode" id="cb39"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb39-1"><a href="https://doisinkidney.com/rss.xml#cb39-1" tabindex="-1"/><span class="ot">grlex ::</span> <span class="dt">Ord</span> a <span class="ot">=&gt;</span> [a] <span class="ot">-&gt;</span> [a] <span class="ot">-&gt;</span> <span class="dt">Ordering</span></span>
<span id="cb39-2"><a href="https://doisinkidney.com/rss.xml#cb39-2" tabindex="-1"/>grlex xs ys</span>
<span id="cb39-3"><a href="https://doisinkidney.com/rss.xml#cb39-3" tabindex="-1"/>  <span class="op">|</span> <span class="fu">length</span> xs <span class="op">&lt;</span> <span class="fu">length</span> ys <span class="ot">=</span> <span class="dt">LT</span></span>
<span id="cb39-4"><a href="https://doisinkidney.com/rss.xml#cb39-4" tabindex="-1"/>  <span class="op">|</span> <span class="fu">length</span> xs <span class="op">&gt;</span> <span class="fu">length</span> ys <span class="ot">=</span> <span class="dt">GT</span></span>
<span id="cb39-5"><a href="https://doisinkidney.com/rss.xml#cb39-5" tabindex="-1"/>  <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="fu">compare</span> xs ys</span></code></pre></div>
<p>We can improve the efficiency of the above function somewhat by using
one of my favourite monoids: the monoid instance on <code class="sourceCode haskell"><span class="dt">Ordering</span></code>.</p>
<div class="sourceCode" id="cb40"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb40-1"><a href="https://doisinkidney.com/rss.xml#cb40-1" tabindex="-1"/><span class="ot">grlex ::</span> <span class="dt">Ord</span> a <span class="ot">=&gt;</span> [a] <span class="ot">-&gt;</span> [a] <span class="ot">-&gt;</span> <span class="dt">Ordering</span></span>
<span id="cb40-2"><a href="https://doisinkidney.com/rss.xml#cb40-2" tabindex="-1"/>grlex <span class="ot">=</span> go <span class="dt">EQ</span></span>
<span id="cb40-3"><a href="https://doisinkidney.com/rss.xml#cb40-3" tabindex="-1"/>  <span class="kw">where</span></span>
<span id="cb40-4"><a href="https://doisinkidney.com/rss.xml#cb40-4" tabindex="-1"/>    go <span class="op">!</span>a []     []     <span class="ot">=</span> a</span>
<span id="cb40-5"><a href="https://doisinkidney.com/rss.xml#cb40-5" tabindex="-1"/>    go <span class="op">!</span>a []     (_<span class="op">:</span>_)  <span class="ot">=</span> <span class="dt">LT</span></span>
<span id="cb40-6"><a href="https://doisinkidney.com/rss.xml#cb40-6" tabindex="-1"/>    go <span class="op">!</span>a (_<span class="op">:</span>_)  []     <span class="ot">=</span> <span class="dt">GT</span></span>
<span id="cb40-7"><a href="https://doisinkidney.com/rss.xml#cb40-7" tabindex="-1"/>    go <span class="op">!</span>a (x<span class="op">:</span>xs) (y<span class="op">:</span>ys) <span class="ot">=</span> go (a <span class="op">&lt;&gt;</span> <span class="fu">compare</span> x y) xs ys</span></code></pre></div>
<p>This version performs just one pass through each list, and does the
correct comparison without additionally calculating the length. Itâ€™s
also nonstrict: if one of the lists passed is infinite, this comparison
will still terminate.</p>
<p>Another admissible order we could use is <em>reverse</em> grlex,
which basically amounts to reversing the lists before the comparison.
The trie structure means that weâ€™re basically forced to use <code class="sourceCode haskell">grlex</code>, but I will include an
implementation of <code class="sourceCode haskell">grevlex</code> here
because I think itâ€™s cute.</p>
<details>

Implementations of <code class="sourceCode haskell">grevlex</code>

<div class="sourceCode" id="cb41"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb41-1"><a href="https://doisinkidney.com/rss.xml#cb41-1" tabindex="-1"/><span class="ot">grevlex ::</span> <span class="dt">Ord</span> a <span class="ot">=&gt;</span> [a] <span class="ot">-&gt;</span> [a] <span class="ot">-&gt;</span> <span class="dt">Ordering</span></span>
<span id="cb41-2"><a href="https://doisinkidney.com/rss.xml#cb41-2" tabindex="-1"/>grevlex []     []     <span class="ot">=</span> <span class="dt">EQ</span></span>
<span id="cb41-3"><a href="https://doisinkidney.com/rss.xml#cb41-3" tabindex="-1"/>grevlex (_<span class="op">:</span>_)  []     <span class="ot">=</span> <span class="dt">GT</span></span>
<span id="cb41-4"><a href="https://doisinkidney.com/rss.xml#cb41-4" tabindex="-1"/>grevlex []     (_<span class="op">:</span>_)  <span class="ot">=</span> <span class="dt">LT</span></span>
<span id="cb41-5"><a href="https://doisinkidney.com/rss.xml#cb41-5" tabindex="-1"/>grevlex (x<span class="op">:</span>xs) (y<span class="op">:</span>ys) <span class="ot">=</span> grevlex xs ys <span class="op">&lt;&gt;</span> <span class="fu">compare</span> x y</span>
<span id="cb41-6"><a href="https://doisinkidney.com/rss.xml#cb41-6" tabindex="-1"/></span>
<span id="cb41-7"><a href="https://doisinkidney.com/rss.xml#cb41-7" tabindex="-1"/><span class="co">-- This version is tail-recursive, but it also might unnecessarily compare</span></span>
<span id="cb41-8"><a href="https://doisinkidney.com/rss.xml#cb41-8" tabindex="-1"/><span class="co">-- elements. However, that should be cheaper than building up the list of</span></span>
<span id="cb41-9"><a href="https://doisinkidney.com/rss.xml#cb41-9" tabindex="-1"/><span class="co">-- comparisons.</span></span>
<span id="cb41-10"><a href="https://doisinkidney.com/rss.xml#cb41-10" tabindex="-1"/><span class="ot">grevlex ::</span> <span class="dt">Ord</span> a <span class="ot">=&gt;</span> [a] <span class="ot">-&gt;</span> [a] <span class="ot">-&gt;</span> <span class="dt">Ordering</span></span>
<span id="cb41-11"><a href="https://doisinkidney.com/rss.xml#cb41-11" tabindex="-1"/>grevlex <span class="ot">=</span> go <span class="dt">EQ</span></span>
<span id="cb41-12"><a href="https://doisinkidney.com/rss.xml#cb41-12" tabindex="-1"/>  <span class="kw">where</span></span>
<span id="cb41-13"><a href="https://doisinkidney.com/rss.xml#cb41-13" tabindex="-1"/>    go <span class="op">!</span>a []     []     <span class="ot">=</span> a</span>
<span id="cb41-14"><a href="https://doisinkidney.com/rss.xml#cb41-14" tabindex="-1"/>    go <span class="op">!</span>a (_<span class="op">:</span>_)  []     <span class="ot">=</span> <span class="dt">GT</span></span>
<span id="cb41-15"><a href="https://doisinkidney.com/rss.xml#cb41-15" tabindex="-1"/>    go <span class="op">!</span>a []     (_<span class="op">:</span>_)  <span class="ot">=</span> <span class="dt">LT</span></span>
<span id="cb41-16"><a href="https://doisinkidney.com/rss.xml#cb41-16" tabindex="-1"/>    go <span class="op">!</span>a (x<span class="op">:</span>xs) (y<span class="op">:</span>ys) <span class="ot">=</span> go (<span class="fu">compare</span> x y <span class="op">&lt;&gt;</span> a) xs ys</span></code></pre></div>
</details>
<h2 id="enumerating-monomials">Enumerating Monomials</h2>
<p>The problem with all the admissible monomial orderings is that they
need to see the entire monomial before they can decide whether itâ€™s
ordered before or after another. This is at odds with the trie, which
tends to prefer computations that can be described in terms of
prefix/suffix decompositions.</p>
<p>To demonstrate the problem, letâ€™s take a look at an algorithm that
enumerates the monomials of a polynomial in lexicographic order:</p>
<div class="sourceCode" id="cb42"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb42-1"><a href="https://doisinkidney.com/rss.xml#cb42-1" tabindex="-1"/><span class="ot">monos ::</span> (<span class="dt">Num</span> c, <span class="dt">Eq</span> c) <span class="ot">=&gt;</span> <span class="dt">Poly</span> v c <span class="ot">-&gt;</span> [([v],c)]</span>
<span id="cb42-2"><a href="https://doisinkidney.com/rss.xml#cb42-2" tabindex="-1"/>monos p <span class="ot">=</span> search [] p []</span>
<span id="cb42-3"><a href="https://doisinkidney.com/rss.xml#cb42-3" tabindex="-1"/>  <span class="kw">where</span></span>
<span id="cb42-4"><a href="https://doisinkidney.com/rss.xml#cb42-4" tabindex="-1"/>    cons vs <span class="dv">0</span> ms <span class="ot">=</span> ms</span>
<span id="cb42-5"><a href="https://doisinkidney.com/rss.xml#cb42-5" tabindex="-1"/>    cons vs c ms <span class="ot">=</span> (<span class="fu">reverse</span> vs,c) <span class="op">:</span> ms</span>
<span id="cb42-6"><a href="https://doisinkidney.com/rss.xml#cb42-6" tabindex="-1"/></span>
<span id="cb42-7"><a href="https://doisinkidney.com/rss.xml#cb42-7" tabindex="-1"/>    search sv (n <span class="op">:&lt;+</span> ns) ms <span class="ot">=</span> cons sv n (Map.foldrWithKey (search <span class="op">.</span> (<span class="op">:</span>sv)) ms ns)</span>
<span id="cb42-8"><a href="https://doisinkidney.com/rss.xml#cb42-8" tabindex="-1"/></span>
<span id="cb42-9"><a href="https://doisinkidney.com/rss.xml#cb42-9" tabindex="-1"/><span class="op">&gt;&gt;&gt;</span> monos ((<span class="dv">2</span> <span class="op">+</span> <span class="dv">3</span><span class="op">*</span>x <span class="op">-</span> <span class="dv">5</span><span class="op">*</span>y) <span class="op">^</span> <span class="dv">2</span>)</span>
<span id="cb42-10"><a href="https://doisinkidney.com/rss.xml#cb42-10" tabindex="-1"/>[([],<span class="dv">4</span>),([<span class="dt">X</span>],<span class="dv">12</span>),([<span class="dt">X</span>,<span class="dt">X</span>],<span class="dv">9</span>),([<span class="dt">X</span>,<span class="dt">Y</span>],<span class="op">-</span><span class="dv">15</span>),([<span class="dt">Y</span>],<span class="op">-</span><span class="dv">20</span>),([<span class="dt">Y</span>,<span class="dt">X</span>],<span class="op">-</span><span class="dv">15</span>),([<span class="dt">Y</span>,<span class="dt">Y</span>],<span class="dv">25</span>)]</span></code></pre></div>
<p>Notice that the function <code class="sourceCode haskell">search</code> emits the monomial <code class="sourceCode haskell">(<span class="fu">reverse</span> sv, n)</code>
straight away (if <code class="sourceCode haskell">n <span class="op">/=</span> <span class="dv">0</span></code>),
when it encounters it: for a proper admissible monomial ordering, it
would instead want to first emit monomials of higher degree; that is,
those monomials in the map <code class="sourceCode haskell">ns</code>.</p>
<p>However, we canâ€™t just flip the order of consing in <code class="sourceCode haskell">search</code>: notice that even if we
reversed the output, we still wouldnâ€™t get an admissible monomial
ordering (the singleton list <code class="sourceCode haskell">[<span class="dt">Y</span>]</code> should be
grouped with the other singleton lists). The problem is that <code class="sourceCode haskell">monos</code> is performing a
<em>depth</em>-first search. What we need is <em>breadth</em>-first.</p>
<p>I happen to be a little <a href="https://doisinkidney.com/series/Breadth-First%20Traversals.html">obsessed</a> with
breadth-first search, so I probably spent too much time on this
particular implementation, but I do always get excited when I see a
breadth-first traversal pop up in the wild.</p>
<p>For this case, I started with the <code class="sourceCode haskell">levels</code> function.</p>
<div class="sourceCode" id="cb43"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb43-1"><a href="https://doisinkidney.com/rss.xml#cb43-1" tabindex="-1"/><span class="ot">levels ::</span> (<span class="dt">Num</span> c, <span class="dt">Eq</span> c) <span class="ot">=&gt;</span> <span class="dt">Poly</span> v c <span class="ot">-&gt;</span> [[([v],c)]]</span>
<span id="cb43-2"><a href="https://doisinkidney.com/rss.xml#cb43-2" tabindex="-1"/>levels p <span class="ot">=</span> search [] p []</span>
<span id="cb43-3"><a href="https://doisinkidney.com/rss.xml#cb43-3" tabindex="-1"/>  <span class="kw">where</span></span>
<span id="cb43-4"><a href="https://doisinkidney.com/rss.xml#cb43-4" tabindex="-1"/>    cons _  <span class="dv">0</span> ms <span class="ot">=</span> ms</span>
<span id="cb43-5"><a href="https://doisinkidney.com/rss.xml#cb43-5" tabindex="-1"/>    cons vs c ms <span class="ot">=</span> (<span class="fu">reverse</span> vs,c) <span class="op">:</span> ms</span>
<span id="cb43-6"><a href="https://doisinkidney.com/rss.xml#cb43-6" tabindex="-1"/></span>
<span id="cb43-7"><a href="https://doisinkidney.com/rss.xml#cb43-7" tabindex="-1"/>    search sv (n <span class="op">:&lt;+</span> ns) []     <span class="ot">=</span> cons sv n [] <span class="op">:</span> Map.foldrWithKey (search <span class="op">.</span> (<span class="op">:</span>sv)) [] ns</span>
<span id="cb43-8"><a href="https://doisinkidney.com/rss.xml#cb43-8" tabindex="-1"/>    search sv (n <span class="op">:&lt;+</span> ns) (q<span class="op">:</span>qs) <span class="ot">=</span> cons sv n  q <span class="op">:</span> Map.foldrWithKey (search <span class="op">.</span> (<span class="op">:</span>sv)) qs ns</span>
<span id="cb43-9"><a href="https://doisinkidney.com/rss.xml#cb43-9" tabindex="-1"/></span>
<span id="cb43-10"><a href="https://doisinkidney.com/rss.xml#cb43-10" tabindex="-1"/><span class="op">&gt;&gt;&gt;</span> levels ((<span class="dv">2</span> <span class="op">+</span> <span class="dv">3</span><span class="op">*</span>x <span class="op">-</span> <span class="dv">5</span><span class="op">*</span>y) <span class="op">^</span> <span class="dv">2</span>)</span>
<span id="cb43-11"><a href="https://doisinkidney.com/rss.xml#cb43-11" tabindex="-1"/>[[([],<span class="dv">4</span>)],[([<span class="dt">X</span>],<span class="dv">12</span>),([<span class="dt">Y</span>],<span class="op">-</span><span class="dv">20</span>)],[([<span class="dt">X</span>,<span class="dt">X</span>],<span class="dv">9</span>),([<span class="dt">X</span>,<span class="dt">Y</span>],<span class="op">-</span><span class="dv">15</span>),([<span class="dt">Y</span>,<span class="dt">X</span>],<span class="op">-</span><span class="dv">15</span>),([<span class="dt">Y</span>,<span class="dt">Y</span>],<span class="dv">25</span>)]]</span></code></pre></div>
<p>I have written about levels <a href="https://doisinkidney.com/posts/2019-05-28-linear-phases.html">before</a> <span class="citation">(see also
<a href="https://doisinkidney.com/rss.xml#ref-gibbons_breadthfirst_2015">Gibbons
2015</a>; <a href="https://doisinkidney.com/rss.xml#ref-jones_lineartime_1993">Jones and Gibbons 1993</a>)</span>.</p>
<p>I think itâ€™s a good fit here because it lets us build the prefix
string for each monomial in a natural way (that prefix string is the
<code class="sourceCode haskell">sv</code> thatâ€™s passed to <code class="sourceCode haskell">search</code>).</p>
<p>However, one flaw of this function is that it produces a list of
lists: one inner list for each degree of polynomial. The output that I
actually want, however, is the concatenation of the whole thing.</p>
<p>In reality, this isnâ€™t actually a flaw: we can just call <code class="sourceCode haskell"><span class="fu">concat</span></code> and
move on. I had a feeling, though, that there was probably some annoying
circular program that would let us avoid the second traversal to
concatenate the inner lists. Inspired by Geraint Jonesâ€™ cyclic
breadth-first traversal <span class="citation">(<a href="https://doisinkidney.com/rss.xml#ref-jones_lineartime_1993">1993</a>)</span>, I finally arrived at the
following solution:</p>
<div class="sourceCode" id="cb44"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb44-1"><a href="https://doisinkidney.com/rss.xml#cb44-1" tabindex="-1"/><span class="kw">data</span> <span class="dt">Knots</span> a</span>
<span id="cb44-2"><a href="https://doisinkidney.com/rss.xml#cb44-2" tabindex="-1"/>  <span class="ot">=</span> <span class="dt">Knot</span></span>
<span id="cb44-3"><a href="https://doisinkidney.com/rss.xml#cb44-3" tabindex="-1"/>  {<span class="ot"> tied ::</span> <span class="op">!</span><span class="dt">Bool</span></span>
<span id="cb44-4"><a href="https://doisinkidney.com/rss.xml#cb44-4" tabindex="-1"/>  ,<span class="ot"> yank ::</span> [a]</span>
<span id="cb44-5"><a href="https://doisinkidney.com/rss.xml#cb44-5" tabindex="-1"/>  ,<span class="ot"> ends ::</span> <span class="dt">Knots</span> a }</span>
<span id="cb44-6"><a href="https://doisinkidney.com/rss.xml#cb44-6" tabindex="-1"/></span>
<span id="cb44-7"><a href="https://doisinkidney.com/rss.xml#cb44-7" tabindex="-1"/><span class="ot">tighten ::</span> <span class="dt">Knots</span> a <span class="ot">-&gt;</span> <span class="dt">Knots</span> a</span>
<span id="cb44-8"><a href="https://doisinkidney.com/rss.xml#cb44-8" tabindex="-1"/>tighten <span class="op">~</span>(<span class="dt">Knot</span> t y e) <span class="ot">=</span> <span class="dt">Knot</span> <span class="dt">False</span> (<span class="kw">if</span> t <span class="kw">then</span> y <span class="kw">else</span> []) (tighten e)</span>
<span id="cb44-9"><a href="https://doisinkidney.com/rss.xml#cb44-9" tabindex="-1"/></span>
<span id="cb44-10"><a href="https://doisinkidney.com/rss.xml#cb44-10" tabindex="-1"/><span class="ot">monos ::</span> (<span class="dt">Eq</span> c, <span class="dt">Num</span> c) <span class="ot">=&gt;</span> <span class="dt">Poly</span> v c <span class="ot">-&gt;</span> [([v],c)]</span>
<span id="cb44-11"><a href="https://doisinkidney.com/rss.xml#cb44-11" tabindex="-1"/>monos p <span class="ot">=</span> y</span>
<span id="cb44-12"><a href="https://doisinkidney.com/rss.xml#cb44-12" tabindex="-1"/>  <span class="kw">where</span></span>
<span id="cb44-13"><a href="https://doisinkidney.com/rss.xml#cb44-13" tabindex="-1"/>    <span class="dt">Knot</span> _ y e <span class="ot">=</span> tie [] p (tighten e)</span>
<span id="cb44-14"><a href="https://doisinkidney.com/rss.xml#cb44-14" tabindex="-1"/>    cons sv <span class="dv">0</span> ms <span class="ot">=</span> ms</span>
<span id="cb44-15"><a href="https://doisinkidney.com/rss.xml#cb44-15" tabindex="-1"/>    cons sv c ms <span class="ot">=</span> (<span class="fu">reverse</span> sv, c) <span class="op">:</span> ms</span>
<span id="cb44-16"><a href="https://doisinkidney.com/rss.xml#cb44-16" tabindex="-1"/>    tie sv (n <span class="op">:&lt;+</span> m) (<span class="dt">Knot</span> _ ms ps) <span class="ot">=</span> <span class="dt">Knot</span> <span class="dt">True</span> (cons sv n ms) (Map.foldrWithKey (tie <span class="op">.</span> (<span class="op">:</span>sv)) ps m)</span>
<span id="cb44-17"><a href="https://doisinkidney.com/rss.xml#cb44-17" tabindex="-1"/></span>
<span id="cb44-18"><a href="https://doisinkidney.com/rss.xml#cb44-18" tabindex="-1"/><span class="op">&gt;&gt;&gt;</span> monos ((<span class="dv">2</span> <span class="op">+</span> <span class="dv">3</span> <span class="op">*</span> x <span class="op">-</span> <span class="dv">5</span> <span class="op">*</span> y) <span class="op">^</span> <span class="dv">2</span>)</span>
<span id="cb44-19"><a href="https://doisinkidney.com/rss.xml#cb44-19" tabindex="-1"/>[([],<span class="dv">4</span>),([<span class="dt">X</span>],<span class="dv">12</span>),([<span class="dt">Y</span>],<span class="op">-</span><span class="dv">20</span>),([<span class="dt">X</span>,<span class="dt">X</span>],<span class="dv">9</span>),([<span class="dt">X</span>,<span class="dt">Y</span>],<span class="op">-</span><span class="dv">15</span>),([<span class="dt">Y</span>,<span class="dt">X</span>],<span class="op">-</span><span class="dv">15</span>),([<span class="dt">Y</span>,<span class="dt">Y</span>],<span class="dv">25</span>)]</span></code></pre></div>
<p>While this does order the output according to grlex, itâ€™s ordered
from smallest to largest, which is the <em>reverse</em> of what we want.
And yes, while we could just reverse the output, I didnâ€™t write the
circular abomination above to throw away the single-pass traversal at
such a small hurdle. Any (list-based) algorithm written in a fold-like
fashion can usually be reversed by swapping out right-folds for
left.</p>
<div class="sourceCode" id="cb45"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb45-1"><a href="https://doisinkidney.com/rss.xml#cb45-1" tabindex="-1"/><span class="ot">pull ::</span> <span class="dt">Knots</span> a <span class="ot">-&gt;</span> [a]</span>
<span id="cb45-2"><a href="https://doisinkidney.com/rss.xml#cb45-2" tabindex="-1"/>pull (<span class="dt">Knot</span> <span class="dt">True</span> _ e) <span class="ot">=</span> pull e</span>
<span id="cb45-3"><a href="https://doisinkidney.com/rss.xml#cb45-3" tabindex="-1"/>pull (<span class="dt">Knot</span> <span class="dt">False</span> y _) <span class="ot">=</span> y</span>
<span id="cb45-4"><a href="https://doisinkidney.com/rss.xml#cb45-4" tabindex="-1"/></span>
<span id="cb45-5"><a href="https://doisinkidney.com/rss.xml#cb45-5" tabindex="-1"/><span class="ot">monosDesc ::</span> (<span class="dt">Eq</span> c, <span class="dt">Num</span> c) <span class="ot">=&gt;</span> <span class="dt">Poly</span> v c <span class="ot">-&gt;</span> [([v],c)]</span>
<span id="cb45-6"><a href="https://doisinkidney.com/rss.xml#cb45-6" tabindex="-1"/>monosDesc p <span class="ot">=</span> pull r</span>
<span id="cb45-7"><a href="https://doisinkidney.com/rss.xml#cb45-7" tabindex="-1"/>  <span class="kw">where</span></span>
<span id="cb45-8"><a href="https://doisinkidney.com/rss.xml#cb45-8" tabindex="-1"/>    r <span class="ot">=</span> tie [] p (<span class="dt">Knot</span> <span class="dt">False</span> [] (tighten r))</span>
<span id="cb45-9"><a href="https://doisinkidney.com/rss.xml#cb45-9" tabindex="-1"/>    cons sv <span class="dv">0</span> ms <span class="ot">=</span> ms</span>
<span id="cb45-10"><a href="https://doisinkidney.com/rss.xml#cb45-10" tabindex="-1"/>    cons sv c ms <span class="ot">=</span> (<span class="fu">reverse</span> sv, c) <span class="op">:</span> ms</span>
<span id="cb45-11"><a href="https://doisinkidney.com/rss.xml#cb45-11" tabindex="-1"/>    tie sv (n <span class="op">:&lt;+</span> m) (<span class="dt">Knot</span> _ ms ps) <span class="ot">=</span> <span class="dt">Knot</span> <span class="dt">True</span> (cons sv n ms) (Map.foldlWithKey (\a v p <span class="ot">-&gt;</span> tie (v<span class="op">:</span>sv) p a) ps m)</span></code></pre></div>
<h2 id="efficiently-popping-the-leading-monomial">Efficiently Popping
the Leading Monomial</h2>
<p>Unfortunately, as fun as <code class="sourceCode haskell">monosDesc</code> is, it doesnâ€™t really do
what we need it to for most of the GrÃ¶bner basis algorithms. While it is
pretty efficient if we want <em>all</em> of the monomials of a
polynomial, usually we just want the <em>first</em> one. And sadly,
while <code class="sourceCode haskell">monosDesc</code> is linear
overall, itâ€™s not lazy in the right way, meaning that we have to pay
that full linear cost even if we only inspect the first element of the
list it produces.</p>
<p>The solution here will require us to use a new data structure in
place of the <code class="sourceCode haskell"><span class="dt">Map</span></code> that we
have currently. To avoid traversing the whole tree to find the largest
monomial, we need to cache the depth of each subterm so that we can just
descend into the subterm which contains the monomial of the highest
degree. But we donâ€™t want to just swap out our <code class="sourceCode haskell"><span class="dt">Map</span> v (<span class="dt">Poly</span> v c)</code>
for a <code class="sourceCode haskell"><span class="dt">Map</span> v (<span class="dt">Word</span>, <span class="dt">Poly</span> v c)</code>:
that solution would require us to walk over every entry in the map to
find the largest <code class="sourceCode haskell"><span class="dt">Word</span></code>. While it
would be an improvement in practical terms, it would still incur an
<math display="inline">&lt;semantics&gt;<mrow><mi>ğ�’ª</mi><mo form="prefix" stretchy="false">(</mo><mtext mathvariant="normal">width</mtext><mo>Ã—</mo><mtext mathvariant="normal">depth</mtext><mo form="postfix" stretchy="false">)</mo></mrow>&lt;annotation encoding="application/x-tex"&gt;\mathcal{O}(\text{width} \times \text{depth})&lt;/annotation&gt;&lt;/semantics&gt;</math>
cost to find the leading monomial.</p>
<p>Instead, we need the map itself to be able to efficiently provide the
entry with the largest degree. We need our map to simultaneously act as
a <em>priority queue</em>.</p>
<p>Luckily, the combination of these two structures has been researched
before: <span class="citation">Hinze (<a href="https://doisinkidney.com/rss.xml#ref-hinze_simple_2001">2001</a>)</span>
wrote about â€œpriority search treesâ€�, a data structure that allows for
<math display="inline">&lt;semantics&gt;<mrow><mi>ğ�’ª</mi><mo form="prefix" stretchy="false">(</mo><mrow><mi>log</mi><mo>⁡</mo></mrow><mi>n</mi><mo form="postfix" stretchy="false">)</mo></mrow>&lt;annotation encoding="application/x-tex"&gt;\mathcal{O}(\log n)&lt;/annotation&gt;&lt;/semantics&gt;</math>
lookup and insertion based on some ordered key, and separately allows
for a
<math display="inline">&lt;semantics&gt;<mrow><mi>ğ�’ª</mi><mo form="prefix" stretchy="false">(</mo><mrow><mi>log</mi><mo>⁡</mo></mrow><mi>n</mi><mo form="postfix" stretchy="false">)</mo></mrow>&lt;annotation encoding="application/x-tex"&gt;\mathcal{O}(\log n)&lt;/annotation&gt;&lt;/semantics&gt;</math>
<code class="sourceCode haskell">popMin</code> operation, based on some
separate priority. The <a href="https://hackage.haskell.org/package/psqueues"><code class="sourceCode haskell">psqueues</code> package</a> provides a few
implementations of this technique. The API isnâ€™t quite as extensive as,
say, <a href="https://hackage.haskell.org/package/containers"><code class="sourceCode haskell">containers</code></a>, so some functions will
be slightly less efficient (we donâ€™t get a nice general <code class="sourceCode haskell">merge</code> function, for example), but we
can basically drop in the <code class="sourceCode haskell"><span class="dt">OrdPSQ</span></code> as a
replacement for <code class="sourceCode haskell"><span class="dt">Map</span></code>.</p>
<div class="sourceCode" id="cb46"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb46-1"><a href="https://doisinkidney.com/rss.xml#cb46-1" tabindex="-1"/><span class="kw">type</span> <span class="dt">SubTerms</span> v c <span class="ot">=</span> <span class="dt">OrdPSQ</span> (<span class="dt">Down</span> v) (<span class="dt">Down</span> <span class="dt">Word</span>) (<span class="dt">Poly</span> v c)</span>
<span id="cb46-2"><a href="https://doisinkidney.com/rss.xml#cb46-2" tabindex="-1"/><span class="kw">data</span> <span class="dt">Poly</span> v c <span class="ot">=</span> c <span class="op">:&lt;+</span> <span class="dt">SubTerms</span> v c</span></code></pre></div>
<p>Iâ€™m using the <a href="https://hackage.haskell.org/package/base-4.22.0.0/docs/Data-Ord.html#t:Down"><code class="sourceCode haskell"><span class="dt">Down</span></code>
wrapper</a> here because I want a <em>max</em> heap, rather than a
min-heap. Iâ€™m using that wrapper on both the keys and priorities because
<code class="sourceCode haskell"><span class="dt">OrdPSQ</span></code>
breaks priority ties according to the keys, and I also want greater keys
returned first, to follow the <code class="sourceCode haskell">grlex</code> ordering.</p>
<p>The priority here is the <em>depth</em> of the tree. It tells us the
length of the longest monomial contained:</p>
<div class="sourceCode" id="cb47"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb47-1"><a href="https://doisinkidney.com/rss.xml#cb47-1" tabindex="-1"/><span class="ot">depth ::</span> <span class="dt">Poly</span> v c <span class="ot">-&gt;</span> <span class="dt">Word</span></span>
<span id="cb47-2"><a href="https://doisinkidney.com/rss.xml#cb47-2" tabindex="-1"/>depth (_ <span class="op">:&lt;+</span> ns) <span class="ot">=</span> <span class="fu">maybe</span> <span class="dv">0</span> (\(_,<span class="dt">Down</span> p,_) <span class="ot">-&gt;</span> <span class="fu">succ</span> p) (Map.findMin ns)</span></code></pre></div>
<p>This operation is
<math display="inline">&lt;semantics&gt;<mrow><mi>ğ�’ª</mi><mo form="prefix" stretchy="false">(</mo><mn>1</mn><mo form="postfix" stretchy="false">)</mo></mrow>&lt;annotation encoding="application/x-tex"&gt;\mathcal{O}(1)&lt;/annotation&gt;&lt;/semantics&gt;</math>,
since finding the minimum entry in <code class="sourceCode haskell"><span class="dt">OrdPSQ</span></code> is
<math display="inline">&lt;semantics&gt;<mrow><mi>ğ�’ª</mi><mo form="prefix" stretchy="false">(</mo><mn>1</mn><mo form="postfix" stretchy="false">)</mo></mrow>&lt;annotation encoding="application/x-tex"&gt;\mathcal{O}(1)&lt;/annotation&gt;&lt;/semantics&gt;</math>.</p>
<p>Iâ€™ll also use the following isomorphism, for the lensy things:</p>
<div class="sourceCode" id="cb48"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb48-1"><a href="https://doisinkidney.com/rss.xml#cb48-1" tabindex="-1"/><span class="ot">entry ::</span> (<span class="dt">Num</span> c, <span class="dt">Eq</span> c) <span class="ot">=&gt;</span> <span class="dt">Iso'</span> (<span class="dt">Maybe</span> (<span class="dt">Down</span> <span class="dt">Word</span>, <span class="dt">Poly</span> v c)) (<span class="dt">Poly</span> v c)</span>
<span id="cb48-2"><a href="https://doisinkidney.com/rss.xml#cb48-2" tabindex="-1"/>entry <span class="ot">=</span> iso (<span class="fu">maybe</span> (<span class="dv">0</span> <span class="op">:&lt;+</span> Map.empty) <span class="fu">snd</span>) (\p <span class="ot">-&gt;</span> <span class="kw">if</span> isZero p <span class="kw">then</span> <span class="dt">Nothing</span> <span class="kw">else</span> <span class="dt">Just</span> (<span class="dt">Down</span> (depth p), p))</span></code></pre></div>
<p>This lets us chain together lenses that index into an <code class="sourceCode haskell"><span class="dt">OrdPSQ</span></code>.</p>
<div class="sourceCode" id="cb49"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb49-1"><a href="https://doisinkidney.com/rss.xml#cb49-1" tabindex="-1"/><span class="ot">factored ::</span> (<span class="dt">Ord</span> v, <span class="dt">Num</span> c, <span class="dt">Eq</span> c) <span class="ot">=&gt;</span> [v] <span class="ot">-&gt;</span> <span class="dt">Lens'</span> (<span class="dt">Poly</span> v c) (<span class="dt">Poly</span> v c)</span>
<span id="cb49-2"><a href="https://doisinkidney.com/rss.xml#cb49-2" tabindex="-1"/>factored <span class="ot">=</span> <span class="fu">foldr</span> (\v ls <span class="ot">-&gt;</span> vars <span class="op">.</span> at (<span class="dt">Down</span> v) <span class="op">.</span> entry <span class="op">.</span> ls) <span class="fu">id</span></span></code></pre></div>
<p>Finally, we can implement a function that pops the leading monomial
from a polynomial, efficiently:</p>
<div class="sourceCode" id="cb50"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb50-1"><a href="https://doisinkidney.com/rss.xml#cb50-1" tabindex="-1"/><span class="ot">leading ::</span> (<span class="dt">Num</span> c, <span class="dt">Eq</span> c, <span class="dt">Ord</span> v) <span class="ot">=&gt;</span> <span class="dt">Poly</span> v c <span class="ot">-&gt;</span> <span class="dt">Maybe</span> (([v],c),<span class="dt">Poly</span> v c)</span>
<span id="cb50-2"><a href="https://doisinkidney.com/rss.xml#cb50-2" tabindex="-1"/>leading p <span class="op">|</span> isZero p <span class="ot">=</span> <span class="dt">Nothing</span></span>
<span id="cb50-3"><a href="https://doisinkidney.com/rss.xml#cb50-3" tabindex="-1"/>leading (n <span class="op">:&lt;+</span> ns) <span class="ot">=</span> <span class="dt">Just</span> (retrie (Map.alterMin step ns))</span>
<span id="cb50-4"><a href="https://doisinkidney.com/rss.xml#cb50-4" tabindex="-1"/>  <span class="kw">where</span></span>
<span id="cb50-5"><a href="https://doisinkidney.com/rss.xml#cb50-5" tabindex="-1"/>    retrie ((r,n'),ns') <span class="ot">=</span> (r, n' <span class="op">:&lt;+</span> ns')</span>
<span id="cb50-6"><a href="https://doisinkidney.com/rss.xml#cb50-6" tabindex="-1"/></span>
<span id="cb50-7"><a href="https://doisinkidney.com/rss.xml#cb50-7" tabindex="-1"/>    step <span class="dt">Nothing</span> <span class="ot">=</span> ((([],n),<span class="dv">0</span>),<span class="dt">Nothing</span>)</span>
<span id="cb50-8"><a href="https://doisinkidney.com/rss.xml#cb50-8" tabindex="-1"/>    step (<span class="dt">Just</span> (<span class="dt">Down</span> v, _, p)) <span class="ot">=</span> (((v<span class="op">:</span>vs,c),n), subTrie)</span>
<span id="cb50-9"><a href="https://doisinkidney.com/rss.xml#cb50-9" tabindex="-1"/>      <span class="kw">where</span></span>
<span id="cb50-10"><a href="https://doisinkidney.com/rss.xml#cb50-10" tabindex="-1"/>        <span class="dt">Just</span> ((vs,c),p') <span class="ot">=</span> leading p</span>
<span id="cb50-11"><a href="https://doisinkidney.com/rss.xml#cb50-11" tabindex="-1"/>        subTrie <span class="op">|</span> isZero p' <span class="ot">=</span> <span class="dt">Nothing</span></span>
<span id="cb50-12"><a href="https://doisinkidney.com/rss.xml#cb50-12" tabindex="-1"/>                <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="dt">Just</span> (<span class="dt">Down</span> v, <span class="dt">Down</span> (depth p'), p')</span></code></pre></div>
<p>And it matches the earlier enumeration that we built:</p>
<div class="sourceCode" id="cb51"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb51-1"><a href="https://doisinkidney.com/rss.xml#cb51-1" tabindex="-1"/><span class="ot">prop_leadingMonos ::</span> <span class="dt">Poly</span> <span class="dt">Var</span> <span class="dt">Word</span> <span class="ot">-&gt;</span> <span class="dt">Property</span></span>
<span id="cb51-2"><a href="https://doisinkidney.com/rss.xml#cb51-2" tabindex="-1"/>prop_leadingMonos p <span class="ot">=</span> monosDesc p <span class="op">===</span> unfoldr leading p</span></code></pre></div>
<h2 id="next-steps">Next Steps</h2>
<p>I think this is an interesting data structure, and representation of
polynomials. However, I am not very familiar with the computer algebra
literature, so I canâ€™t yet tell how this kind of representation relates
to the other systems out there. Furthermore, most of the algorithms I
have read seem to work implicitly with â€œleading monomialsâ€� etc., leading
to the following kind of implementation of division:</p>
<div class="sourceCode" id="cb52"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb52-1"><a href="https://doisinkidney.com/rss.xml#cb52-1" tabindex="-1"/><span class="ot">divModPrefM ::</span> (<span class="dt">Fractional</span> c, <span class="dt">Eq</span> c, <span class="dt">Ord</span> v) <span class="ot">=&gt;</span> <span class="dt">Poly</span> v c <span class="ot">-&gt;</span> ([v],c) <span class="ot">-&gt;</span> (<span class="dt">Poly</span> v c, <span class="dt">Poly</span> v c)</span>
<span id="cb52-2"><a href="https://doisinkidney.com/rss.xml#cb52-2" tabindex="-1"/>divModPrefM p (vs, i) <span class="ot">=</span> factored vs ((, <span class="dv">0</span>) <span class="op">.</span> <span class="fu">fmap</span> (<span class="op">/</span>i)) p</span>
<span id="cb52-3"><a href="https://doisinkidney.com/rss.xml#cb52-3" tabindex="-1"/></span>
<span id="cb52-4"><a href="https://doisinkidney.com/rss.xml#cb52-4" tabindex="-1"/><span class="ot">divModPref ::</span> (<span class="dt">Fractional</span> c, <span class="dt">Eq</span> c, <span class="dt">Ord</span> v) <span class="ot">=&gt;</span> <span class="dt">Poly</span> v c <span class="ot">-&gt;</span> <span class="dt">Poly</span> v c <span class="ot">-&gt;</span> (<span class="dt">Poly</span> v c, <span class="dt">Poly</span> v c)</span>
<span id="cb52-5"><a href="https://doisinkidney.com/rss.xml#cb52-5" tabindex="-1"/>divModPref num divisor <span class="ot">=</span> <span class="kw">case</span> leading divisor <span class="kw">of</span></span>
<span id="cb52-6"><a href="https://doisinkidney.com/rss.xml#cb52-6" tabindex="-1"/>  <span class="dt">Nothing</span> <span class="ot">-&gt;</span> <span class="fu">error</span> <span class="st">"Divide by zero"</span></span>
<span id="cb52-7"><a href="https://doisinkidney.com/rss.xml#cb52-7" tabindex="-1"/>  <span class="dt">Just</span> (lt, rest) <span class="ot">-&gt;</span> go <span class="dv">0</span> num</span>
<span id="cb52-8"><a href="https://doisinkidney.com/rss.xml#cb52-8" tabindex="-1"/>    <span class="kw">where</span></span>
<span id="cb52-9"><a href="https://doisinkidney.com/rss.xml#cb52-9" tabindex="-1"/>      go <span class="op">!</span><span class="fu">quot</span> <span class="op">!</span><span class="fu">rem</span> <span class="ot">=</span> <span class="kw">case</span> divModPrefM <span class="fu">rem</span> lt <span class="kw">of</span></span>
<span id="cb52-10"><a href="https://doisinkidney.com/rss.xml#cb52-10" tabindex="-1"/>        (<span class="dv">0</span>, _) <span class="ot">-&gt;</span> (<span class="fu">quot</span>, <span class="fu">rem</span>)</span>
<span id="cb52-11"><a href="https://doisinkidney.com/rss.xml#cb52-11" tabindex="-1"/>        (q, rem') <span class="ot">-&gt;</span> go (<span class="fu">quot</span> <span class="op">+</span> q) (rem' <span class="op">-</span> rest <span class="op">*</span> q)</span></code></pre></div>
<p>I feel that this doesnâ€™t make use of the benefits of the trie-based
representation. I have implemented Buchbergerâ€™s algorithm <span class="citation">(with most of the
improvements from <a href="https://doisinkidney.com/rss.xml#ref-xiu_noncommutative_2012">Xiu 2012</a>)</span>, but I have yet to really
research in depth what competitively fast systems do these days <span class="citation">(<a href="https://doisinkidney.com/rss.xml#ref-heisinger_f4ncgb_2025">Heisinger and
Hofstadler 2025</a>; <a href="https://doisinkidney.com/rss.xml#ref-cohen_gbnp_2026">Cohen and Knopper 2026</a>; <a href="https://doisinkidney.com/rss.xml#ref-levandovskyy_letterplace_2020">Levandovskyy, SchÃ¶nemann, and Zeid
2020</a>)</span>. Iâ€™m also interested in seeing what kinds of
applications there are for this stuff: I started this project with Weyl
algebras in mind, but after looking into it a little more it seems clear
that a trie is <em>not</em> a good fit for Weyl algebras.</p>
<p>I have looked a little bit at some other Haskell work on polynomials
and similar things; <span class="citation">Zucker (<a href="https://doisinkidney.com/rss.xml#ref-zucker_division_2018">2018</a>)</span>
implemented listed polynomials very similar to the ones I had at the
start of this post, as did <span class="citation">Manzyuk (<a href="https://doisinkidney.com/rss.xml#ref-manzyuk_grobner_2012">2012</a>)</span>
and <span class="citation">Buteau
(<a href="https://doisinkidney.com/rss.xml#ref-buteau_polynomials_2013">2013</a>)</span>. Iâ€™ve seen some bigger Haskell
packages that work with polynomials <span class="citation">(<a href="https://doisinkidney.com/rss.xml#ref-malaquias_implementing_2007">Malaquias
and Lopes 2007</a>; <a href="https://doisinkidney.com/rss.xml#ref-ishii_purely_2018">Ishii 2018</a>; <a href="https://doisinkidney.com/rss.xml#ref-laurent_hspray_2024">Laurent 2024</a>)</span>, though none seem to use a
representation similar to the trie here. I also had a look at calculi
<span class="citation">(<a href="https://doisinkidney.com/rss.xml#ref-barton_calculi_2024">Barton
2024</a>)</span>, but I think that that project mainly works with
commutative rings (although itâ€™s pretty big project, so I wouldnâ€™t be
surprised if there was some module I missed).</p>
<p>I would actually be interested to hear if anyone has any pointers to
work that has a similar approach to polynomials, or on the kinds of
things that people use these noncommutative polynomials for. I find most
of the descriptions of these algorithms difficult to parse (since
theyâ€™re usually written by and for mathematicians rather than computer
scientists, and almost never for functional programmers), so I am sure
Iâ€™m missing some major projects.</p>
<hr/>
<h2 id="gists">Gists</h2>
<p><a href="https://gist.github.com/oisdk/67714b0e02259e972fa5e06071ab7c5e">Listed
Polynomial with arbitrary variables</a></p>
<p><a href="https://gist.github.com/oisdk/a10b27a54a3fef6b489eb9202406387c">Polynomial
Trie</a></p>
<hr/>
<h2 class="unnumbered" id="references">References</h2>
<div class="references csl-bib-body hanging-indent" id="refs">
<div class="csl-entry" id="ref-barton_calculi_2024">
Barton, Dave. 2024. <span>â€œCalculi.â€�</span> <a href="https://github.com/DaveBarton/calculi">https://github.com/DaveBarton/calculi</a>.
</div>
<div class="csl-entry" id="ref-buteau_polynomials_2013">
Buteau, Samuel. 2013. <span>â€œPolynomials - <span>School</span> of
<span>Haskell</span> <span>School</span> of
<span>Haskell</span>.â€�</span> <em>School of Haskell</em>. <a href="https://www.schoolofhaskell.com/user/Sam567/computational-physics/beginner-s-tools/polynomials">https://www.schoolofhaskell.com/user/Sam567/computational-physics/beginner-s-tools/polynomials</a>.
</div>
<div class="csl-entry" id="ref-cohen_gbnp_2026">
Cohen, Arjeh M., and Jan Willem Knopper. 2026.
<span>â€œ<span>GBNP</span>.â€�</span> GAP packages. <a href="https://github.com/gap-packages/gbnp">https://github.com/gap-packages/gbnp</a>.
</div>
<div class="csl-entry" id="ref-gibbons_horners_2011">
Gibbons, Jeremy. 2011. <span>â€œHornerâ€™s <span>Rule</span>.â€�</span>
<em>Patterns in Functional Programming</em>. <a href="https://patternsinfp.wordpress.com/2011/05/05/horners-rule/">https://patternsinfp.wordpress.com/2011/05/05/horners-rule/</a>.
</div>
<div class="csl-entry" id="ref-gibbons_breadthfirst_2015">
â€”â€”â€”. 2015. <span>â€œBreadth-<span>First Traversal</span>.â€�</span>
<em>Patterns in Functional Programming</em>. <a href="https://patternsinfp.wordpress.com/2015/03/05/breadth-first-traversal/">https://patternsinfp.wordpress.com/2015/03/05/breadth-first-traversal/</a>.
</div>
<div class="csl-entry" id="ref-heisinger_f4ncgb_2025">
Heisinger, Maximilian, and Clemens Hofstadler. 2025. <span>â€œF4ncgb:
<span>High Performance GrÃ¶bner Basis Computations</span> in <span>Free
Algebras</span>.â€�</span> arXiv. doi:<a href="https://doi.org/10.48550/arXiv.2505.19304">10.48550/arXiv.2505.19304</a>.
<a href="https://arxiv.org/abs/2505.19304">https://arxiv.org/abs/2505.19304</a>.
</div>
<div class="csl-entry" id="ref-hinze_simple_2001">
Hinze, Ralf. 2001. <span>â€œA simple implementation technique for priority
search queues.â€�</span> <em>SIGPLAN Not.</em> 36 (10) (October): 110â€“121.
doi:<a href="https://doi.org/10.1145/507669.507650">10.1145/507669.507650</a>.
</div>
<div class="csl-entry" id="ref-ishii_purely_2018">
Ishii, Hiromi. 2018. <span>â€œA <span>Purely Functional Computer Algebra
System Embedded</span> in <span>Haskell</span>.â€�</span> In,
11088:288â€“303. doi:<a href="https://doi.org/10.1007/978-3-319-99639-4_20">10.1007/978-3-319-99639-4_20</a>.
<a href="https://arxiv.org/abs/1807.01456">https://arxiv.org/abs/1807.01456</a>.
</div>
<div class="csl-entry" id="ref-jones_lineartime_1993">
Jones, Geraint, and Jeremy Gibbons. 1993. <em>Linear-time breadth-first
tree algorithms: <span>An</span> exercise in the arithmetic of folds and
zips</em>. Dept of Computer Science, University of Auckland. <a href="https://www.cs.ox.ac.uk/people/jeremy.gibbons/publications/linear.ps.gz">https://www.cs.ox.ac.uk/people/jeremy.gibbons/publications/linear.ps.gz</a>.
</div>
<div class="csl-entry" id="ref-laurent_hspray_2024">
Laurent, StÃ©phane. 2024. <span>â€œHspray.â€�</span> <a href="https://github.com/stla/hspray">https://github.com/stla/hspray</a>.
</div>
<div class="csl-entry" id="ref-levandovskyy_letterplace_2020">
Levandovskyy, Viktor, Hans SchÃ¶nemann, and Karim Abou Zeid. 2020.
<span>â€œLetterplace: A subsystem of singular for computations with free
algebras via letterplace embedding.â€�</span> In <em>Proceedings of the
45th <span>International Symposium</span> on <span>Symbolic</span> and
<span>Algebraic Computation</span></em>, 305â€“311. <span>ISSAC</span>
â€™20. New York, NY, USA: Association for Computing Machinery. doi:<a href="https://doi.org/10.1145/3373207.3404056">10.1145/3373207.3404056</a>.
</div>
<div class="csl-entry" id="ref-malaquias_implementing_2007">
Malaquias, JosÃ© Romildo, and Carlos Roberto Lopes. 2007.
<span>â€œImplementing a computer algebra system in
<span>Haskell</span>.â€�</span> <em>Applied Mathematics and
Computation</em> 192 (1) (September): 120â€“134. doi:<a href="https://doi.org/10.1016/j.amc.2007.02.126">10.1016/j.amc.2007.02.126</a>.
</div>
<div class="csl-entry" id="ref-manzyuk_grobner_2012">
Manzyuk, Oleksandr. 2012. <span>â€œGrÃ¶bner bases in <span>Haskell</span>:
<span>Part I</span>.â€�</span> <em>Oleksandr Manzyukâ€™s Blog</em>. <a href="https://web.archive.org/web/20221206080655/https://oleksandrmanzyuk.wordpress.com/2012/10/25/grobner-bases-in-haskell-part-i/">https://web.archive.org/web/20221206080655/https://oleksandrmanzyuk.wordpress.com/2012/10/25/grobner-bases-in-haskell-part-i/</a>.
</div>
<div class="csl-entry" id="ref-mcilroy_power_1999">
McIlroy, M. Douglas. 1999. <span>â€œPower <span>Series</span>, <span>Power
Serious</span>.â€�</span> <em>J. Funct. Program.</em> 9 (3) (May):
325â€“337. doi:<a href="https://doi.org/10.1017/S0956796899003299">10.1017/S0956796899003299</a>.
</div>
<div class="csl-entry" id="ref-sturmfels_what_2005">
Sturmfels, Bernd. 2005. <span>â€œWhat is... A <span>GrÃ¶bner
Basis</span>?â€�</span> <em>Notices of the AMS</em> 52 (10) (November). <a href="https://www.ams.org/journals/notices/200510/what-is.pdf">https://www.ams.org/journals/notices/200510/what-is.pdf</a>.
</div>
<div class="csl-entry" id="ref-xiu_noncommutative_2012">
Xiu, Xingqiang. 2012. <span>â€œNon-commutative <span>GrÃ¶bner Bases</span>
and <span>Applications</span>.â€�</span> PhD thesis, UniversitÃ¤t Passau.
<a href="https://opus4.kobv.de/opus4-uni-passau/frontdoor/index/index/docId/170">https://opus4.kobv.de/opus4-uni-passau/frontdoor/index/index/docId/170</a>.
</div>
<div class="csl-entry" id="ref-zucker_division_2018">
Zucker, Philip. 2018. <span>â€œDivision of polynomials in haskell.â€�</span>
<em>Hey There Buddo!</em> <a href="https://www.philipzucker.com/division-of-polynomials-in-haskell/">https://www.philipzucker.com/division-of-polynomials-in-haskell/</a>.
</div>
</div></div>
    </summary>
    <updated>2026-04-28T00:00:00Z</updated>
    <published>2026-04-28T00:00:00Z</published>
    <author>
      <name>Donnacha Oisín Kidney</name>
    </author>
    <source>
      <id>https://doisinkidney.com</id>
      <link href="https://doisinkidney.com" rel="alternate" type="text/html"/>
      <link href="https://doisinkidney.com/rss.xml" rel="self" type="application/rss+xml"/>
      <subtitle>Mainly writing about programming</subtitle>
      <title>Donnacha Oisín Kidney's Blog</title>
      <updated>2026-04-28T00:00:00Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-11295132.post-5406444218917761776</id>
    <link href="http://blog.sigfpe.com/2026/04/introduction-i-want-to-return-to.html" rel="alternate" type="text/html"/>
    <title>Some type constructors are tensor products</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><br/><b>Introduction</b><p>

</p><p>I want to return to something I've mentioned a <a href="http://blog.sigfpe.com/2006/08/geometric-algebra-for-free_30.html">couple</a> of <a href="https://blog.sigfpe.com/2023/03/constructing-clifford-algebras-using.html">times</a> in the past - the fact that applying certain type constructors performs a tensor product.</p>

<p>First some admin stuff:</p>

<pre>&gt; {-# LANGUAGE DeriveFunctor #-}
&gt; {-# LANGUAGE FlexibleInstances #-}
&gt; {-# LANGUAGE MultiParamTypeClasses #-}
&gt; {-# LANGUAGE UndecidableInstances #-}
&gt; {-# LANGUAGE TypeApplications #-}
&gt; {-# LANGUAGE KindSignatures #-}
&gt; {-# LANGUAGE ScopedTypeVariables #-}
&gt; {-# LANGUAGE AllowAmbiguousTypes #-}

&gt; import Data.Proxy
&gt; import Data.Kind (Type)

&gt; infixr 7 ⊗
</pre>

<p>Suppose you define a type like so:</p>

<pre>&gt; data Complex a = C a a
&gt;     deriving (Eq, Show, Functor)

&gt; instance Num a =&gt; Num (Complex a) where
&gt;     fromInteger n = C (fromInteger n) 0

&gt;     C a b + C c d = C (a + c) (b + d)
&gt;     C a b - C c d = C (a - c) (b - d)

&gt;     C a b * C c d = C (a * c - b * d) (a * d + b * c)

&gt;     negate (C a b) = C (negate a) (negate b)

&gt;     abs    = error "abs doesn't make sense here"
&gt;     signum = error "signum makes no sense here"
</pre>

<p>It seems straightforward. You've defined complex numbers in a way that allows a choice of base type to represent the real numbers. For example you could use <tt>Complex Float</tt> or <tt>Complex Double</tt> as representations of \(\mathbb{C}\).</p>

<p>In actual fact you've done quite a bit more! That code has another reading - it implements a tensor product both in the category of vector spaces, and, less trivially, in the category of algebras. So if <tt>A</tt> is a suitable algebraic structure then, if you allow me to mix code and mathematics notation,</p>

<div class="legacy-equation-display">\[
\mathtt{Complex\ A} = \mathbb{C}\otimes\mathtt{A}
\]</div>

<p>I took this for granted when I mentioned it previously but I thought I'd look into it in a little bit more detail.</p>

<br/><b>Tensor Products</b><p>

</p><p>I want to start from the definition of the tensor product given by its universal property, but to make that slightly less fearsome I'll use an English sketch of it.</p>

<p>Suppose you have a pair of vector spaces \(X\) and \(Y\) over some base field \(k\). A bilinear function \(X\times Y\rightarrow Z\) is a function that is linear in \(X\) and linear in \(Y\). Now suppose we know that at some point in the future we are going to need some bilinear function on \(X\times Y\) but don't yet know what it is. Can we make a structure, \(T\), that contains precisely the information we need so that we can compute any bilinear function we want - with the proviso that we compute these bilinear functions by applying a linear function to \(T\)? We don't want \(T\) to be lacking anything we might need to compute a future bilinear product, but we also don't want it to contain any extraneous data.</p>

<p>For example, imagine working with \(V\), the vector space of 3D vectors. Some examples of bilinear functions we might want are the dot product \(V\cdot V\rightarrow\mathbb{R}\) and the cross product \(V\times V\rightarrow V\). What should \(T\) look like?</p>

<p>We can write the dot product as \((x, y, z)\cdot(x', y', z') = xx'+yy'+zz'\). Note how it's made of products of coordinates from \((x, y, z)\) and coordinates from \((x', y', z')\). Similarly \((x, y, z)\times(x', y', z')=(yz'-zy',\ldots)\). Again, it's a linear combination of products of coordinates, one from each vector. You can prove that any bilinear product will be some linear combination of such products.</p>

<p>By thinking about all possible bilinear products you I hope you can see that \(T\) should be a 9-dimensional vector space and a suitable way to represent a pair of vectors \((x, y, z), (x', y', z')\) for future application of a bilinear function is as \((xx', xy', xz', yx', yy', yz', zx', zy', zz')\). Any bilinear product is a linear combination of these 9 quantities and so is given by some linear operation on \(T\). It is commonplace to arrange the 9-dimensional vector as a \(3\times 3\) matrix in which case the map from the pair is called the outer product. But it doesn't really matter as all 9-dimensional vector spaces over a given field are isomorphic.</p>

<p>In this case I chose to consider bilinear functions on \(V\times V\), but you can reason similarly for any pair of vector spaces \(X\) and \(Y\). When working with finite-dimensional vector spaces, the structure we need will be \(mn\)-dimensional where \(m\) is the dimension of \(X\) and \(n\) is the dimension of \(Y\). The structure is called the tensor product and is written as \(X\otimes Y\). The bilinear map from the original vectors into the tensor product is also called the tensor product and as written as a binary operator \(x\otimes y\). And once you have the tensor product, every bilinear function on the original pair of spaces can be expressed uniquely as a linear function on the tensor product.</p>

<p>So, for example, the dot product can be written as</p>

<div class="legacy-equation-display">\[
x\cdot y = \phi(x\otimes y)
\]</div>

<p>where \((x, y, z)\otimes(x', y', z')=(xx',xy',\ldots zz')\) and so the linear function is \(\phi(x_0, x_1,\ldots,x_8) = x_0+x_4+x_8\).</p>

<p>Similarly</p>

<div class="legacy-equation-display">\[
x\times y = \psi(x\otimes y)
\]</div>

<p>where \(\psi(x_0, x_1, \ldots, x_8)=(x_5 - x_7, x_6 - x_2, x_1 - x_3)\)</p>

<br/><b>Algebras</b><p>

</p><p>It's a confusing use of terminology, but the term "algebra (over \(k\))" is used specifically to mean a vector space \(A\) (over \(k\)) equipped with a bilinear product \(A\times A\rightarrow A\) which is compatible with the vector space structure. And in addition I'm assuming my algebras contain a multiplicative unit element. Other people may call this a "unital algebra". I'll use the word "unital" when I want to stress that there is a unit.</p>

<p>An example is the algebra of complex numbers \(\mathbb{C}\) over \(\mathbb{R}\). It's a 2-dimensional vector space over \(\mathbb{R}\). We can, for example, scale complex numbers by elements of the base field. We also have properties like \((au)v = u(av)\) for \(a\in\mathbb{R}\) and \(u,v\in\mathbb{C}\). We can scale either argument of the complex product by a real and it makes no difference which we choose. See <a href="https://en.wikipedia.org/wiki/Algebra_over_a_field">Wikipedia</a> for all the properties an algebra must satisfy.</p>

<p>Vector spaces come with an addition operation and a zero but we're going to share the work out a little differently because our <tt>Num</tt> instance already has those. So our <tt>VectorSpace</tt> class is just going to have the scale operation:</p>

<pre>&gt; class VectorSpace k v where
&gt;     scale :: k -&gt; v -&gt; v

&gt; instance VectorSpace Double Double where
&gt;     scale = (*)
</pre>

<p>You can think of the definition of <tt>Complex</tt> above as a container for the coordinates in a choice of basis. Because I use <tt>deriving Functor</tt> I can get the <tt>VectorSpace</tt> instance for all similar types for free:</p>

<pre>&gt; instance (Functor c, VectorSpace k a) =&gt; VectorSpace k (c a) where
&gt;     scale k = fmap (scale k)
</pre>

<p>Because fmap composes through nested functors, scale descends recursively through arbitrarily nested structures like <tt>Complex (Complex Double)</tt>.</p>

<p>And now we can concretely implement the bilinear tensor product operation in our choice of basis. It works by descending through the construction of \(x\) until it reaches its individual coordinates and then uses each one to scale \(y\). A special case of this is our 9-dimensional vector construction above: each batch of 3 coordinates is s scaling of one vector by a coordinate from the other.</p>

<pre>&gt; (⊗) :: (Functor c, VectorSpace k a) =&gt; c k -&gt; a -&gt; c a
&gt; x ⊗ y = fmap (`scale` y) x
</pre>

<p>We're literally just recursively building a table of all products of coordinates of <tt>c k</tt> and coordinates of <tt>a</tt>.</p>

<p>Any bilinear function <tt>f :: U -&gt; V -&gt; W</tt> can now be implemented as <tt>f x y = phi (x ⊗ y)</tt> for a unique choice of <tt>phi</tt>.</p>

<br/><b>Algebras too</b><p>

</p><p>But there's more, and this is the point of me writing this article. Algebras also have a tensor product defined on them. The underlying carrier space is the tensor product of algebras considered as vector spaces. The product structure is defined by \((x\otimes y)(x'\otimes y')=(xx')\otimes(yy')\) and linear combinations thereof. But what's neat here is that we don't have to write any more code to implement this, our <tt>Num</tt> instance is already doing the work.</p>

<p>We need to check that our definition of <tt>Complex</tt> satisfies this property. In fact, I want to prove it more generally for any type like <tt>Complex</tt> that has a multiplication that looks like</p>

<pre>    C a b * C c d = C (a * c - b * d) (a * d + b * c)
</pre>

<p>ie. I'll assume we have a type <tt>F</tt> that is an instance of <tt>Num</tt>, with constructor <tt>F</tt>, and whose multiplication is constructed from a linear combination of terms of the form <tt>a * a'</tt>.</p>

<p>Something like:</p>

<pre>    (F ... a ...) * (F ... a' ...) = F ... (... + a * a' + ...) ...
</pre>

<p>Note that I'm claiming</p>

<div class="legacy-equation-display">\[
\mathtt{F\ A} = \mathtt{F\ Double}\otimes\mathtt{A}
\]</div>

<p>so I can suppose that <tt>a</tt> is in <tt>Double</tt> (or whatever we use to represent the reals).</p>

<p>Assuming <tt>*</tt> is such a product:</p>

<pre>   (x ⊗ y) * (x' ⊗ y')
== fmap (`scale` y) x * fmap (`scale` y') x'
   -- definition of tensor
== fmap (`scale` y) (F ... a ...) * fmap (`scale` y') (F ... a' ...)
   -- stating our assumptions about the form of x and x'
== (F ... (scale a y) ...) * (F ... (scale a' y') ...)
   -- this is what derived fmap looks like
== F ... (... + scale a y * scale a' y' + ...) ...
   -- our assumption about the form that multiplication takes
== F ... (... + scale (a * a') (y * y') + ...) ...
   -- multiplication is bilinear all the way down
== fmap (`scale` (y * y')) (F ... (... + a * a' + ...))
   -- same fact about fmap used above
== fmap (`scale` (y * y')) (x * x')
   -- again our assumption about how multiplication is implemented
== (x * x') ⊗ (y * y')
   -- definition of tensor again
</pre>

<p>Anyway, my motivation here is that quite a while back someone (on Mastodon) I think pushed back on my claim that we have a tensor product so I thought I'd give some more detail.</p>

<p>I could say more. The tensor product of algebras has the nice property that you can embed the original algebras in it in a way that the two images commute with each other. In fact, if you can define the tensor product to be the initial algebra with this property. But this is too long already.</p>

<p>Also, I used Haskell above but it carries over straightforwardly to other languages, even <tt>C++</tt>.</p>

<pre>&gt; main :: IO ()
&gt; main = do
&gt;   print "Bye!"
</pre></div>
    </summary>
    <updated>2026-04-27T19:15:36Z</updated>
    <published>2026-04-27T19:15:00Z</published>
    <author>
      <name>sigfpe</name>
      <email>noreply@blogger.com</email>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-11295132</id>
      <category term="mathematics"/>
      <category term="haskell"/>
      <category term="physics"/>
      <category term="monad"/>
      <category term="programming"/>
      <category term="types"/>
      <category term="astronomy"/>
      <category term="quantum"/>
      <category term="comonads"/>
      <category term="self-reference"/>
      <category term="category theory"/>
      <category term="lawvere theories"/>
      <category term="optimisation"/>
      <category term="probability"/>
      <author>
        <name>sigfpe</name>
        <email>noreply@blogger.com</email>
      </author>
      <link href="http://blog.sigfpe.com/" rel="alternate" type="text/html"/>
      <link href="http://sigfpe.blogspot.com/rss.xml" rel="self" type="application/rss+xml"/>
      <title>A Neighborhood of Infinity</title>
      <updated>2026-05-19T09:26:13Z</updated>
    </source>
  </entry>

  <entry xml:lang="en-us">
    <id>Buzzsprout-19077145</id>
    <link href="https://www.buzzsprout.com/1817535/episodes/19077145-81-torsten-grust.mp3" length="50950616" rel="enclosure" type="audio/mpeg"/>
    <title>81: Torsten Grust</title>
    <summary>Mike and Andres sat down with Torsten Grust, who is a professor of DB systems at the University of TÃ¼bingen. Even though Torsten loves SQL, he's used functional programming and Haskell to inform his work on query language design and compilation. We talked about the best way to program databases, how to bridge the gap between regular programming languages and databases, and compiling just about everything to SQL.</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Mike and Andres sat down with Torsten Grust, who is a professor of DB systems at the University of Tübingen. Even though Torsten loves SQL, he's used functional programming and Haskell to inform his work on query language design and compilation. We talked about the best way to program databases, how to bridge the gap between regular programming languages and databases, and compiling just about everything to SQL. </p></div>
    </content>
    <updated>2026-04-27T07:00:00Z</updated>
    <published>2026-04-27T07:00:00Z</published>
    <author>
      <name>Haskell Podcast</name>
    </author>
    <source>
      <id>https://haskell.foundation/podcast/</id>
      <logo>https://storage.buzzsprout.com/tnk1ztokn5vmeiufqmr4kkp37mw2?.jpg</logo>
      <category scheme="http://www.itunes.com/" term="Technology"/>
      <author>
        <name>Haskell Podcast</name>
      </author>
      <link href="https://rss.buzzsprout.com/1817535.rss" rel="self" type="application/rss+xml"/>
      <link href="https://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="https://haskell.foundation/podcast/" rel="alternate" type="text/html"/>
      <rights>Â© 2026 The Haskell Interlude</rights>
      <subtitle>This is the Haskell Interlude, where the five co-hosts (Wouter Swierstra, Andres LÃ¶h, Alejandro Serrano, Niki Vazou, and Joachim Breitner) chat with Haskell guests!</subtitle>
      <title>The Haskell Interlude</title>
      <updated>2026-05-19T12:36:05Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://readerunner.wordpress.com/?p=251</id>
    <link href="https://readerunner.wordpress.com/2024/04/08/penrosekitedart-user-guides/" rel="alternate" type="text/html"/>
    <link href="https://readerunner.wordpress.com/2024/04/08/penrosekitedart-user-guides/#comments" rel="replies" type="text/html"/>
    <link href="https://readerunner.wordpress.com/2024/04/08/penrosekitedart-user-guides/feed/atom/" rel="replies" type="application/atom+xml"/>
    <title xml:lang="en">PenroseKiteDart User Guide</title>
    <summary xml:lang="en">Introduction (Updated April 2026 for PenroseKiteDart version 1.8) PenroseKiteDart is a Haskell package with tools to experiment with finite tilings of Penrose’s Kites and Darts. It uses the Haskell Diagrams package for drawing tilings. As well as providing drawing tools, this package introduces tile graphs (Tgraphs) for describing finite tilings. (I would like to thank […]</summary>
    <content type="xhtml" xml:lang="en"><div xmlns="http://www.w3.org/1999/xhtml"><h2 id="introduction">Introduction</h2>
<p><strong>(Updated April 2026 for PenroseKiteDart version 1.8)</strong></p>
<p>PenroseKiteDart is a Haskell package with tools to experiment with finite tilings of Penrose’s Kites and Darts. It uses the <a href="https://diagrams.github.io">Haskell Diagrams</a> package for drawing tilings. As well as providing drawing tools, this package introduces tile graphs (<code>Tgraphs</code>) for describing finite tilings. (I would like to thank Stephen Huggett for suggesting planar graphs as a way to reperesent the tilings).</p>
<p>This document summarises the design and use of the PenroseKiteDart package.</p>
<p>PenroseKiteDart package is now available on <a href="https://hackage.haskell.org">Hackage</a>.</p>
<p>The source files are available on GitHub at <a href="https://github.com/chrisreade/PenroseKiteDart">https://github.com/chrisreade/PenroseKiteDart</a>.</p>
<p>There is a small art gallery of examples created with PenroseKiteDart <a href="https://github.com/chrisreade/PenroseKiteDart/tree/master/ArtGallery">here</a>.</p>
<p><strong>Index</strong></p>
<ol type="1">
<li><a href="https://readerunner.wordpress.com/2024/04/08/penrosekitedart-user-guides/#1">About Penrose’s Kites and Darts</a></li>
<li><a href="https://readerunner.wordpress.com/2024/04/08/penrosekitedart-user-guides/#2">Using the PenroseKiteDart Package</a> (initial set up).</li>
<li><a href="https://readerunner.wordpress.com/2024/04/08/penrosekitedart-user-guides/#3">Overview of Types and Operations</a></li>
<li><a href="https://readerunner.wordpress.com/2024/04/08/penrosekitedart-user-guides/#4">Drawing in more detail</a></li>
<li><a href="https://readerunner.wordpress.com/2024/04/08/penrosekitedart-user-guides/#5">Forcing in more detail</a></li>
<li><a href="https://readerunner.wordpress.com/2024/04/08/penrosekitedart-user-guides/#6">Advanced Operations</a></li>
<li><a href="https://readerunner.wordpress.com/2024/04/08/penrosekitedart-user-guides/#7">Other Reading</a></li>
</ol>
<p><a name="1"> </a></p>
<h2 id="about-penroses-kites-and-darts">1. About Penroseâ€™s Kites and Darts</h2>
<h3 id="the-tiles">The Tiles</h3>
<p>In figure 1 we show a dart and a kite. All angles are multiples of <img alt="36^{\circ}" class="latex" src="https://s0.wp.com/latex.php?latex=36%5E%7B%5Ccirc%7D&amp;bg=ffffff&amp;fg=444444&amp;s=0&amp;c=20201002"/> (a tenth of a full turn). If the shorter edges are of length 1, then the longer edges are of length <img alt="\phi" class="latex" src="https://s0.wp.com/latex.php?latex=%5Cphi&amp;bg=ffffff&amp;fg=444444&amp;s=0&amp;c=20201002"/>, where <img alt="\phi = (1+ \sqrt{5})/ 2" class="latex" src="https://s0.wp.com/latex.php?latex=%5Cphi+%3D+%281%2B+%5Csqrt%7B5%7D%29%2F+2&amp;bg=ffffff&amp;fg=444444&amp;s=0&amp;c=20201002"/> is the golden ratio.</p>
<figure>
<img alt="Figure 1: The Dart and Kite Tiles" src="https://readerunner.wordpress.com/wp-content/uploads/2024/04/geomtiles.png?w=625"/><figcaption>Figure 1: The Dart and Kite Tiles</figcaption></figure>
<h3 id="aperiodic-infinite-tilings">Aperiodic Infinite Tilings</h3>
<p>What is interesting about these tiles is:</p>
<p><em>It is possible to tile the entire plane with kites and darts in an aperiodic way.</em></p>
<p>Such a tiling is non-periodic and does not contain arbitrarily large periodic regions or patches.</p>
<p>The possibility of aperiodic tilings with kites and darts was discovered by Sir Roger Penrose in 1974. There are other shapes with this property, including a chiral aperiodic monotile discovered in 2023 by Smith, Myers, Kaplan, Goodman-Strauss. (See the Penrose Tiling <a href="https://en.wikipedia.org/wiki/Penrose_tiling">Wikipedia page</a> for the history of aperiodic tilings)</p>
<p>This package is entirely concerned with Penrose’s kite and dart tilings also known as P2 tilings.</p>
<h3 id="legal-tilings">Legal Tilings</h3>
<p>In figure 2 we add a temporary green line marking purely to illustrate a rule for making <em>legal tilings</em>. The purpose of the rule is to exclude the possibility of periodic tilings.</p>
<p>If all tiles are marked as shown, then whenever tiles come together at a point, they must all be marked or must all be unmarked at that meeting point. So, for example, each long edge of a kite can be placed legally on only <em>one</em> of the two long edges of a dart. The kite wing vertex (which is marked) has to go next to the dart tip vertex (which is marked) and cannot go next to the dart wing vertex (which is unmarked) for a legal tiling.</p>
<figure>
<img alt="Figure 2: Marked Dart and Kite" src="https://readerunner.wordpress.com/wp-content/uploads/2024/04/markedtiles2.png?w=625"/><figcaption>Figure 2: Marked Dart and Kite</figcaption></figure>
<h3 id="correct-tilings">Correct Tilings</h3>
<p>Unfortunately, having a finite legal tiling is not enough to guarantee you can continue the tiling without getting stuck. Finite legal tilings which can be continued to cover the entire plane are called <em>correct</em> and the others (which are doomed to get stuck) are called <em>incorrect</em>. This means that decomposition and forcing (described later) become important tools for constructing correct finite tilings.</p>
<p><a name="2"> </a></p>
<h2 id="using-the-penrosekitedart-package">2. Using the PenroseKiteDart Package</h2>
<p>You will need the Haskell Diagrams package (See <a href="https://diagrams.github.io">Haskell Diagrams</a>) as well as this package (PenroseKiteDart). When these are installed, you can produce diagrams with a Main.hs module. This should import a chosen backend for diagrams such as the default (SVG) along with <code>Diagrams.Prelude</code>.</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span style="color: blue; font-weight: bold;">module</span> <span>Main</span> <span style="color: red;">(</span><span>main</span><span style="color: red;">)</span> <span style="color: blue; font-weight: bold;">where</span>
    
    <span style="color: blue; font-weight: bold;">import</span> <span>Diagrams.Backend.SVG.CmdLine</span>
    <span style="color: blue; font-weight: bold;">import</span> <span>Diagrams.Prelude</span></code></pre>
<p>For Penrose’s Kite and Dart tilings, you also need to import the <code>PKD</code> module and (optionally) the <code>TgraphExamples</code> module.</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span style="color: blue; font-weight: bold;">import</span> <span>PKD</span>
    <span style="color: blue; font-weight: bold;">import</span> <span>TgraphExamples</span></code></pre>
<p>Then to ouput <code>someExample</code> figure</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>fig</span><span style="color: red;">::</span><span>Diagram</span> <span>B</span>
    <span>fig</span> <span style="color: red;">=</span> <span>someExample</span>

    <span>main</span> <span style="color: red;">::</span> <span>IO</span> <span>()</span>
    <span>main</span> <span style="color: red;">=</span> <span>mainWith</span> <span>fig</span></code></pre>
<p>Note that the token <code>B</code> is used in the diagrams package to represent the chosen backend for output. So a diagram has type <code>Diagram B</code>. In this case <code>B</code> is bound to SVG by the import of the SVG backend. When the compiled module is executed it will generate an SVG file. (See <a href="https://diagrams.github.io">Haskell Diagrams</a> for more details on producing diagrams and using alternative backends).</p>
<p><a name="3"> </a></p>
<h2 id="overview-of-types-and-operations">3. Overview of Types and Operations</h2>
<h3 id="half-tiles">Half-Tiles</h3>
<p>In order to implement operations on tilings (<code>decompose</code> in particular), we work with half-tiles. These are illustrated in figure 3 and labelled <code>RD</code> (right dart), <code>LD</code> (left dart), <code>LK</code> (left kite), <code>RK</code> (right kite). The <em>join</em> edges where left and right halves come together are shown with dotted lines, leaving one short edge and one long edge on each half-tile (excluding the join edge). We have shown a red dot at the vertex we regard as the origin of each half-tile (the tip of a half-dart and the base of a half-kite).</p>
<figure>
<img alt="Figure 3: Half-Tile pieces showing join edges (dashed) and origin vertices (red dots)" src="https://readerunner.wordpress.com/wp-content/uploads/2024/04/newpiecesfig.png?w=625"/><figcaption>Figure 3: Half-Tile pieces showing join edges (dashed) and origin vertices (red dots)</figcaption></figure>
<p>The labels are actually data constructors introduced with type operator <code>HalfTile</code> which has an argument type (<code>rep</code>) to allow for more than one representation of the half-tiles.</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span style="color: blue; font-weight: bold;">data</span> <span>HalfTile</span> <span>rep</span> 
      <span style="color: red;">=</span> <span>LD</span> <span>rep</span> <span style="color: green;">-- Left Dart</span>
      <span style="color: red;">|</span> <span>RD</span> <span>rep</span> <span style="color: green;">-- Right Dart</span>
      <span style="color: red;">|</span> <span>LK</span> <span>rep</span> <span style="color: green;">-- Left Kite</span>
      <span style="color: red;">|</span> <span>RK</span> <span>rep</span> <span style="color: green;">-- Right Kite</span>
      <span style="color: blue; font-weight: bold;">deriving</span> <span style="color: red;">(</span><span>Show</span><span style="color: red;">,</span><span>Eq</span><span style="color: red;">)</span></code></pre>
<h3 id="tgraphs">Tgraphs</h3>
<p>We introduce tile graphs (<code>Tgraph</code>s) which provide a simple planar graph representation for finite patches of tiles. For <code>Tgraph</code>s we first specialise <code>HalfTile</code> with a triple of vertices (positive integers) to make a <code>TileFace</code> such as <code>RD(1,2,3)</code>, where the vertices go clockwise round the half-tile triangle starting with the origin.</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span style="color: blue; font-weight: bold;">type</span> <span>TileFace</span>  <span style="color: red;">=</span> <span>HalfTile</span> <span style="color: red;">(</span><span>Vertex</span><span style="color: red;">,</span><span>Vertex</span><span style="color: red;">,</span><span>Vertex</span><span style="color: red;">)</span>
    <span style="color: blue; font-weight: bold;">type</span> <span>Vertex</span>    <span style="color: red;">=</span> <span>Int</span>  <span style="color: green;">-- must be positive</span></code></pre>
<p>The function</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>makeTgraph</span> <span style="color: red;">::</span> <span style="color: red;">[</span><span>TileFace</span><span style="color: red;">]</span> <span style="color: red;">-&gt;</span> <span>Tgraph</span></code></pre>
<p>then constructs a <code>Tgraph</code> from a <code>TileFace</code> list after checking the <code>TileFace</code>s satisfy certain properties (described below). We also have</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>faces</span> <span style="color: red;">::</span> <span>Tgraph</span> <span style="color: red;">-&gt;</span> <span style="color: red;">[</span><span>TileFace</span><span style="color: red;">]</span></code></pre>
<p>to retrieve the <code>TileFace</code> list from a <code>Tgraph</code>.</p>
<p>As an example, the <code>fool</code> (short for <em>fool’s kite</em> and also called an <em>ace</em> in the literature) consists of two kites and a dart (= 4 half-kites and 2 half-darts):</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>fool</span> <span style="color: red;">::</span> <span>Tgraph</span>
    <span>fool</span> <span style="color: red;">=</span> <span>makeTgraph</span> <span style="color: red;">[</span><span>RD</span> <span style="color: red;">(</span><span class="hs-num">1</span><span style="color: red;">,</span><span class="hs-num">2</span><span style="color: red;">,</span><span class="hs-num">3</span><span style="color: red;">)</span><span style="color: red;">,</span> <span>LD</span> <span style="color: red;">(</span><span class="hs-num">1</span><span style="color: red;">,</span><span class="hs-num">3</span><span style="color: red;">,</span><span class="hs-num">4</span><span style="color: red;">)</span>   <span style="color: green;">-- right and left dart</span>
                      <span style="color: red;">,</span><span>LK</span> <span style="color: red;">(</span><span class="hs-num">5</span><span style="color: red;">,</span><span class="hs-num">3</span><span style="color: red;">,</span><span class="hs-num">2</span><span style="color: red;">)</span><span style="color: red;">,</span> <span>RK</span> <span style="color: red;">(</span><span class="hs-num">5</span><span style="color: red;">,</span><span class="hs-num">2</span><span style="color: red;">,</span><span class="hs-num">7</span><span style="color: red;">)</span>   <span style="color: green;">-- left and right kite</span>
                      <span style="color: red;">,</span><span>RK</span> <span style="color: red;">(</span><span class="hs-num">5</span><span style="color: red;">,</span><span class="hs-num">4</span><span style="color: red;">,</span><span class="hs-num">3</span><span style="color: red;">)</span><span style="color: red;">,</span> <span>LK</span> <span style="color: red;">(</span><span class="hs-num">5</span><span style="color: red;">,</span><span class="hs-num">6</span><span style="color: red;">,</span><span class="hs-num">4</span><span style="color: red;">)</span>   <span style="color: green;">-- right and left kite</span>
                      <span style="color: red;">]</span></code></pre>
<p>To produce a diagram, we simply <code>draw</code> the <code>Tgraph</code></p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>foolFigure</span> <span style="color: red;">::</span> <span>Diagram</span> <span>B</span>
    <span>foolFigure</span> <span style="color: red;">=</span> <span>draw</span> <span>fool</span></code></pre>
<p>which will produce the diagram on the left in figure 4.</p>
<p>Alternatively,</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>foolFigure</span> <span style="color: red;">::</span> <span>Diagram</span> <span>B</span>
    <span>foolFigure</span> <span style="color: red;">=</span> <span>labelled</span> <span>drawj</span> <span>fool</span></code></pre>
<p>will produce the diagram on the right in figure 4 (showing vertex labels and dashed join edges).</p>
<figure>
<img alt="Figure 4: Diagram of fool without labels and join edges (left), and with (right)" src="https://readerunner.wordpress.com/wp-content/uploads/2024/04/newfool.png?w=625"/><figcaption>Figure 4: Diagram of <code>fool</code> without labels and join edges (left), and with (right)</figcaption></figure>
<p>When any (non-empty) <code>Tgraph</code> is drawn, a default orientation and scale are chosen based on the lowest numbered join edge. This is aligned on the positive x-axis with length 1 (for darts) or length <img alt="\phi" class="latex" src="https://s0.wp.com/latex.php?latex=%5Cphi&amp;bg=ffffff&amp;fg=444444&amp;s=0&amp;c=20201002"/> (for kites).</p>
<h3 id="tgraph-properties">Tgraph Properties</h3>
<p>Tgraphs are actually implemented as</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span style="color: blue; font-weight: bold;">newtype</span> <span>Tgraph</span> <span style="color: red;">=</span> <span>Tgraph</span> <span style="color: red;">[</span><span>TileFace</span><span style="color: red;">]</span>
                     <span style="color: blue; font-weight: bold;">deriving</span> <span style="color: red;">(</span><span>Show</span><span style="color: red;">)</span></code></pre>
<p>but the data constructor <code>Tgraph</code> is not exported to avoid accidentally by-passing checks for the required properties. The properties checked by <code>makeTgraph</code> ensure the <code>Tgraph</code> represents a legal tiling as a planar graph with positive vertex numbers, and that the collection of half-tile faces are both connected and have no crossing boundaries (see note below). Finally, there is a check to ensure two or more distinct vertex numbers are not used to represent the same vertex of the graph (a <em>touching vertex</em> check). An error is raised if there is a problem.</p>
<p>Note: If the <code>TileFace</code>s are faces of a planar graph there will also be exterior (untiled) regions, and in graph theory these would also be called faces of the graph. To avoid confusion, we will refer to these only as <em>exterior regions</em>, and unless otherwise stated, <em>face</em> will mean a <code>TileFace</code>. We can then define the boundary of a list of <code>TileFace</code>s as the edges of the exterior regions. There is a <em>crossing boundary</em> if the boundary crosses itself at a vertex. We exclude crossing boundaries from <code>Tgraph</code>s because they prevent us from calculating relative positions of tiles locally and create touching vertex problems.</p>
<p>For convenience, in addition to <code>makeTgraph</code>, we also have</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>makeUncheckedTgraph</span> <span style="color: red;">::</span> <span style="color: red;">[</span><span>TileFace</span><span style="color: red;">]</span> <span style="color: red;">-&gt;</span> <span>Tgraph</span>
    <span>checkedTgraph</span>   <span style="color: red;">::</span> <span style="color: red;">[</span><span>TileFace</span><span style="color: red;">]</span> <span style="color: red;">-&gt;</span> <span>Tgraph</span></code></pre>
<p>The first of these (performing no checks) is useful when you know the required properties hold. The second performs the same checks as <code>makeTgraph</code> except that it omits the touching vertex check. This could be used, for example, when making a <code>Tgraph</code> from a sub-collection of <code>TileFace</code>s of another <code>Tgraph</code>.</p>
<h3 id="main-tiling-operations">Main Tiling Operations</h3>
<p>There are three key operations on finite tilings, namely</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>decompose</span> <span style="color: red;">::</span> <span>Tgraph</span> <span style="color: red;">-&gt;</span> <span>Tgraph</span>
    <span>force</span>     <span style="color: red;">::</span> <span>Tgraph</span> <span style="color: red;">-&gt;</span> <span>Tgraph</span>
    <span>compose</span>   <span style="color: red;">::</span> <span>Tgraph</span> <span style="color: red;">-&gt;</span> <span>Tgraph</span></code></pre>
<h4 id="decompose">Decompose</h4>
<p>Decomposition (also called <em>deflation</em>) works by splitting each half-tile into either 2 or 3 new (<em>smaller scale</em>) half-tiles, to produce a new tiling. The fact that this is possible, is used to establish the existence of infinite aperiodic tilings with kites and darts. Since our <code>Tgraph</code>s have abstracted away from scale, the result of decomposing a <code>Tgraph</code> is just another <code>Tgraph</code>. However if we wish to compare before and after with a drawing, the latter should be scaled by a factor <img alt="1/{\phi} = \phi - 1" class="latex" src="https://s0.wp.com/latex.php?latex=1%2F%7B%5Cphi%7D+%3D+%5Cphi+-+1&amp;bg=ffffff&amp;fg=444444&amp;s=0&amp;c=20201002"/> times the scale of the former, to reflect the change in scale.</p>
<figure>
<img alt="Figure 5: fool (left) and decompose fool (right)" src="https://readerunner.wordpress.com/wp-content/uploads/2024/04/foolandfoold.png?w=625"/><figcaption>Figure 5: <code>fool</code> (left) and <code>decompose fool</code> (right)</figcaption></figure>
<p>We can, of course, iterate <code>decompose</code> to produce an infinite list of finer and finer decompositions of a <code>Tgraph</code></p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>decompositions</span> <span style="color: red;">::</span> <span>Tgraph</span> <span style="color: red;">-&gt;</span> <span style="color: red;">[</span><span>Tgraph</span><span style="color: red;">]</span>
    <span>decompositions</span> <span style="color: red;">=</span> <span>iterate</span> <span>decompose</span></code></pre>
<h4 id="force">Force</h4>
<p>Force works by adding any <code>TileFace</code>s on the boundary edges of a <code>Tgraph</code> which are <em>forced</em>. That is, where there is only one legal choice of <code>TileFace</code> addition consistent with the seven possible vertex types. Such additions are continued until either (i) there are no more forced cases, in which case a final (forced) <code>Tgraph</code> is returned, or (ii) the process finds the tiling is stuck, in which case an error is raised indicating an incorrect tiling. [In the latter case, the argument to <code>force</code> must have been an incorrect tiling, because the forced additions cannot produce an incorrect tiling starting from a correct tiling.]</p>
<p>An example is shown in figure 6. When forced, the <code>Tgraph</code> on the left produces the result on the right. The original is highlighted in red in the result to show what has been added.</p>
<figure>
<img alt="Figure 6: A Tgraph (left) and its forced result (right) with the original shown red" src="https://readerunner.wordpress.com/wp-content/uploads/2024/04/fooldandforce.png?w=625"/><figcaption>Figure 6: A Tgraph (left) and its forced result (right) with the original shown red</figcaption></figure>
<h4 id="compose">Compose</h4>
<p>Composition (also called <em>inflation</em>) is an opposite to <code>decompose</code> but this has complications for finite tilings, so it is not simply an inverse. (See <a href="https://readerunner.wordpress.com/2023/09/12/graphs-kites-and-darts-and-theorems/">Graphs,Kites and Darts and Theorems</a> for more discussion of the problems). Figure 7 shows a <code>Tgraph</code> (left) with the result of composing (right) where we have also shown (in pale green) the faces of the original that are not included in the composition – the remainder faces.</p>
<figure>
<img alt="Figure 7: A Tgraph (left) and its (part) composed result (right) with the remainder faces shown pale green" src="https://readerunner.wordpress.com/wp-content/uploads/2024/04/pcomposeexample.png?w=625"/><figcaption>Figure 7: A Tgraph (left) and its (part) composed result (right) with the remainder faces shown pale green</figcaption></figure>
<p>Under some circumstances composing can fail to produce a <code>Tgraph</code> because there are crossing boundaries in the resulting <code>TileFaces</code>. However, we have established that</p>
<ul>
<li>If <code>g</code> is a forced <code>Tgraph</code>, then <code>compose g</code> is defined and it is also a forced <code>Tgraph</code>.</li>
</ul>
<h3 id="try-results">Try Results</h3>
<p>It is convenient to use types of the form <code>Try a</code> for results where we know there can be a failure. For example, <code>compose</code> can fail if the result does not pass the connected and no crossing boundary check, and <code>force</code> can fail if its argument is an incorrect <code>Tgraph</code>. In situations when you would like to continue some computation rather than raise an error when there is a failure, use a <em>try</em> version of a function.</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>tryCompose</span> <span style="color: red;">::</span> <span>Tgraph</span> <span style="color: red;">-&gt;</span> <span>Try</span> <span>Tgraph</span>
    <span>tryForce</span>   <span style="color: red;">::</span> <span>Tgraph</span> <span style="color: red;">-&gt;</span> <span>Try</span> <span>Tgraph</span></code></pre>
<p>We define <code>Try</code> as a synonym for <code>Either ShowS</code> (which is a monad) in module <code>Tgraph.Try</code>.</p>
<pre><code>type Try a = Either ShowS a</code></pre>
<p>(Note <code>ShowS</code> is <code>String -&gt; String</code>). Successful results have the form <code>Right r</code> (for some correct result <code>r</code>) and failure results have the form <code>Left (s&lt;&gt;)</code> (where <code>s</code> is a <code>String</code> describing the problem as a failure report).</p>
<p>The function</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>runTry</span><span style="color: red;">::</span> <span>Try</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>a</span>
    <span>runTry</span> <span style="color: red;">=</span> <span>either</span> <span>error</span> <span>id</span></code></pre>
<p>will retrieve a correct result but raise an error for failure cases. This means we can always derive an error raising version from a try version of a function by composing with <code>runTry</code>.</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>force</span> <span style="color: red;">=</span> <span>runTry</span> <span>.</span> <span>tryForce</span>
    <span>compose</span> <span style="color: red;">=</span> <span>runTry</span> <span>.</span> <span>tryCompose</span></code></pre>
<h3 id="elementary-tgraph-and-tileface-operations">Elementary Tgraph and TileFace Operations</h3>
<p>The module <code>Tgraph.Prelude</code> defines elementary operations on <code>Tgraph</code>s relating vertices, directed edges, and faces. We describe a few of them here.</p>
<p>When we need to refer to particular vertices of a <code>TileFace</code> we use</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>originV</span> <span style="color: red;">::</span> <span>TileFace</span> <span style="color: red;">-&gt;</span> <span>Vertex</span> <span style="color: green;">-- the first vertex - red dot in figure 2</span>
    <span>oppV</span>    <span style="color: red;">::</span> <span>TileFace</span> <span style="color: red;">-&gt;</span> <span>Vertex</span> <span style="color: green;">-- the vertex at the opposite end of the join edge from the origin</span>
    <span>wingV</span>   <span style="color: red;">::</span> <span>TileFace</span> <span style="color: red;">-&gt;</span> <span>Vertex</span> <span style="color: green;">-- the vertex not on the join edge</span></code></pre>
<p>A directed edge is represented as a pair of vertices.</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span style="color: blue; font-weight: bold;">type</span> <span>Dedge</span> <span style="color: red;">=</span> <span style="color: red;">(</span><span>Vertex</span><span style="color: red;">,</span><span>Vertex</span><span style="color: red;">)</span></code></pre>
<p>So <code>(a,b)</code> is regarded as a directed edge from a to b.</p>
<p>When we need to refer to particular edges of a <code>TileFace</code> we use</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>joinE</span>  <span style="color: red;">::</span> <span>TileFace</span> <span style="color: red;">-&gt;</span> <span>Dedge</span>  <span style="color: green;">-- shown dotted in figure 2</span>
    <span>shortE</span> <span style="color: red;">::</span> <span>TileFace</span> <span style="color: red;">-&gt;</span> <span>Dedge</span>  <span style="color: green;">-- the non-join short edge</span>
    <span>longE</span>  <span style="color: red;">::</span> <span>TileFace</span> <span style="color: red;">-&gt;</span> <span>Dedge</span>  <span style="color: green;">-- the non-join long edge</span></code></pre>
<p>which are all directed clockwise round the <code>TileFace</code>. In contrast, <code>joinOfTile</code> is always directed away from the origin vertex, so is not clockwise for right darts or for left kites:</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>joinOfTile</span><span style="color: red;">::</span> <span>TileFace</span> <span style="color: red;">-&gt;</span> <span>Dedge</span>
    <span>joinOfTile</span> <span>face</span> <span style="color: red;">=</span> <span style="color: red;">(</span><span>originV</span> <span>face</span><span style="color: red;">,</span> <span>oppV</span> <span>face</span><span style="color: red;">)</span></code></pre>
<p>In the special case that a list of directed edges is symmetrically closed [(b,a) is in the list whenever (a,b) is in the list] we can think of this as an edge list rather than just a directed edge list.</p>
<p>For example,</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>internalEdges</span> <span style="color: red;">::</span> <span>Tgraph</span> <span style="color: red;">-&gt;</span> <span style="color: red;">[</span><span>Dedge</span><span style="color: red;">]</span></code></pre>
<p>produces an edge list, whereas</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>boundary</span> <span style="color: red;">::</span> <span>Tgraph</span> <span style="color: red;">-&gt;</span> <span style="color: red;">[</span><span>Dedge</span><span style="color: red;">]</span></code></pre>
<p>produces single directions. Each directed edge in the resulting boundary will have a <code>TileFace</code> on the left and an exterior region on the right. The function</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>dedges</span> <span style="color: red;">::</span> <span>Tgraph</span> <span style="color: red;">-&gt;</span> <span style="color: red;">[</span><span>Dedge</span><span style="color: red;">]</span></code></pre>
<p>produces all the directed edges obtained by going clockwise round each <code>TileFace</code> so not every edge in the list has an inverse in the list.</p>
<p><strong>Note 1:</strong> There is now a class <code>HasFaces</code> (introduced in version 1.4) which includes instances for both <code>Tgraph</code> and <code>[TileFace]</code> and others. This allows some generalisations. For example</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>faces</span>         <span style="color: red;">::</span> <span>HasFaces</span> <span>a</span> <span style="color: red;">=&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span style="color: red;">[</span><span>TileFace</span><span style="color: red;">]</span>
    <span>internalEdges</span> <span style="color: red;">::</span> <span>HasFaces</span> <span>a</span> <span style="color: red;">=&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span style="color: red;">[</span><span>Dedge</span><span style="color: red;">]</span>
    <span>boundary</span>      <span style="color: red;">::</span> <span>HasFaces</span> <span>a</span> <span style="color: red;">=&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span style="color: red;">[</span><span>Dedge</span><span style="color: red;">]</span> 
    <span>dedges</span>        <span style="color: red;">::</span> <span>HasFaces</span> <span>a</span> <span style="color: red;">=&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span style="color: red;">[</span><span>Dedge</span><span style="color: red;">]</span> 
    <span>nullFaces</span>     <span style="color: red;">::</span> <span>HasFaces</span> <span>a</span> <span style="color: red;">=&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>Bool</span></code></pre>
<p><strong>Note 2:</strong> There is now a class <code>HasGraph</code> (introduced in version 1.8) which includes instances for <code>Tgraph</code> as well as other types used in forcing. This allows some other generalisations. For example</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>compose</span> <span style="color: red;">::</span> <span>HasGraph</span> <span>a</span> <span style="color: red;">=&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>Tgraph</span>
    <span>decompose</span> <span style="color: red;">::</span> <span>HasGraph</span> <span>a</span> <span style="color: red;">=&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>Tgraph</span>
    <span>recoverGraph</span> <span style="color: red;">::</span> <span>HasGraph</span> <span>a</span> <span style="color: red;">=&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>Tgraph</span></code></pre>
<h3 id="patches-scaled-and-positioned-tilings">Patches (Scaled and Positioned Tilings)</h3>
<p>Behind the scenes, when a <code>Tgraph</code> is drawn, each <code>TileFace</code> is converted to a <code>Piece</code>. A <code>Piece</code> is another specialisation of <code>HalfTile</code> using a two dimensional vector to indicate the length and direction of the join edge of the half-tile (from the <code>originV</code> to the <code>oppV</code>), thus fixing its scale and orientation. The whole <code>Tgraph</code> then becomes a list of located <code>Piece</code>s called a <code>Patch</code>.</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span style="color: blue; font-weight: bold;">type</span> <span>Piece</span> <span style="color: red;">=</span> <span>HalfTile</span> <span style="color: red;">(</span><span>V2</span> <span>Double</span><span style="color: red;">)</span>
    <span style="color: blue; font-weight: bold;">type</span> <span>Patch</span> <span style="color: red;">=</span> <span style="color: red;">[</span><span>Located</span> <span>Piece</span><span style="color: red;">]</span></code></pre>
<p><code>Piece</code> drawing functions derive vectors for other edges of a half-tile piece from its join edge vector. In particular (in the <code>TileLib</code> module) we have</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>drawPiece</span> <span style="color: red;">::</span> <span>Piece</span> <span style="color: red;">-&gt;</span> <span>Diagram</span> <span>B</span>
    <span>darawjPiece</span> <span style="color: red;">::</span> <span>Piece</span> <span style="color: red;">-&gt;</span> <span>Diagram</span> <span>B</span>
    <span>fillPieceDK</span> <span style="color: red;">::</span> <span>Colour</span> <span>Double</span> <span style="color: red;">-&gt;</span> <span>Colour</span> <span>Double</span> <span style="color: red;">-&gt;</span> <span>Piece</span> <span style="color: red;">-&gt;</span> <span>Diagram</span> <span>B</span></code></pre>
<p>where the first draws the non-join edges of a <code>Piece</code>, the second does the same but adds a faint dashed line for the join edge, and the third takes two colours – one for darts and one for kites, which are used to fill the piece as well as using <code>drawPiece</code>.</p>
<p><code>Patch</code> is an instance of class <code>Transformable</code> so a <code>Patch</code> can be scaled, rotated, and translated.</p>
<h3 id="vertex-patches">Vertex Patches</h3>
<p>It is useful to have an intermediate form between <code>Tgraph</code>s and <code>Patch</code>es, that contains information about both the location of vertices (as 2D points), and the abstract <code>TileFace</code>s. This allows us to introduce labelled drawing functions (to show the vertex labels) which we then extend to <code>Tgraph</code>s. We call the intermediate form a <code>VPatch</code> (short for Vertex Patch).</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span style="color: blue; font-weight: bold;">type</span> <span>VertexLocMap</span> <span style="color: red;">=</span> <span>IntMap.IntMap</span> <span style="color: red;">(</span><span>Point</span> <span>V2</span> <span>Double</span><span style="color: red;">)</span>
    <span style="color: blue; font-weight: bold;">data</span> <span>VPatch</span> <span style="color: red;">=</span> <span>VPatch</span> <span style="color: red;">{</span><span>vLocs</span> <span style="color: red;">::</span> <span>VertexLocMap</span><span style="color: red;">,</span>  <span>vpFaces</span><span style="color: red;">::</span><span style="color: red;">[</span><span>TileFace</span><span style="color: red;">]</span><span style="color: red;">}</span> <span style="color: blue; font-weight: bold;">deriving</span> <span>Show</span></code></pre>
<p>and</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>makeVP</span> <span style="color: red;">::</span> <span>HasGraph</span> <span>a</span> <span style="color: red;">=&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>VPatch</span></code></pre>
<p>calculates vertex locations using a default orientation and scale.</p>
<p><code>VPatch</code> is made an instance of class <code>Transformable</code> so a <code>VPatch</code> can also be scaled and rotated.</p>
<p>One essential use of this intermediate form is to be able to draw a <code>Tgraph</code> with labels, rotated but without the labels themselves being rotated. We can simply convert the <code>Tgraph</code> to a <code>VPatch</code>, and rotate that before drawing with labels.</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>labelled</span> <span>draw</span> <span style="color: red;">(</span><span>rotate</span> <span>someAngle</span> <span style="color: red;">(</span><span>makeVP</span> <span>g</span><span style="color: red;">)</span><span style="color: red;">)</span></code></pre>
<p>We can also align a <code>VPatch</code> using vertex labels.</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>alignXaxis</span> <span style="color: red;">::</span> <span style="color: red;">(</span><span>Vertex</span><span style="color: red;">,</span> <span>Vertex</span><span style="color: red;">)</span> <span style="color: red;">-&gt;</span> <span>VPatch</span> <span style="color: red;">-&gt;</span> <span>VPatch</span> </code></pre>
<p>So if <code>g</code> is a <code>Tgraph</code> with vertex labels <code>a</code> and <code>b</code> we can align it on the x-axis with <code>a</code> at the origin and <code>b</code> on the positive x-axis (after converting to a <code>VPatch</code>), instead of accepting the default orientation.</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>labelled</span> <span>draw</span> <span style="color: red;">(</span><span>alignXaxis</span> <span style="color: red;">(</span><span>a</span><span style="color: red;">,</span><span>b</span><span style="color: red;">)</span> <span style="color: red;">(</span><span>makeVP</span> <span>g</span><span style="color: red;">)</span><span style="color: red;">)</span></code></pre>
<p>Another use of <code>VPatch</code>es is to share the vertex location map when drawing only subsets of the faces (see <em>Overlaid examples</em> in the next section).</p>
<p><a name="4"> </a></p>
<h2 id="drawing-in-more-detail">4. Drawing in More Detail</h2>
<h3 id="class-drawable">Class Drawable</h3>
<p>There is a class <code>Drawable</code> with instances <code>Tgraph</code>, <code>VPatch</code>, <code>Patch</code>. When the token <code>B</code> is in scope standing for a fixed backend then we can assume</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>draw</span>   <span style="color: red;">::</span> <span>Drawable</span> <span>a</span> <span style="color: red;">=&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>Diagram</span> <span>B</span>  <span style="color: green;">-- draws non-join edges</span>
    <span>drawj</span>  <span style="color: red;">::</span> <span>Drawable</span> <span>a</span> <span style="color: red;">=&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>Diagram</span> <span>B</span>  <span style="color: green;">-- as with draw but also draws dashed join edges</span>
    <span>fillDK</span> <span style="color: red;">::</span> <span>Drawable</span> <span>a</span> <span style="color: red;">=&gt;</span> <span>Colour</span> <span>Double</span> <span style="color: red;">-&gt;</span> <span>Colour</span> <span>Double</span> <span style="color: red;">-&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>Diagram</span> <span>B</span> <span style="color: green;">-- fills with colours</span></code></pre>
<p>where <code>fillDK clr1 clr2</code> will fill darts with colour <code>clr1</code> and kites with colour <code>clr2</code> as well as drawing non-join edges.</p>
<p>These are the main drawing tools. However they are actually defined for any suitable backend <code>b</code> so have more general types.</p>
<p>(<em>Update Sept 2024</em>) From version 1.1 onwards of PenroseKiteDart, these are</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>draw</span> <span style="color: red;">::</span>   <span style="color: red;">(</span><span>Drawable</span> <span>a</span><span style="color: red;">,</span> <span>OKBackend</span> <span>b</span><span style="color: red;">)</span> <span style="color: red;">=&gt;</span>
              <span>a</span> <span style="color: red;">-&gt;</span> <span>Diagram</span> <span>b</span>
    <span>drawj</span> <span style="color: red;">::</span>  <span style="color: red;">(</span><span>Drawable</span> <span>a</span><span style="color: red;">,</span> <span>OKBackend</span><span style="color: red;">)</span> <span>b</span><span style="color: red;">)</span> <span style="color: red;">=&gt;</span>
              <span>a</span> <span style="color: red;">-&gt;</span> <span>Diagram</span> <span>b</span>
    <span>fillDK</span> <span style="color: red;">::</span> <span style="color: red;">(</span><span>Drawable</span> <span>a</span><span style="color: red;">,</span> <span>OKBackend</span> <span>b</span><span style="color: red;">)</span> <span style="color: red;">=&gt;</span>
              <span>Colour</span> <span>Double</span> <span style="color: red;">-&gt;</span> <span>Colour</span> <span>Double</span> <span style="color: red;">-&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>Diagram</span> <span>b</span></code></pre>
<p>where the class <code>OKBackend</code> is a check to ensure a backend is suitable for drawing 2D tilings with or without labels.</p>
<p><strong>In these notes we will generally use the simpler description of types using <code>B</code> for a fixed chosen backend for the sake of clarity.</strong></p>
<p>The drawing tools are each defined via the class function <code>drawWith</code> using <code>Piece</code> drawing functions.</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span style="color: blue; font-weight: bold;">class</span> <span>Drawable</span> <span>a</span> <span style="color: blue; font-weight: bold;">where</span>
        <span>drawWith</span> <span style="color: red;">::</span> <span style="color: red;">(</span><span>Piece</span> <span style="color: red;">-&gt;</span> <span>Diagram</span> <span>B</span><span style="color: red;">)</span> <span style="color: red;">-&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>Diagram</span> <span>B</span>
    
    <span>draw</span> <span style="color: red;">=</span> <span>drawWith</span> <span>drawPiece</span>
    <span>drawj</span> <span style="color: red;">=</span> <span>drawWith</span> <span>drawjPiece</span>
    <span>fillDK</span> <span>clr1</span> <span>clr2</span> <span style="color: red;">=</span> <span>drawWith</span> <span style="color: red;">(</span><span>fillPieceDK</span> <span>clr1</span> <span>clr2</span><span style="color: red;">)</span></code></pre>
<p>To design a new drawing function, you only need to implement a function to draw a <code>Piece</code>, (let us call it <code>newPieceDraw</code>)</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>newPieceDraw</span> <span style="color: red;">::</span> <span>Piece</span> <span style="color: red;">-&gt;</span> <span>Diagram</span> <span>B</span></code></pre>
<p>This can then be elevated to draw any <code>Drawable</code> (including <code>Tgraph</code>s, <code>VPatch</code>es, and <code>Patch</code>es) by applying the <code>Drawable</code> class function <code>drawWith</code>:</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>newDraw</span> <span style="color: red;">::</span> <span>Drawable</span> <span>a</span> <span style="color: red;">=&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>Diagram</span> <span>B</span>
    <span>newDraw</span> <span style="color: red;">=</span> <span>drawWith</span> <span>newPieceDraw</span></code></pre>
<h3 id="class-drawablelabelled">Class DrawableLabelled</h3>
<p>Class <code>DrawableLabelled</code> is defined with instances <code>Tgraph</code> and <code>VPatch</code>, but <code>Patch</code> is not an instance (because this does not retain vertex label information).</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span style="color: blue; font-weight: bold;">class</span> <span>DrawableLabelled</span> <span>a</span> <span style="color: blue; font-weight: bold;">where</span>
        <span>labelColourSize</span> <span style="color: red;">::</span> <span>Colour</span> <span>Double</span> <span style="color: red;">-&gt;</span> <span>Measure</span> <span>Double</span> <span style="color: red;">-&gt;</span> <span style="color: red;">(</span><span>Patch</span> <span style="color: red;">-&gt;</span> <span>Diagram</span> <span>B</span><span style="color: red;">)</span> <span style="color: red;">-&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>Diagram</span> <span>B</span></code></pre>
<p>So <code>labelColourSize c m</code> modifies a <code>Patch</code> drawing function to add labels (of colour <code>c</code> and size measure <code>m</code>). <code>Measure</code> is defined in Diagrams.Prelude with pre-defined measures <code>tiny</code>, <code>verySmall</code>, <code>small</code>, <code>normal</code>, <code>large</code>, <code>veryLarge</code>, <code>huge</code>. For most of our diagrams of <code>Tgraph</code>s, we use red labels and we also find <code>small</code> is a good default size choice, so we define</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>labelSize</span> <span style="color: red;">::</span> <span>DrawableLabelled</span> <span>a</span> <span style="color: red;">=&gt;</span> <span>Measure</span> <span>Double</span> <span style="color: red;">-&gt;</span> <span style="color: red;">(</span><span>Patch</span> <span style="color: red;">-&gt;</span> <span>Diagram</span> <span>B</span><span style="color: red;">)</span> <span style="color: red;">-&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>Diagram</span> <span>B</span>
    <span>labelSize</span> <span style="color: red;">=</span> <span>labelColourSize</span> <span>red</span>

    <span>labelled</span> <span style="color: red;">::</span> <span>DrawableLabelled</span> <span>a</span> <span style="color: red;">=&gt;</span> <span style="color: red;">(</span><span>Patch</span> <span style="color: red;">-&gt;</span> <span>Diagram</span> <span>B</span><span style="color: red;">)</span> <span style="color: red;">-&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>Diagram</span> <span>B</span>
    <span>labelled</span> <span style="color: red;">=</span> <span>labelSize</span> <span>small</span></code></pre>
<p>and then <code>labelled draw</code>, <code>labelled drawj</code>, <code>labelled (fillDK clr1 clr2)</code> can all be used on both <code>Tgraph</code>s and <code>VPatch</code>es as well as (for example) <code>labelSize tiny draw</code>, or <code>labelCoulourSize blue normal drawj</code>.</p>
<h3 id="further-drawing-functions">Further drawing functions</h3>
<p>There are a few extra drawing functions built on top of the above ones. The function <code>smart</code> is a modifier to add dashed join edges only when they occur on the boundary of a <code>Tgraph</code></p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>smart</span> <span style="color: red;">::</span> <span>HasGraph</span> <span>a</span> <span style="color: red;">=&gt;</span> <span style="color: red;">(</span><span>VPatch</span> <span style="color: red;">-&gt;</span> <span>Diagram</span> <span>B</span><span style="color: red;">)</span> <span style="color: red;">-&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>Diagram</span> <span>B</span></code></pre>
<p>So <code>smart vpdraw g</code> will draw dashed join edges on the boundary of <code>g</code> before applying the drawing function <code>vpdraw</code> to the <code>VPatch</code> for <code>g</code>. For example the following all draw dashed join edges only on the boundary for a <code>Tgraph g</code></p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>smart</span> <span>draw</span> <span>g</span>
    <span>smart</span> <span style="color: red;">(</span><span>labelled</span> <span>draw</span><span style="color: red;">)</span> <span>g</span>
    <span>smart</span> <span style="color: red;">(</span><span>labelSize</span> <span>normal</span> <span>draw</span><span style="color: red;">)</span> <span>g</span></code></pre>
<p>When using labels, the function <code>rotating</code> allows a <code>Tgraph</code> to be drawn rotated without rotating the labels.</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>rotating</span> <span style="color: red;">::</span> <span>HasGraph</span> <span>a</span> <span style="color: red;">=&gt;</span> <span>Angle</span> <span>Double</span> <span style="color: red;">-&gt;</span> <span style="color: red;">(</span><span>VPatch</span> <span style="color: red;">-&gt;</span> <span>b</span><span style="color: red;">)</span> <span style="color: red;">-&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>b</span>
    <span>rotating</span> <span>angle</span> <span>vpdraw</span> <span style="color: red;">=</span> <span>vpdraw</span> <span>.</span> <span>rotate</span> <span>angle</span> <span>.</span> <span>makeVP</span></code></pre>
<p>So for example,</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>rotating</span> <span style="color: red;">(</span><span class="hs-num">90</span><span>@@</span><span>deg</span><span style="color: red;">)</span> <span style="color: red;">(</span><span>labelled</span> <span>draw</span><span style="color: red;">)</span> <span>g</span></code></pre>
<p>makes sense for a <code>Tgraph g</code>. Of course if there are no labels we can simply use</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>rotate</span> <span style="color: red;">(</span><span class="hs-num">90</span><span>@@</span><span>deg</span><span style="color: red;">)</span> <span style="color: red;">(</span><span>draw</span> <span>g</span><span style="color: red;">)</span></code></pre>
<p>Similarly <code>aligning</code> allows a <code>Tgraph</code> to be aligned on the X-axis using a pair of vertex numbers before drawing.</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>aligning</span> <span style="color: red;">::</span> <span>HasGraph</span> <span>a</span> <span style="color: red;">=&gt;</span> <span style="color: red;">(</span><span>Vertex</span><span style="color: red;">,</span><span>Vertex</span><span style="color: red;">)</span> <span style="color: red;">-&gt;</span> <span style="color: red;">(</span><span>VPatch</span> <span style="color: red;">-&gt;</span> <span>b</span><span style="color: red;">)</span> <span style="color: red;">-&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>b</span>
    <span>aligning</span> <span style="color: red;">(</span><span>a</span><span style="color: red;">,</span><span>b</span><span style="color: red;">)</span> <span>vpdraw</span> <span style="color: red;">=</span> <span>vpdraw</span> <span>.</span> <span>alignXaxis</span> <span style="color: red;">(</span><span>a</span><span style="color: red;">,</span><span>b</span><span style="color: red;">)</span> <span>.</span> <span>makeVP</span></code></pre>
<p>So, for example, if <code>Tgraph g</code> has vertices <code>a</code> and <code>b</code>, both</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>aligning</span> <span style="color: red;">(</span><span>a</span><span style="color: red;">,</span><span>b</span><span style="color: red;">)</span> <span>draw</span> <span>g</span>
    <span>aligning</span> <span style="color: red;">(</span><span>a</span><span style="color: red;">,</span><span>b</span><span style="color: red;">)</span> <span style="color: red;">(</span><span>labelled</span> <span>draw</span><span style="color: red;">)</span> <span>g</span></code></pre>
<p>make sense. Note that the following two examples are <strong>wrong</strong>. Even though they type check, they re-orient <code>g</code> without repositioning the boundary joins.</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>smart</span> <span style="color: red;">(</span><span>labelled</span> <span>draw</span> <span>.</span> <span>rotate</span> <span>angle</span><span style="color: red;">)</span> <span>g</span>      <span style="color: green;">-- WRONG</span>
    <span>smart</span> <span style="color: red;">(</span><span>labelled</span> <span>draw</span> <span>.</span> <span>alignXaxis</span> <span style="color: red;">(</span><span>a</span><span style="color: red;">,</span><span>b</span><span style="color: red;">)</span><span style="color: red;">)</span> <span>g</span>  <span style="color: green;">-- WRONG</span></code></pre>
<p>Instead use</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>smartRotating</span> <span>angle</span> <span style="color: red;">(</span><span>labelled</span> <span>draw</span><span style="color: red;">)</span> <span>g</span>
    <span>smartAligning</span> <span style="color: red;">(</span><span>a</span><span style="color: red;">,</span><span>b</span><span style="color: red;">)</span> <span style="color: red;">(</span><span>labelled</span> <span>draw</span><span style="color: red;">)</span> <span>g</span></code></pre>
<p>where</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>smartRotating</span> <span style="color: red;">::</span> <span>HasGraph</span> <span>a</span> <span style="color: red;">=&gt;</span>  <span>Angle</span> <span>Double</span> <span style="color: red;">-&gt;</span> <span style="color: red;">(</span><span>VPatch</span> <span style="color: red;">-&gt;</span> <span>Diagram</span> <span>B</span><span style="color: red;">)</span> <span style="color: red;">-&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>Diagram</span> <span>B</span>
    <span>smartAligning</span>  <span style="color: red;">::</span> <span>HasGraph</span> <span>a</span> <span style="color: red;">=&gt;</span> <span style="color: red;">(</span><span>Vertex</span><span style="color: red;">,</span><span>Vertex</span><span style="color: red;">)</span> <span style="color: red;">-&gt;</span> <span style="color: red;">(</span><span>VPatch</span> <span style="color: red;">-&gt;</span> <span>Diagram</span> <span>B</span><span style="color: red;">)</span> <span style="color: red;">-&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>Diagram</span> <span>B</span></code></pre>
<p>are defined using</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>smartOn</span> <span style="color: red;">::</span> <span>HasGraph</span> <span>a</span> <span style="color: red;">=&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span style="color: red;">(</span><span>VPatch</span> <span style="color: red;">-&gt;</span> <span>Diagram</span> <span>B</span><span style="color: red;">)</span> <span style="color: red;">-&gt;</span> <span>VPatch</span> <span style="color: red;">-&gt;</span> <span>Diagram</span> <span>B</span></code></pre>
<p>Here, <code>smartOn g vpdraw vp</code> uses the given <code>vp</code> for drawing boundary joins and drawing faces of <code>g</code> (with <code>vpdraw</code>) rather than converting <code>g</code> to a new <code>VPatch</code>. This assumes <code>vp</code> has locations for vertices in <code>g</code>.</p>
<h3 id="overlaid-examples-location-map-sharing">Overlaid examples (location map sharing)</h3>
<p>The function</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>drawForce</span> <span style="color: red;">::</span> <span>Tgraph</span> <span style="color: red;">-&gt;</span> <span>Diagram</span> <span>B</span></code></pre>
<p>will (smart) draw a <code>Tgraph g</code> in red overlaid (using <code>&lt;&gt;</code>) on the result of <code>force g</code> as in figure 6. Similarly</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>drawPCompose</span>  <span style="color: red;">::</span> <span>Tgraph</span> <span style="color: red;">-&gt;</span> <span>Diagram</span> <span>B</span></code></pre>
<p>applied to a <code>Tgraph g</code> will draw the result of a partial composition of <code>g</code> as in figure 7. That is a drawing of <code>compose g</code> but overlaid with a drawing of the remainder faces of <code>g</code> shown in pale green.</p>
<p>Both these functions make use of sharing a vertex location map to get correct alignments of overlaid diagrams. In the case of <code>drawForce g</code>, we know that a <code>VPatch</code> for <code>force g</code> will contain all the vertex locations for <code>g</code> since force only adds to a <code>Tgraph</code> (when it succeeds). So when constructing the diagram for <code>g</code> we can use the <code>VPatch</code> created for <code>force g</code> instead of starting afresh. Similarly for <code>drawPCompose g</code> the <code>VPatch</code> for <code>g</code> contains locations for all the vertices of <code>compose g</code> so <code>compose g</code> is drawn using the <code>VPatch</code> for <code>g</code> instead of starting afresh.</p>
<p>The location map sharing is done with</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>subFaces</span> <span style="color: red;">::</span> <span>HasFaces</span> <span>a</span> <span style="color: red;">=&gt;</span> 
                <span>a</span> <span style="color: red;">-&gt;</span> <span>VPatch</span> <span style="color: red;">-&gt;</span> <span>VPatch</span></code></pre>
<p>so that <code>subFaces fcs vp</code> is a <code>VPatch</code> with the same vertex locations as <code>vp</code>, but replacing the faces of <code>vp</code> with <code>fcs</code>. [Of course, this can go wrong if the new faces have vertices not in the domain of the vertex location map so this needs to be used with care. Any errors would only be discovered when a diagram is created.]</p>
<p>For cases where labels are only going to be drawn for certain faces, we need a version of <code>subFaces</code> which also gets rid of vertex locations that are not relevant to the faces. For this situation we have</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>restrictTo</span><span style="color: red;">::</span> <span>HasFaces</span> <span>a</span> <span style="color: red;">=&gt;</span> 
                 <span>a</span> <span style="color: red;">-&gt;</span> <span>VPatch</span> <span style="color: red;">-&gt;</span> <span>VPatch</span></code></pre>
<p>which filters out un-needed vertex locations from the vertex location map. Unlike <code>subFaces</code>, <code>restrictTo</code> checks for missing vertex locations, so <code>restrictTo fcs vp</code> raises an error if a vertex in <code>fcs</code> is missing from the keys of the vertex location map of <code>vp</code>.</p>
<p><a name="5"> </a></p>
<h2 id="forcing-in-more-detail">5. Forcing in More Detail</h2>
<h3 id="the-force-rules">The force rules</h3>
<p>The rules used by our force algorithm are local and derived from the fact that there are seven possible vertex types as depicted in figure 8.</p>
<figure>
<img alt="Figure 8: Seven vertex types" src="https://readerunner.wordpress.com/wp-content/uploads/2024/04/verttypesfig.png?w=625"/><figcaption>Figure 8: Seven vertex types</figcaption></figure>
<p>Our rules are shown in figure 9 (omitting mirror symmetric versions). In each case the <code>TileFace</code> shown yellow needs to be added in the presence of the other <code>TileFace</code>s shown.</p>
<figure>
<img alt="Figure 9: Rules for forcing" src="https://readerunner.wordpress.com/wp-content/uploads/2024/04/forcerules.png?w=625"/><figcaption>Figure 9: Rules for forcing</figcaption></figure>
<h3 id="main-forcing-operations">Main Forcing Operations</h3>
<p>To make forcing efficient we convert a <code>Tgraph</code> to a <code>BoundaryState</code> to keep track of boundary information of the <code>Tgraph</code>, and then calculate a <code>ForceState</code> which combines the <code>BoundaryState</code> with a record of awaiting boundary edge updates (an update map), and an UpdateGenerator. Then each face addition is carried out on a <code>ForceState</code>, converting back when all the face additions are complete. It makes sense to apply <code>force</code> (and related functions) to a <code>Tgraph</code>, a <code>BoundaryState</code>, or a <code>ForceState</code>, so we define a class <code>Forcible</code> with instances <code>Tgraph</code>, <code>BoundaryState</code>, and <code>ForceState</code>.</p>
<p>This allows us to define</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>force</span> <span style="color: red;">::</span> <span>Forcible</span> <span>a</span> <span style="color: red;">=&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>a</span>
    <span>tryForce</span> <span style="color: red;">::</span> <span>Forcible</span> <span>a</span> <span style="color: red;">=&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>Try</span> <span>a</span></code></pre>
<p>The first will raise an error if a stuck tiling is encountered. The second uses a <code>Try</code> result which produces a <code>Left string</code> for failures and a <code>Right a</code> for successful result <code>a</code>.</p>
<p>There are several other operations related to forcing including</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>stepForce</span> <span style="color: red;">::</span> <span>Forcible</span> <span>a</span> <span style="color: red;">=&gt;</span> <span>Int</span> <span style="color: red;">-&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>a</span>
    <span>tryStepForce</span>  <span style="color: red;">::</span> <span>Forcible</span> <span>a</span> <span style="color: red;">=&gt;</span> <span>Int</span> <span style="color: red;">-&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>Try</span> <span>a</span>

    <span>addHalfDart</span><span style="color: red;">,</span> <span>addHalfKite</span> <span style="color: red;">::</span> <span>Forcible</span> <span>a</span> <span style="color: red;">=&gt;</span> <span>Dedge</span> <span style="color: red;">-&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>a</span>
    <span>tryAddHalfDart</span><span style="color: red;">,</span> <span>tryAddHalfKite</span> <span style="color: red;">::</span> <span>Forcible</span> <span>a</span> <span style="color: red;">=&gt;</span> <span>Dedge</span> <span style="color: red;">-&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>Try</span> <span>a</span></code></pre>
<p>The first two force (up to) a given number of steps (=face additions) and the other four add a half dart/kite on a given boundary edge.</p>
<h3 id="update-generators">Update Generators</h3>
<p>An update generator is used to calculate which boundary edges can have a certain update. There is an update generator for each force rule, but also a combined (all update) generator. The force operations mentioned above all use the default all update generator (<code>defaultAllUGen</code>) but there are more general (<em>with</em>) versions that can be passed an update generator of choice. For example</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>forceWith</span> <span style="color: red;">::</span> <span>Forcible</span> <span>a</span> <span style="color: red;">=&gt;</span> <span>UpdateGenerator</span> <span style="color: red;">-&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>a</span>
    <span>tryForceWith</span> <span style="color: red;">::</span> <span>Forcible</span> <span>a</span> <span style="color: red;">=&gt;</span> <span>UpdateGenerator</span> <span style="color: red;">-&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>Try</span> <span>a</span></code></pre>
<p>We can also define</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>wholeTiles</span> <span style="color: red;">::</span> <span>Forcible</span> <span>a</span> <span style="color: red;">=&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>a</span>
    <span>wholeTiles</span> <span style="color: red;">=</span> <span>forceWith</span> <span>wholeTileUpdates</span></code></pre>
<p>where <code>wholeTileUpdates</code> is an update generator that just finds boundary join edges to complete whole tiles.</p>
<p>In fact <code>UpdateGenerator</code>s are functions that take a <code>BoundaryState</code> and a focus (list of boundary directed edges) to produce an update map. Each <code>Update</code> is calculated as either a <code>SafeUpdate</code> (where two of the new face edges are on the existing boundary and no new vertex is needed) or an <code>UnsafeUpdate</code> (where only one edge of the new face is on the boundary and a new vertex needs to be created for a new face).</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span style="color: blue; font-weight: bold;">type</span> <span>UpdateGenerator</span> <span style="color: red;">=</span> <span>BoundaryState</span> <span style="color: red;">-&gt;</span> <span style="color: red;">[</span><span>Dedge</span><span style="color: red;">]</span> <span style="color: red;">-&gt;</span> <span>Try</span> <span>UpdateMap</span>
    <span style="color: blue; font-weight: bold;">type</span> <span>UpdateMap</span> <span style="color: red;">=</span> <span>Map.Map</span> <span>Dedge</span> <span>Update</span>
    <span style="color: blue; font-weight: bold;">data</span> <span>Update</span> <span style="color: red;">=</span> <span>SafeUpdate</span> <span>TileFace</span> 
                <span style="color: red;">|</span> <span>UnsafeUpdate</span> <span style="color: red;">(</span><span>Vertex</span> <span style="color: red;">-&gt;</span> <span>TileFace</span><span style="color: red;">)</span></code></pre>
<p>Completing (executing) an <code>UnsafeUpdate</code> requires a touching vertex check to ensure that the new vertex does not clash with an existing boundary vertex. Using an existing (touching) vertex would create a crossing boundary so such an update has to be blocked.</p>
<h3 id="forcible-class-operations">Forcible Class Operations</h3>
<p>The <code>Forcible</code> class operations are higher order and designed to allow for easy additions of further generic operations. They take care of conversions between <code>Tgraph</code>s, <code>BoundaryState</code>s and <code>ForceState</code>s. The first two are designed to create functions that return the same Forcible type as the input.</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span style="color: blue; font-weight: bold;">class</span> <span>Forcible</span> <span>a</span> <span style="color: blue; font-weight: bold;">where</span>
      <span>tryFSOp</span> <span style="color: red;">::</span> <span style="color: red;">(</span><span>ForceState</span> <span style="color: red;">-&gt;</span> <span>Try</span> <span>ForceState</span><span style="color: red;">)</span> <span style="color: red;">-&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>Try</span> <span>a</span>
      <span>tryChangeBoundary</span> <span style="color: red;">::</span> <span style="color: red;">(</span><span>BoundaryState</span> <span style="color: red;">-&gt;</span> <span>Try</span> <span>BoundaryChange</span><span style="color: red;">)</span> <span style="color: red;">-&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>Try</span> <span>a</span>
      <span>tryInitFS</span> <span style="color: red;">::</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>Try</span> <span>ForceState</span></code></pre>
<p>For example, given any <code>f:: ForceState -&gt; Try ForceState</code> , then <code>f</code> can be generalised to work on any <code>Forcible</code> using <code>tryFSOp f</code>. This is used to define both <code>tryForce</code> and <code>tryStepForce</code>.</p>
<p>Similarly given any <code>f:: BoundaryState -&gt; Try BoundaryChange</code> , then <code>f</code> can be generalised to work on any <code>Forcible</code> using <code>tryChangeBoundary f</code>. This is used to define <code>tryAddHalfDart</code> and <code>tryAddHalfKite</code>.</p>
<p>Note that the type <code>BoundaryChange</code> contains a resulting <code>BoundaryState</code>, the single <code>TileFace</code> that has been added, a list of edges removed from the boundary (of the <code>BoundaryState</code> prior to the face addition), and a list of the (3 or 4) boundary edges affected around the change that require checking or re-checking for updates.</p>
<p>The class function <code>tryInitFS</code> will create an initial <code>ForceState</code> for any <code>Forcible</code>. If the <code>Forcible</code> is already a <code>ForceState</code> it will do nothing. Otherwise it will calculate updates for the whole boundary using <code>defaultAllUGen</code>.</p>
<p>The update generator is assumed to be <code>defaultAllUGen</code> but this can be changed using</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>tryFSOpWith</span> <span style="color: red;">::</span> <span>Forcible</span> <span>a</span> <span style="color: red;">=&gt;</span> <span>UpdateGenerator</span> <span style="color: red;">-&gt;</span> <span style="color: red;">(</span><span>ForceState</span> <span style="color: red;">-&gt;</span> <span>Try</span> <span>ForceState</span><span style="color: red;">)</span> <span style="color: red;">-&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>Try</span> <span>a</span></code></pre>
<p>so, for example, we defined</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>tryForceWith</span> <span>ugen</span> <span style="color: red;">=</span> <span>tryFSOpWith</span> <span>ugen</span> <span>tryForce</span></code></pre>
<h3 id="efficient-chains-of-forcing-operations.">Efficient chains of forcing operations.</h3>
<p>Note that <code>(force . force)</code> does the same as <code>force</code>, but we might want to chain other <code>force</code> related steps in a calculation.</p>
<p>For example, consider the following combination which, after decomposing a <code>Tgraph</code>, forces, then adds a half dart on a given boundary edge (<code>d</code>) and then forces again.</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>combo</span> <span style="color: red;">::</span> <span>Dedge</span> <span style="color: red;">-&gt;</span> <span>Tgraph</span> <span style="color: red;">-&gt;</span> <span>Tgraph</span>
    <span>combo</span> <span>d</span> <span style="color: red;">=</span> <span>force</span> <span>.</span> <span>addHalfDart</span> <span>d</span> <span>.</span> <span>force</span> <span>.</span> <span>decompose</span></code></pre>
<p>Since <code>decompose</code> produces a <code>Tgraph</code>, the instances of <code>force</code> and <code>addHalfDart d</code> will have type <code>Tgraph -&gt; Tgraph</code> so each of these operations, will begin and end with conversions between <code>Tgraph</code> and <code>ForceState</code>. We would do better to avoid these wasted intermediate conversions working only with <code>ForceState</code>s and keeping only those necessary conversions at the beginning and end of the whole sequence.</p>
<p>This can be done using <code>tryFSOp</code>. To see this, let us first re-express the forcing sequence using the <code>Try</code> monad, so</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>force</span> <span>.</span> <span>addHalfDart</span> <span>d</span> <span>.</span> <span>force</span></code></pre>
<p>becomes</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>tryForce</span> <span>&lt;=&lt;</span> <span>tryAddHalfDart</span> <span>d</span> <span>&lt;=&lt;</span> <span>tryForce</span></code></pre>
<p>Note that (<code>&lt;=&lt;</code>) is the Kliesli arrow which replaces composition for Monads (defined in Control.Monad). (We could also have expressed this right to left sequence with a left to right version <code>tryForce &gt;=&gt; tryAddHalfDart d &gt;=&gt; tryForce</code>). The definition of <code>combo</code> becomes</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>combo</span> <span style="color: red;">::</span> <span>Dedge</span> <span style="color: red;">-&gt;</span> <span>Tgraph</span> <span style="color: red;">-&gt;</span> <span>Tgraph</span>
    <span>combo</span> <span>d</span> <span style="color: red;">=</span> <span>runTry</span> <span>.</span> <span style="color: red;">(</span><span>tryForce</span> <span>&lt;=&lt;</span> <span>tryAddHalfDart</span> <span>d</span> <span>&lt;=&lt;</span> <span>tryForce</span><span style="color: red;">)</span> <span>.</span> <span>decompose</span></code></pre>
<p>This has no performance improvement, but now we can pass the sequence to <code>tryFSOp</code> to remove the unnecessary conversions between steps.</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>combo</span> <span style="color: red;">::</span> <span>Dedge</span> <span style="color: red;">-&gt;</span> <span>Tgraph</span> <span style="color: red;">-&gt;</span> <span>Tgraph</span>
    <span>combo</span> <span>d</span> <span style="color: red;">=</span> <span>runTry</span> <span>.</span> <span>tryFSOp</span> <span style="color: red;">(</span><span>tryForce</span> <span>&lt;=&lt;</span> <span>tryAddHalfDart</span> <span>d</span> <span>&lt;=&lt;</span> <span>tryForce</span><span style="color: red;">)</span> <span>.</span> <span>decompose</span></code></pre>
<p>The sequence actually has type <code>Forcible a =&gt; a -&gt; Try a</code> but when passed to <code>tryFSOp</code> it specialises to type <code>ForceState -&gt; Try ForseState</code>. This ensures the sequence works on a <code>ForceState</code> and any conversions are confined to the beginning and end of the sequence, avoiding unnecessary intermediate conversions.</p>
<h3 id="a-limitation-of-forcing">A limitation of forcing</h3>
<p>To avoid creating touching vertices (or crossing boundaries) a <code>BoundaryState</code> keeps track of locations of boundary vertices. At around 35,000 face additions in a single <code>force</code> operation the calculated positions of boundary vertices can become too inaccurate to prevent touching vertex problems. In such cases it is better to use</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>recalibratingForce</span> <span style="color: red;">::</span> <span>Forcible</span> <span>a</span> <span style="color: red;">=&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>a</span>
    <span>tryRecalibratingForce</span> <span style="color: red;">::</span> <span>Forcible</span> <span>a</span> <span style="color: red;">=&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>Try</span> <span>a</span></code></pre>
<p>These work by recalculating all vertex positions at 20,000 step intervals to get more accurate boundary vertex positions. For example, 6 decompositions of the <code>kingGraph</code> has 2,906 faces. Applying <code>force</code> to this should result in 53,574 faces but will go wrong before it reaches that. This can be fixed by calculating either</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>recalibratingForce</span> <span style="color: red;">(</span><span>decompositions</span> <span>kingGraph</span> <span>!!</span><span class="hs-num">6</span><span style="color: red;">)</span></code></pre>
<p>or using an extra <code>force</code> before the decompositions</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>force</span> <span style="color: red;">(</span><span>decompositions</span> <span style="color: red;">(</span><span>force</span> <span>kingGraph</span><span style="color: red;">)</span> <span>!!</span><span class="hs-num">6</span><span style="color: red;">)</span></code></pre>
<p>In the latter case, the final <code>force</code> only needs to add 17,864 faces to the 35,710 produced by <code>decompositions (force kingGraph) !!6</code>.</p>
<p><a name="6"> </a></p>
<h2 id="advanced-operations">6. Advanced Operations</h2>
<h3 id="guided-comparison-of-tgraphs">Guided comparison of <code>Tgraph</code>s</h3>
<p>Asking if two <code>Tgraph</code>s are equivalent (the same apart from choice of vertex numbers) is a an np-complete problem. However, we do have an efficient <em>guided</em> way of comparing <code>Tgraph</code>s. In the module <code>Tgraph.Rellabelling</code> we have</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>sameGraph</span> <span style="color: red;">::</span> <span style="color: red;">(</span><span>Tgraph</span><span style="color: red;">,</span><span>Dedge</span><span style="color: red;">)</span> <span style="color: red;">-&gt;</span> <span style="color: red;">(</span><span>Tgraph</span><span style="color: red;">,</span><span>Dedge</span><span style="color: red;">)</span> <span style="color: red;">-&gt;</span> <span>Bool</span></code></pre>
<p>The expression <code>sameGraph (g1,d1) (g2,d2)</code> asks if <code>g2</code> can be relabelled to match <code>g1</code> assuming that the directed edge <code>d2</code> in <code>g2</code> is identified with <code>d1</code> in <code>g1</code>. Hence the comparison is guided by the assumption that <code>d2</code> corresponds to <code>d1</code>.</p>
<p>It is implemented using</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>tryRelabelToMatch</span> <span style="color: red;">::</span> <span style="color: red;">(</span><span>Tgraph</span><span style="color: red;">,</span><span>Dedge</span><span style="color: red;">)</span> <span style="color: red;">-&gt;</span> <span style="color: red;">(</span><span>Tgraph</span><span style="color: red;">,</span><span>Dedge</span><span style="color: red;">)</span> <span style="color: red;">-&gt;</span> <span>Try</span> <span>Tgraph</span></code></pre>
<p>where <code>tryRelabelToMatch (g1,d1) (g2,d2)</code> will either fail with a <code>Left report</code> if a mismatch is found when relabelling <code>g2</code> to match <code>g1</code> or will succeed with <code>Right g3</code> where <code>g3</code> is a relabelled version of <code>g2</code>. The successful result <code>g3</code> will match <code>g1</code> in a maximal tile-connected collection of faces containing the face with edge <code>d1</code> and have vertices disjoint from those of <code>g1</code> elsewhere. The comparison tries to grow a suitable relabelling by comparing faces one at a time starting from the face with edge <code>d1</code> in <code>g1</code> and the face with edge <code>d2</code> in <code>g2</code>. (This relies on the fact that <code>Tgraph</code>s are connected with no crossing boundaries, and hence tile-connected.)</p>
<p>The above function is also used to implement</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>tryFullUnion</span><span style="color: red;">::</span> <span style="color: red;">(</span><span>Tgraph</span><span style="color: red;">,</span><span>Dedge</span><span style="color: red;">)</span> <span style="color: red;">-&gt;</span> <span style="color: red;">(</span><span>Tgraph</span><span style="color: red;">,</span><span>Dedge</span><span style="color: red;">)</span> <span style="color: red;">-&gt;</span> <span>Try</span> <span>Tgraph</span></code></pre>
<p>which tries to find the union of two <code>Tgraph</code>s guided by a directed edge identification. However, there is an extra complexity arising from the fact that <code>Tgraph</code>s might <em>overlap</em> in more than one tile-connected region. After calculating one overlapping region, the full union uses some geometry (calculating vertex locations) to detect further overlaps.</p>
<p>Finally we have</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>commonFaces</span><span style="color: red;">::</span> <span style="color: red;">(</span><span>Tgraph</span><span style="color: red;">,</span><span>Dedge</span><span style="color: red;">)</span> <span style="color: red;">-&gt;</span> <span style="color: red;">(</span><span>Tgraph</span><span style="color: red;">,</span><span>Dedge</span><span style="color: red;">)</span> <span style="color: red;">-&gt;</span> <span style="color: red;">[</span><span>TileFace</span><span style="color: red;">]</span></code></pre>
<p>which will find common regions of overlapping faces of two <code>Tgraph</code>s guided by a directed edge identification. The resulting common faces will be a sub-collection of faces from the first <code>Tgraph</code>. These are returned as a list as they may not be a connected collection of faces and therefore not necessarily a <code>Tgraph</code>.</p>
<h3 id="empires-and-superforce">Empires and SuperForce</h3>
<p>In <a href="https://readerunner.wordpress.com/2023/04/26/graphs-kites-and-darts-empires-and-superforce/">Empires and SuperForce</a> we discussed forced boundary coverings which were used to implement both a <code>superForce</code> operation</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>superForce</span><span style="color: red;">::</span> <span>Forcible</span> <span>a</span> <span style="color: red;">=&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>Forced</span> <span>a</span></code></pre>
<p>and operations to calculate empires.</p>
<p>We will not repeat the descriptions here other than to note that</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>forcedBoundaryECovering</span><span style="color: red;">::</span> <span>Tgraph</span> <span style="color: red;">-&gt;</span> <span style="color: red;">[</span><span>Forced</span> <span>Tgraph</span><span style="color: red;">]</span></code></pre>
<p>finds boundary edge coverings after forcing a <code>Tgraph</code>. That is, <code>forcedBoundaryECovering g</code> will first force <code>g</code>, then (if it succeeds) finds a collection of (forced) extensions to <code>force g</code> such that</p>
<ul>
<li>each extension has the whole boundary of <code>force g</code> as internal edges.</li>
<li>each possible addition to a boundary edge of <code>force g</code> (kite or dart) has been included in the collection.</li>
</ul>
<p>(<em>possible</em> here means – not leading to a stuck <code>Tgraph</code> when forced.) There is also</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>forcedBoundaryVCovering</span><span style="color: red;">::</span> <span>Tgraph</span> <span style="color: red;">-&gt;</span> <span style="color: red;">[</span><span>Forced</span> <span>Tgraph</span><span style="color: red;">]</span></code></pre>
<p>which does the same except that the extensions have all boundary vertices internal rather than just the boundary edges. In both cases the result is a list of explicitly forced Tgraphs (discussed next).</p>
<h3 id="combinations-and-explicitly-forced">Combinations and Explicitly Forced</h3>
<p>We introduced a new type <code>Forced</code> (in v 1.3) to enable a forcible to be explictily labelled as being forced. For example</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>forceF</span>    <span style="color: red;">::</span> <span>Forcible</span> <span>a</span> <span style="color: red;">=&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>Forced</span> <span>a</span> 
    <span>tryForceF</span> <span style="color: red;">::</span> <span>Forcible</span> <span>a</span> <span style="color: red;">=&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>Try</span> <span style="color: red;">(</span><span>Forced</span> <span>a</span><span style="color: red;">)</span>
    <span>forgetF</span>   <span style="color: red;">::</span> <span>Forced</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>a</span></code></pre>
<p>This allows us to restrict certain functions which expect a forced argument by making this explicit.</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>composeF</span> <span style="color: red;">::</span> <span>HasGraph</span> <span>a</span> <span style="color: red;">=&gt;</span> <span>Forced</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>Forced</span> <span>Tgraph</span></code></pre>
<p>The definition makes use of theorems established in <a href="https://readerunner.wordpress.com/2023/09/12/graphs-kites-and-darts-and-theorems/">Graphs,Kites and Darts and Theorems</a> that composing a forced <code>Tgraph</code> does not require a check (for connectedness and no crossing boundaries) and the result is also forced. This can then be used to define efficient combinations such as</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>compForce</span><span style="color: red;">::</span> <span style="color: red;">(</span><span>Forcible</span> <span>a</span><span style="color: red;">,</span> <span>HasGraph</span> <span>a</span><span style="color: red;">)</span> <span style="color: red;">=&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>Forced</span> <span>Tgraph</span>      <span style="color: green;">-- compose after forcing</span>
    <span>compForce</span> <span style="color: red;">=</span> <span>composeF</span> <span>.</span> <span>forceF</span>

    <span>allCompForce</span><span style="color: red;">::</span> <span style="color: red;">(</span><span>Forcible</span> <span>a</span><span style="color: red;">,</span> <span>HasGraph</span> <span>a</span><span style="color: red;">)</span> <span style="color: red;">=&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span style="color: red;">[</span><span>Forced</span> <span>Tgraph</span><span style="color: red;">]</span> <span style="color: green;">-- iterated (compose after force) while not emptyTgraph</span>
    <span>maxCompForce</span><span style="color: red;">::</span> <span style="color: red;">(</span><span>Forcible</span> <span>a</span><span style="color: red;">,</span> <span>HasGraph</span> <span>a</span><span style="color: red;">)</span> <span style="color: red;">=&gt;</span> <span>a</span> <span style="color: red;">-&gt;</span> <span>Forced</span> <span>Tgraph</span>   <span style="color: green;">-- last item in allCompForce (or emptyTgraph)</span></code></pre>
<p>Note that <code>BoundaryState</code>, <code>ForceState</code> as well as <code>Tgraph</code> and <code>Forced</code> versions of these are all instances of class <code>HasGraph</code>.</p>
<h3 id="tracked-tgraphs">Tracked Tgraphs</h3>
<p>The type</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span style="color: blue; font-weight: bold;">data</span> <span>TrackedTgraph</span> <span style="color: red;">=</span> <span>TrackedTgraph</span>
       <span style="color: red;">{</span> <span>tgraph</span>  <span style="color: red;">::</span> <span>Tgraph</span>
       <span style="color: red;">,</span> <span>tracked</span> <span style="color: red;">::</span> <span style="color: red;">[</span><span style="color: red;">[</span><span>TileFace</span><span style="color: red;">]</span><span style="color: red;">]</span> 
       <span style="color: red;">}</span> <span style="color: blue; font-weight: bold;">deriving</span> <span>Show</span></code></pre>
<p>has proven useful in experimentation as well as in producing artwork with darts and kites. The idea is to keep a record of sub-collections of faces of a <code>Tgraph</code> when doing both force operations and decompositions. A list of the sub-collections forms the tracked list associated with the <code>Tgraph</code>. We make <code>TrackedTgraph</code> an instance of class <code>Forcible</code> by having force operations only affect the <code>Tgraph</code> and not the tracked list. The significant idea is the implementation of</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>decomposeTracked</span> <span style="color: red;">::</span> <span>TrackedTgraph</span> <span style="color: red;">-&gt;</span> <span>TrackedTgraph</span></code></pre>
<p>Decomposition of a <code>Tgraph</code> involves introducing a new vertex for each long edge and each kite join. These are then used to construct the decomposed faces. For <code>decomposeTracked</code> we do the same for the <code>Tgraph</code>, but when it comes to the tracked collections, we decompose them re-using the same new vertex numbers calculated for the edges in the <code>Tgraph</code>. This keeps a consistent numbering between the <code>Tgraph</code> and tracked faces, so each item in the tracked list remains a sub-collection of faces in the <code>Tgraph</code>.</p>
<p>The function</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>drawTrackedTgraph</span> <span style="color: red;">::</span> <span style="color: red;">[</span><span>VPatch</span> <span style="color: red;">-&gt;</span> <span>Diagram</span> <span>B</span><span style="color: red;">]</span> <span style="color: red;">-&gt;</span> <span>TrackedTgraph</span> <span style="color: red;">-&gt;</span> <span>Diagram</span> <span>B</span></code></pre>
<p>is used to draw a <code>TrackedTgraph</code>. It uses a list of functions to draw <code>VPatch</code>es. The first drawing function is applied to a <code>VPatch</code> for any untracked faces. Subsequent functions are applied to <code>VPatch</code>es for the tracked list in order. Each diagram is beneath later ones in the list, with the diagram for the untracked faces at the bottom. The <code>VPatch</code>es used are all restrictions of a single <code>VPatch</code> for the <code>Tgraph</code>, so will be consistent in vertex locations. When labels are used, there is also a <code>drawTrackedTgraphRotating</code> and <code>drawTrackedTgraphAligning</code> for rotating or aligning the <code>VPatch</code> prior to applying the drawing functions.</p>
<p>Note that the result of calculating empires (see <a href="https://readerunner.wordpress.com/2023/04/26/graphs-kites-and-darts-empires-and-superforce/">Empires and SuperForce</a> ) is represented as a <code>TrackedTgraph</code>. The result is actually the common faces of a forced boundary covering, but a particular element of the covering (the first one) is chosen as the background <code>Tgraph</code> with the common faces as a tracked sub-collection of faces. Hence we have</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell">    <span>empire1</span><span style="color: red;">,</span> <span>empire2</span> <span style="color: red;">::</span> <span>Tgraph</span> <span style="color: red;">-&gt;</span> <span>TrackedTgraph</span>
    
    <span>drawEmpire</span> <span style="color: red;">::</span> <span>TrackedTgraph</span> <span style="color: red;">-&gt;</span> <span>Diagram</span> <span>B</span></code></pre>
<p>Figure 10 was also created using <code>TrackedTgraph</code>s.</p>
<figure>
<img alt="Figure 10: Using a TrackedTgraph for drawing" src="https://readerunner.wordpress.com/wp-content/uploads/2024/04/cover.png?w=625"/><figcaption>Figure 10: Using a TrackedTgraph for drawing</figcaption></figure>
<p><a name="7"> </a></p>
<h2 id="other-reading">7. Other Reading</h2>
<p>Previous related blogs are:</p>
<ul>
<li><a href="https://readerunner.wordpress.com/2021/03/20/diagrams-for-penrose-tiles/">Diagrams for Penrose Tiles</a> – the first blog introduced drawing <code>Piece</code>s and <code>Patch</code>es (without using Tgraphs) and provided a version of decomposing for Patches (<code>decompPatch</code>).</li>
<li><a href="https://readerunner.wordpress.com/2022/01/06/graphs-kites-and-darts/">Graphs, Kites and Darts</a> intoduced Tgraphs. This gave more details of implementation and results of early explorations. (The class <code>Forcible</code> was introduced subsequently).</li>
<li><a href="https://readerunner.wordpress.com/2023/04/26/graphs-kites-and-darts-empires-and-superforce/">Empires and SuperForce</a> – these new operations were based on observing properties of boundaries of forced Tgraphs.</li>
<li><a href="https://readerunner.wordpress.com/2023/09/12/graphs-kites-and-darts-and-theorems/">Graphs,Kites and Darts and Theorems</a> established some important results relating <code>force</code>, <code>compose</code>, <code>decompose</code>.</li>
</ul></div>
    </content>
    <updated>2026-04-26T16:11:03Z</updated>
    <published>2024-04-08T15:11:17Z</published>
    <category scheme="https://readerunner.wordpress.com" term="Haskell"/>
    <category scheme="https://readerunner.wordpress.com" term="Maths"/>
    <author>
      <name>readerunner</name>
      <uri>https://readerunner.wordpress.com</uri>
    </author>
    <source>
      <id>http://readerunner.wordpress.com/feed/atom/</id>
      <link href="https://readerunner.wordpress.com" rel="alternate" type="text/html"/>
      <link href="https://readerunner.wordpress.com/feed/atom/" rel="self" type="application/atom+xml"/>
      <link href="https://readerunner.wordpress.com/osd.xml" rel="search" title="readerunner" type="application/opensearchdescription+xml"/>
      <link href="https://s1.wp.com/opensearch.xml" rel="search" title="WordPress.com" type="application/opensearchdescription+xml"/>
      <link href="https://readerunner.wordpress.com/?pushpress=hub" rel="hub" type="text/html"/>
      <subtitle xml:lang="en">maths and computing experiments</subtitle>
      <title xml:lang="en">readerunner</title>
      <updated>2026-04-26T16:11:03Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-11295132.post-4271990394665143853</id>
    <link href="http://blog.sigfpe.com/2023/03/constructing-clifford-algebras-using.html" rel="alternate" type="text/html"/>
    <title>Constructing Clifford Algebras using the Super Tensor Product</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><div style="border: 1px solid #ccc; padding: 10px; background-color: #f9e9e9; margin: 10px 0;">
Google have stopped supporting the Chart API so all of the mathematics notation below is missing. There is a PDF version of this article at <a href="https://github.com/dpiponi/StableBlog/blob/main/ConstructingClifford/ConstructingClifford.pdf">GitHub</a>.
</div>
<p>
Some literate Haskell but little about this code is specific to Haskell...
</p><p><br/>
</p><pre>&gt; {-# LANGUAGE DataKinds #-}
&gt; {-# LANGUAGE TypeFamilies #-}
&gt; {-# LANGUAGE TypeOperators #-}
&gt; {-# LANGUAGE UndecidableInstances #-}
&gt; 
&gt; import GHC.TypeLits
<p><br/>
</p></pre>
<br/><b>Introduction</b><p>
This is a followup to <a href="http://blog.sigfpe.com/2006/08/geometric-algebra-for-free_30.html">Geometric Algebra for Free</a> and <a href="http://blog.sigfpe.com/2006/09/more-low-cost-geometric-algebra.html">More Low Cost Geometric Algebra</a>.
</p><p><br/>
In those articles I showed how you could build up the Clifford algebras like so:
</p><p><br/>
</p><pre>type Cliff1  = Complex R
type Cliff1' = Split R
type Cliff2  = Quaternion R
type Cliff2' = Matrix R
type Cliff3  = Quaternion Cliff1'
type Cliff3' = Matrix Cliff1
type Cliff4  = Quaternion Cliff2'
type Cliff4' = Matrix Cliff2
type Cliff5  = Quaternion Cliff3'
...
<p><br/>
</p></pre>
I used <tt>CliffN</tt> as the Clifford algebra for a negative definite inner product and
<tt>CliffN'</tt> for the positive definite case.
It's not a completely uniform sequence in the sense that <tt>CliffN</tt> is built from <tt>CliffN'</tt> for dimension two lower and you use a mix of <tt>Matrix</tt> and <tt>Quaternion</tt>.
<p><br/>
The core principle making this work is that for type constructors <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=T" style="vertical-align: middle;"/> implemented like <tt>Matrix</tt>, <tt>Quaternion</tt> etc. we have the property that
</p><p><br/>
<img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=TU%5Cmathbb%7BR%7D%20%3D%20T%5Cmathbb%7BR%7D%5Cotimes%20U%5Cmathbb%7BR%7D" style="vertical-align: middle;"/>
</p><p><br/>
eg. <tt>Matrix (Quaternion Float)</tt> is effectively the same thing as <tt>Matrix Float</tt> <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=%5Cotimes" style="vertical-align: middle;"/> <tt>Quaternion Float</tt>.
</p><p><br/>
But John Baez pointed out to me that you can build up the <tt>CliffN</tt> algebras much more simply enabling us to use these definitions:
</p><p><br/>
</p><pre>&gt; type Cliff1 = Complex Float
&gt; type Cliff2 = Complex Cliff1
&gt; type Cliff3 = Complex Cliff2
&gt; type Cliff4 = Complex Cliff3
&gt; type Cliff5 = Complex Cliff4
<p><br/>
</p></pre>
<pre>...
<p><br/>
</p></pre>
Or even better:
<p><br/>
</p><pre>&gt; type family Cliff (n :: Nat) :: * where
&gt;   Cliff 0 = Float
&gt;   Cliff n = Complex (Cliff (n - 1))
<p><br/>
</p></pre>
But there's one little catch.
We have to work, not with the tensor product, but the <b>super tensor</b> product.
<p><br/>
We define <tt>Complex</tt> the same way as before:
</p><p><br/>
</p><pre>&gt; data Complex a = C a a deriving (Eq, Show)
<p><br/>
</p></pre>
Previously we used a definition of multiplication like this:
<p><br/>
</p><pre>instance Num a =&gt; Num (Complex a) where
  C a b * C c d = C (a * c - b * d) (a * d + b * c) 
<p><br/>
</p></pre>
We can think of <tt>C a b</tt> in <tt>Complex R</tt> as representing the element \(1\otimes a+i\otimes b\). The definition of multiplication in a tensor product of algebras is
<div class="legacy-equation-display">\[(a\otimes b)(c\otimes d)=(ac)\otimes(bd).\]</div>
So we have
<div class="legacy-equation-display">\[(1\otimes a+i\otimes b)(1\otimes c+i\otimes d)\]</div>
<div class="legacy-equation-display">\[=1\otimes ac+i\otimes ad+i\otimes bc+i^2\otimes bd\]</div>
<div class="legacy-equation-display">\[=1\otimes(ac-bd)+i\otimes(ad+bc).\]</div>
<p><br/>
This means that line of code we wrote above defining <tt>*</tt> for <tt>Complex</tt> isn't simply a definition of multiplication of complex numbers, it says how to multiply in an algebra tensored with the complex numbers.
</p><p><br/>
<br/><b>Let's go Super!</b></p><p>
A <a href="https://en.wikipedia.org/wiki/Superalgebra">superalgebra</a> is an algebra graded by <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=%5Cmathbb%7BZ%7D_2" style="vertical-align: middle;"/> where <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=%5Cmathbb%7BZ%7D_2" style="vertical-align: middle;"/> is the ring of integers modulo 2.
What that means is that we have some algebra <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=A" style="vertical-align: middle;"/> that can be broken down as a direct sum <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=A_0%5Coplus%20A_1" style="vertical-align: middle;"/> (the subscripts live in <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=%5Cmathbb%7BZ%7D_2" style="vertical-align: middle;"/>) with the property that multiplication respects the grading, ie. if <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=x" style="vertical-align: middle;"/> is in <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=A_i" style="vertical-align: middle;"/> and <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=y" style="vertical-align: middle;"/> is in <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=A_j" style="vertical-align: middle;"/> then <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=xy" style="vertical-align: middle;"/> is in <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=A_%7Bi%2Bj%7D" style="vertical-align: middle;"/>.
</p><p><br/>
The elements of <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=A_0" style="vertical-align: middle;"/> are called "even" (or bosonic) and those in <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=A_1" style="vertical-align: middle;"/> "odd" (or fermionic). Often even elements commute with everything and odd elements anticommute with each other but this isn't always the case. (The superalgebra is said to be supercommutative when this happens. This is a common pattern: a thing X becomes a superX if it has odd and even parts and swapping two odd things introduces a sign flip.)
</p><p><br/>
The super tensor product is much like the tensor product but it respects the grading.
This means that if <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=x" style="vertical-align: middle;"/> is in <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=A_i" style="vertical-align: middle;"/> and <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=y" style="vertical-align: middle;"/> is in <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=B_j" style="vertical-align: middle;"/> then <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=x%5Cotimes%20y" style="vertical-align: middle;"/> is in <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=%28A%5Cotimes%20B%29_%7Bi%2Bj%7D" style="vertical-align: middle;"/>.
From now on I'm using <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=%5Cotimes" style="vertical-align: middle;"/> to mean super tensor product.
</p><p><br/>
Multiplication in the super tensor product of two superalgebras <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=A" style="vertical-align: middle;"/> and <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=B" style="vertical-align: middle;"/> is now defined by the following modified rule:
if <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=b" style="vertical-align: middle;"/> is in <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=B_i" style="vertical-align: middle;"/> and <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=c" style="vertical-align: middle;"/> is in <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=A_j" style="vertical-align: middle;"/> then <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=%28a%5Cotimes%20b%29%28c%5Cotimes%20d%29%20%3D%20%28-1%29%5E%7Bij%7D%28ac%29%5Cotimes%28bd%29" style="vertical-align: middle;"/>.
Note that the sign flip arises when we shuffle an odd <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=c" style="vertical-align: middle;"/> left past an odd <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=b" style="vertical-align: middle;"/>.
</p><p><br/>
The neat fact that John pointed out to me is that
</p><div class="legacy-equation-display">\[Cliff_n=\mathbb{C}\otimes\mathbb{C}\otimes\ldots\text{ n times }\ldots\otimes\mathbb{C}.\]</div>
<p><br/>
We have to modify our definition of <tt>*</tt> to take into account that sign flip.
</p><p><br/>
I initially wrote a whole lot of code to define a superalgebra as a pair of algebras with four multiplication operations and it got a bit messy.
But I noticed that the only specifically superalgebraic operation I ever performed on an element of a superalgebra was negating the odd part of an element.
</p><p><br/>
So I could define <tt>SuperAlgebra</tt> like so:
</p><p><br/>
</p><pre>class SuperAlgebra a where
  conjugation :: a -&gt; a
<p><br/>
</p></pre>
where <tt>conjugation</tt> is the negation of the odd part.
<p><br/>
(I'm not sure if this operation corresponds to what is usually called conjugation in this branch of mathematics.)
</p><p><br/>
But there's a little efficiency optimization I want to write.
If I used the above definition, then later I'd often find myself computing a whole lot of <tt>negate</tt>s in a row.
This means applying <tt>negate</tt> to many elements of large algebraic objects even
though any pair of them cancel each other's effect.
So I add a little flag to my conjugation function that is used to say we want an extra <tt>negate</tt> and we can
accumulate flips of a flag rather than flips of lots of elements.
</p><p><br/>
</p><pre>&gt; class SuperAlgebra a where
&gt;   conjugation :: Bool -&gt; a -&gt; a
<p><br/>
</p></pre>
Here's our first instance:
<p><br/>
</p><pre>&gt; instance SuperAlgebra Float where
&gt;   conjugation False x = x
&gt;   conjugation True x = negate x
<p><br/>
</p></pre>
This is saying that the conjugation is the identity on <tt>Float</tt> but if we
want to perform an extra flip we can set the flag to <tt>True</tt>.
Maybe I should call it <tt>conjugationWithOptionalExtraNegation</tt>.
<p><br/>
And now comes the first bit of non-trivial superalgebra:
</p><p><br/>
</p><pre>&gt; instance (Num a, SuperAlgebra a) =&gt; SuperAlgebra (Complex a) where
&gt;   conjugation e (C a b) = C (conjugation e a) (conjugation (not e) b)
<p><br/>
</p></pre>
We consider <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=1" style="vertical-align: middle;"/> to be even and <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=i" style="vertical-align: middle;"/> to be odd. When we apply the conjugation to <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=1%5Cotimes%20a%2Bi%5Cotimes%20b" style="vertical-align: middle;"/> then we can just apply it directly to <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=a" style="vertical-align: middle;"/>.
But that <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=i%5Cotimes" style="vertical-align: middle;"/> flips the "parity" of <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=b" style="vertical-align: middle;"/> (because tensor product respects the grading) so we need to swap when we use the conjugation.
And that should explain why <tt>conjugation</tt> is defined the way it is.
<p><br/>
Now we can use the modified rule for <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=%5Cmathbb%7BC%7D%5Cotimes" style="vertical-align: middle;"/> defined above:
</p><p><br/>
</p><pre>&gt; instance (Num a, SuperAlgebra a) =&gt; Num (Complex a) where
&gt;   fromInteger n = C (fromInteger n) 0
&gt;   C a b + C a' b' = C (a + a') (b + b')
&gt;   C a b * C c d = C (a * c - conjugation False b * d)
&gt;                     (conjugation False a * d + b * c) 
&gt;   negate (C a b) = C (negate a) (negate b)
&gt;   abs = undefined
&gt;   signum = undefined
<p><br/>
</p></pre>
For example, <tt>conjugation False</tt> is applied to the first <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=b" style="vertical-align: middle;"/> on the RHS because <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=d" style="vertical-align: middle;"/> implicitly represents an <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=id" style="vertical-align: middle;"/> term and when expanding out the product we shuffle the (odd) <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=i" style="vertical-align: middle;"/> in <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=id" style="vertical-align: middle;"/> left of <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=b" style="vertical-align: middle;"/>. It doesn't get applied to the second <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=ib" style="vertical-align: middle;"/> because <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=ib" style="vertical-align: middle;"/> and <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=c" style="vertical-align: middle;"/> remain in the same order.
<p><br/>
That's it!
</p><p><br/>
<br/><b>Tests</b></p><p>
I'll test it with some examples from <tt>Cliff3</tt>:
</p><p><br/>
</p><pre>&gt; class HasBasis a where
&gt;   e :: Integer -&gt; a
<p><br/>
&gt; instance HasBasis Float where
&gt;   e = undefined
</p><p><br/>
&gt; instance (Num a, HasBasis a) =&gt; HasBasis (Complex a) where
&gt;   e 0 = C 0 1
&gt;   e n = C (e (n - 1)) 0
</p><p><br/>
&gt; make a b c d e f g h =
&gt;   C (C (C a b) (C c d))
&gt;     (C (C e f) (C g h))
</p><p><br/>
&gt; e1, e2, e3, e21, e31, e32, e321 :: Cliff 3
&gt; e1 = e 0
&gt; e2 = e 1
&gt; e21 = e2 * e1
&gt; e3 = e 2
&gt; e31 = e3 * e1
&gt; e32 = e3 * e2
&gt; e321 = e3 * e2 * e1
</p><p><br/>
&gt; main = do
&gt;     print (e1 * e1 + 1 == 0)
&gt;     print (e31 * e31 + 1 == 0)
&gt;     print (e3 * e3 + 1 == 0)
&gt;     print (e21 * e21 + 1 == 0)
&gt;     print (e2 * e2 + 1 == 0)
&gt;     print (e32 * e32 + 1 == 0)
&gt;     print (e321 * e321 - 1 == 0)
&gt;     print (e3 * e2 * e1 - e321 == 0)
&gt;     print (e2 * e1 - e21 == 0)
&gt;     print (e3 * e1 - e31 == 0)
&gt;     print (e3 * e2 - e32 == 0)
&gt;     print (e21 * e32 - e31 == 0)
</p><p><br/>
</p></pre>
<br/><b>Observation</b><p>
The implementation of multiplication looks remarkably like it's the <a href="https://en.wikipedia.org/wiki/Cayley&#xE2;&#x20AC;&#x201C;Dickson_construction">Cayley-Dickson</a> construction.
It can't be (because iterating it three times gives you a non-associative algebra but the Clifford algebras are associative).
Nonetheless, I think comparison with Cayley-Dickson may be useful.
</p><p><br/>
<br/><b>Efficiency</b></p><p>
As mentioned above, before I realised I just needed the <tt>conjugation</tt> operation I wrote the above code with an explicit split of a superalgebra into two pieces intertwined by four multiplications.
I think the previous approach may have a big advantage - it may be possible to use variations on the well known "speed-up" of complex multiplication that uses three real multiplications instead of four.
This should lead to a fast implementation of Clifford algebras.
</p><p><br/>
Also be warned: you can kill GHC if you turn on optimization and try to multiply elements of high-dimensional Clifford algebras.
I think it tries to inline absolutely everything and you end up with a block of code that grows exponentially with <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=n" style="vertical-align: middle;"/>.
</p><p><br/>
Note also that this code translates directly into many languages.</p></div>
    </summary>
    <updated>2026-04-23T00:28:40Z</updated>
    <published>2023-03-05T19:38:00Z</published>
    <author>
      <name>sigfpe</name>
      <email>noreply@blogger.com</email>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-11295132</id>
      <category term="mathematics"/>
      <category term="haskell"/>
      <category term="physics"/>
      <category term="monad"/>
      <category term="programming"/>
      <category term="types"/>
      <category term="astronomy"/>
      <category term="quantum"/>
      <category term="comonads"/>
      <category term="self-reference"/>
      <category term="category theory"/>
      <category term="lawvere theories"/>
      <category term="optimisation"/>
      <category term="probability"/>
      <author>
        <name>sigfpe</name>
        <email>noreply@blogger.com</email>
      </author>
      <link href="http://blog.sigfpe.com/" rel="alternate" type="text/html"/>
      <link href="http://sigfpe.blogspot.com/rss.xml" rel="self" type="application/rss+xml"/>
      <title>A Neighborhood of Infinity</title>
      <updated>2026-05-19T09:26:13Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-11295132.post-1013073177509119669</id>
    <link href="http://blog.sigfpe.com/2017/07/self-referential-logic-via-self.html" rel="alternate" type="text/html"/>
    <title>Self-referential logic via self-referential circuits</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><br/><b>Introduction</b><p>
</p><p><br/>
<b>TL;DR</b> The behaviour of a certain kind of delay component has a formal similarity to Löb's theorem which gives a way to embed part of provability logic into electronic circuits.
</p><p><br/>
Here's a <a href="https://en.wikipedia.org/wiki/Liar_paradox">famous</a> paradoxical sentence:
</p><p><br/>
</p><blockquote>
<i>This sentence is false</i>
</blockquote>
<p><br/>
If it's false then it's true and if it's true then it's false.
</p><p><br/>
Here's a paradoxical electronic circuit:

</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTQrxM676I5rkbw4SBhHymMm5gIxUI2cZA7sULYTpQQyN_PXP-PzMLuhZ9Jm0XmxKGHY-AUeVNFFPvYGSzKlwgMCwt84CXwBXGhd0O6YMiNOyunXSjDKf8NPgQrJSs93sMhOEH/s1600/not.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="168" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTQrxM676I5rkbw4SBhHymMm5gIxUI2cZA7sULYTpQQyN_PXP-PzMLuhZ9Jm0XmxKGHY-AUeVNFFPvYGSzKlwgMCwt84CXwBXGhd0O6YMiNOyunXSjDKf8NPgQrJSs93sMhOEH/s320/not.png" width="320"/></a></div><br/>

The component in the middle is an inverter. If the output of the circuit is high then its input is high and then it's output must be low, and vice versa.
<p><br/>
There's a similarity here.
But with a bit of tweaking you can turn the similarity into an isomorphism of sorts.
</p><p><br/>
In the first case we avoid paradox by noting that in the mathematical frameworks commonly used by mathematicians it's impossible, in general, for a statement to assert it's own falsity.
Instead, a statement can assert its own <i>unprovability</i> and then we get Gödel's incompleteness theorems and a statement that is apparently true and yet can't be proved.
</p><p><br/>
In the second case we can't model the circuit straightforwardly as a digital circuit.
In practice it might settle down to a voltage that lies between the official high and low voltages so we have to model it as an analogue circuit.
Or instead we can introduce a clock and arrange that the feedback in the circuit is delayed.
We then get an <a href="https://electronics.stackexchange.com/questions/206907/how-to-delay-a-not-gate-oscillator-to-make-it-run-at-a-desired-frequency">oscillator circuit</a> that can be thought of as outputting a stream of bits.
</p><p><br/>
The observation I want to make is that if the feedback delay is defined appropriately, these two scenarios are in some sense isomorphic.
This means that we can model classic results about provability, like Gödel's incompleteness theorems, using electronic circuits.
We can even use such circuits to investigate what happens when <a href="https://intelligence.org/files/ProgramEquilibrium.pdf">logicians or robots play games like Prisoner's Dilemma</a>.
I'll be making use of results found in Boolos' book on <a href="http://www.cambridge.org/catalogue/catalogue.asp?isbn=0521483255">The Logic of Provability</a> and some ideas I borrowed from Smoryński's <a href="https://projecteuclid.org/euclid.bams/1183548781">paper</a> on Fixed Point Algebras.
I'll be assuming the reader has at least a slight acquaintance with ithe ideas behind provability logic.
</p><p><br/>
<br/><b>Provability Logic</b></p><p>
There are many descriptions of <a href="https://en.wikipedia.org/wiki/Provability_logic">provability logic</a> (aka GL) available online, so I'm not going to repeat it all here.
However, I've put some background material in the <a href="http://blog.sigfpe.com/rss.xml#appendix">appendix</a> below and I'm going to give a very brief reminder now.
</p><p><br/>
Start with (classical) propositional calculus which has a bunch of variables with names like <span class="legacy-equation-inline">\(a, b, c, d, \ldots\)</span> and connectives like <span class="legacy-equation-inline">\(\wedge\)</span> for AND, <span class="legacy-equation-inline">\(\vee\)</span> for OR, <span class="legacy-equation-inline">\(\neg\)</span> for NOT and <span class="legacy-equation-inline">\(\rightarrow\)</span> for implication. (Note that <span class="legacy-equation-inline">\(a\rightarrow b = \neg a\vee b\)</span>.)
</p><p><br/>
Provability logic extends propositional calculus by adding a unary operator <span class="legacy-equation-inline">\(\Box\)</span>.
(I apologise, that's meant to be a □ but it's coming out like <span class="legacy-equation-inline">\(\Box\)</span> in LaTeX formulae.
I think it's a bug in Google's LaTeX renderer.)
The idea is that <span class="legacy-equation-inline">\(\Box p\)</span> asserts that <span class="legacy-equation-inline">\(p\)</span> is provable in Peano Arithmetic, aka PA.
In addition to the axioms of propositional calculus we have
</p><blockquote>
<span class="legacy-equation-inline">\(\Box(p\rightarrow q)\rightarrow\Box p\rightarrow\Box q\)</span>
</blockquote>
and
<blockquote>
<span class="legacy-equation-inline">\(\Box p\rightarrow\Box\Box p\)</span>
</blockquote>
as well as a rule that allows us to deduce <span class="legacy-equation-inline">\(\Box p\)</span> from <span class="legacy-equation-inline">\(p\)</span>.
<p><br/>
We also have this fixed point property:
</p><p><br/>
</p><blockquote>
Let <span class="legacy-equation-inline">\(F(p)\)</span> be any predicate we can write in the language of GL involving the variable <span class="legacy-equation-inline">\(p\)</span>, and suppose that every appearance of <span class="legacy-equation-inline">\(p\)</span> in <span class="legacy-equation-inline">\(F(p)\)</span> is inside a <span class="legacy-equation-inline">\(\Box\)</span>, e.g. <span class="legacy-equation-inline">\(F(p)=\Box p\vee\Box(\neg p)\)</span>. Then there is a fixed point, i.e. a proposition <span class="legacy-equation-inline">\(q\)</span> that makes no mention of <span class="legacy-equation-inline">\(p\)</span> such that <span class="legacy-equation-inline">\(q\leftrightarrow F(q)\)</span> is a theorem.
In effect, for any such <span class="legacy-equation-inline">\(F\)</span>, <span class="legacy-equation-inline">\(q\)</span> is a proposition that asserts <span class="legacy-equation-inline">\(F(q)\)</span>.
</blockquote>
<p><br/>
See the <a href="http://blog.sigfpe.com/rss.xml#appendix">appendix</a> for a brief mention of why we should expect this to be true.
</p><p><br/>
From the fixed point property we can deduce Löb's theorem: <span class="legacy-equation-inline">\(\Box(\Box p\rightarrow p)\rightarrow\Box p\)</span>.
There is a <a href="https://en.wikipedia.org/wiki/L&#xF6;b%27s_theorem">proof</a> at wikipedia that starts from the fixed point property.
</p><p><br/>
We can also deduce the fixed point property from Löb's theorem so it's more usual to take Löb's theorem as an axiom of GL and show that the fixed point property follows.
You can think of Löb's theorem as a cunning way to encode the fixed point property.
In fact <a href="http://semantic-domain.blogspot.com/2016/05/lobs-theorem-is-almost-y-combinator.html">you can argue</a> that it's a sort of Y-combinator, the function that allows the formation of recursive fixed points in functional programming languages.
(That's also, sort of, the role played by the <tt>loeb</tt> function I defined <a href="http://blog.sigfpe.com/2006/11/from-l-theorem-to-spreadsheet.html">way back</a>.
But note that <tt>loeb</tt> isn't really a proof of Löb's theorem, it just has formal similarities.)
</p><p><br/>
<br/><b>Back to electronic circuits</b></p><p>
In order to make digital circuits with feedback loops well-behaved I could introduce a circuit element that results in a delay of one clock cycle.
If you insert one of these into the inverter circuit I started with you'll end up with an oscillator that flips back and forth between 0 and 1 on each clock cycle.
But I want to work with something slightly stricter.
I'd like my circuits to eventually stop oscillating.
(I have an ulterior motive for studying these.)
Let me introduce this component:

</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUDKyNpC4N5JjamkQovWaimr79X_y6Q6LEGvffnhEUJEXOxR6Z3OlZLHH_MvwGt4M3GHGeuL_7IjX-DeuhXRJk9liFdeOTCnJUTDUDqPWfrx5hLFr7xO4rnofKOUFKoGuOEFuy/s1600/delay.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="137" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUDKyNpC4N5JjamkQovWaimr79X_y6Q6LEGvffnhEUJEXOxR6Z3OlZLHH_MvwGt4M3GHGeuL_7IjX-DeuhXRJk9liFdeOTCnJUTDUDqPWfrx5hLFr7xO4rnofKOUFKoGuOEFuy/s320/delay.png" width="320"/></a></div><br/>

It is intended to serve as a delayed latch and I'll always have the flow of data being from left to right.
The idea is that when it is switched on it outputs 1.
It keeps outputting 1 until it sees a 0 input.
When that happens, then on the next clock cycle its output drops to 0 and never goes back up to 1 until reset.
<p><br/>
Because the output of our delay-latch isn't a function of its current input, we can't simply describe its operation as a mathematical function from <span class="legacy-equation-inline">\(\{0,1\}\)</span> to <span class="legacy-equation-inline">\(\{0,1\}\)</span>.
Instead let's think of electronic components as binary operators on bitstreams, i.e. infinite streams of binary digits like <tt>...00111010</tt> with the digits emerging over time starting with the one written on the right and working leftwards.
The ordinary logic gates perform bitwise operations which I'll represent using the operators in the C programming language.
For example,
</p><blockquote>
<tt>...001110 &amp; ...101010 = ...001010</tt>
</blockquote>
and
<blockquote><tt>~...101 = ...010</tt>
</blockquote>
and so on.
Let's use □ to represent the effect of latch-delay on a bitstream.
We have, for example,
<blockquote>
<tt>□...000 = ...001</tt>
</blockquote>
and
<blockquote>
<tt>□...11101111 = ...00011111</tt>.
</blockquote>
The operator □ takes the (possibly empty) contiguous sequence of 1's at the end of the bitstream, extends it by one 1, and sets everything further to the left to 0.
If we restrict ourselves to bitstreams that eventually become all 0's or all 1's on the left, then bitstreams are in one-to-one correspondence with the integers using the twos complement representation.
For example <tt>...111111</tt>, all 1's, represents the number -1.
I'll simply call the bistreams that represent integers integers.
With this restriction we can use a classic C hacker trick to write <tt>□p=p^(p+1)</tt> where <tt>^</tt> is the C XOR operator.
The operator □ outputs the bits that get flipped when you add one.
<p><br/>
Let's use the symbol <tt>→</tt> so that <tt>a → b</tt> is shorthand for <tt>~a|b</tt>.
Here are some properties of □:
</p><p><br/>
1. <tt>□(-1) = -1</tt>
</p><p><br/>
2. <tt>□p → □□p = -1</tt>
</p><p><br/>
3. <tt>□(p → q) → □p → □q = -1</tt>
</p><p><br/>
In addition we have the fixed point property:
</p><p><br/>
</p><blockquote>
Let F(p) be any function of p we can write using □ and the bitwise logical operators and such that all occurrences of p occur inside □.
Then there is a unique bitstream q such that q=F(q).
</blockquote>
<p><br/>
We can make this clearer if we return to circuits.
F(p) can be thought of as a circuit that takes p as input and outputs some value.
We build the circuit using only boolean logic gates and delay-latch.
We allow feedback loops, but only ones that go through delay-latches.
With these restrictions it's pretty clear that the circuit is well-behaved and deterministically outputs a bitstream.
</p><p><br/>
We also have the Löb property:
</p><p><br/>
4. □(□p → p) → □p = -1
</p><p><br/>
We can see this by examining the definition of □.
Intuitively it says something like "once □ has seen a 0 input then no amount of setting input bits to 1 later in the stream make any different to its output".
</p><p><br/>
I hope you've noticed something curious.
These properties are extremely close to the properties of <span class="legacy-equation-inline">\(\Box\)</span> in GL.
In fact, these electronic circuits form a model of the part of GL that doesn't involve variable names, i.e. what's known as letterless GL.
We can formalise this:
</p><p><br/>
1. Map <span class="legacy-equation-inline">\(\bot\)</span> to a wire set to 0, which outputs <tt>...000 = 0</tt>.
</p><p><br/>
2. Map <span class="legacy-equation-inline">\(\top\)</span> to a wire set to 1, which outputs <tt>...111 = -1</tt>.
</p><p><br/>
3. Map <span class="legacy-equation-inline">\(p \circ q\)</span>, where <span class="legacy-equation-inline">\(\circ\)</span> is a binary connective, by creating a circuit that takes the outputs from the circuits for <span class="legacy-equation-inline">\(p\)</span> and <span class="legacy-equation-inline">\(q\)</span> and passes them into the corresponding boolean logic gate.
</p><p><br/>
4. Map <span class="legacy-equation-inline">\(\Box p\)</span> to the circuit for <span class="legacy-equation-inline">\(p\)</span> piped through a delay-latch.
</p><p><br/>
For example, let's convert <span class="legacy-equation-inline">\(\Box(\Box\bot\rightarrow\bot)\rightarrow\Box\bot\)</span> into a circuit. I'm translating <span class="legacy-equation-inline">\(a\rightarrow b\)</span> to the circuit for <span class="legacy-equation-inline">\(\neg a\vee b\)</span>.

</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizI-vfx5Ag24RnTOPKZmTX8PF9u6kF38vhmxW5w6kiWuJeLa76JLMm1ise_zRFNq5zx0CXqhN2ppQWP5WFMKSnS9MYdDy6skA43Et-j74PEfH4WhOWzr8oPHnJ15efq1BL-YI9/s1600/a.gif" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="103" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizI-vfx5Ag24RnTOPKZmTX8PF9u6kF38vhmxW5w6kiWuJeLa76JLMm1ise_zRFNq5zx0CXqhN2ppQWP5WFMKSnS9MYdDy6skA43Et-j74PEfH4WhOWzr8oPHnJ15efq1BL-YI9/s640/a.gif" width="640"/></a></div>

<p><br/>
I'm using red wires to mean wires carrying the value 1 rather than 0.
I hope you can see that this circuit eventually settles into a state that outputs nothing but 1s.
</p><p><br/>
We have this neat result:
</p><blockquote>
Because delay-latch satisfies the same equations as <span class="legacy-equation-inline">\(\Box\)</span> in provability logic, any theorem, translated into a circuit, will produce a bistream of just 1s, i.e. -1.
</blockquote>
<p><br/>
But here's a more surprising result: the converse is true.
</p><blockquote>
If the circuit corresponding to a letterless GL proposition produces a bistream of just 1s then the proposition is actually a theorem of GL.
</blockquote>
I'm not going to prove this.
(It's actually a disguised form of lemma 7.4 on p.95 of Boolos' book.)
In the pictured example we got <tt>...1111</tt>, so the circuit represents a theorem.
As it represents Löb's theorem for the special case <span class="legacy-equation-inline">\(p=\bot\)</span> we should hope so.
More generally, any bitstream that represents an integer can be converted back into a proposition that is equivalent to the original proposition.
This means that bitstreams faithfully represent propositions of letterless GL.
I'm not going to give the translation here but it's effectively given in Chapter 7 of Boolos.
I'll use <span class="legacy-equation-inline">\(\psi(p)\)</span> to represent the translation from propositions to bitstreams via circuits that I described above.
Use <span class="legacy-equation-inline">\(\phi(b)\)</span> to represent the translation of bitstream <span class="legacy-equation-inline">\(b\)</span> back into propositions.
We have <span class="legacy-equation-inline">\(p\leftrightarrow\phi(\psi(p))\)</span>.
But I haven't given a full description of <span class="legacy-equation-inline">\(\phi\)</span> and I haven't proved here that it has this property.
<p><br/>
<br/><b>Circuits with feedback</b></p><p>
</p><p><br/>
In the previous section I considered letterless propositions of GL.
When these are translated into circuits they don't have feedback loops.
But we can also "solve equations" in GL using circuits <i>with</i> feedback.
The GL fixed point theorem above says that we can "solve" the equation <span class="legacy-equation-inline">\(p\leftrightarrow F(p)\)</span>, with one letter <span class="legacy-equation-inline">\(p\)</span>, to produce a letterless proposition <span class="legacy-equation-inline">\(q\)</span> such that <span class="legacy-equation-inline">\(q\leftrightarrow F(q)\)</span>.
Note here that <span class="legacy-equation-inline">\(p\)</span> is a letter in the language of GL.
But I'm using <span class="legacy-equation-inline">\(q\)</span> to represent a proposition in letterless GL.
If we build a circuit to represent <span class="legacy-equation-inline">\(F\)</span>, and feed its output back into where <span class="legacy-equation-inline">\(p\)</span> appears, then the output bitstream represents the fixed point.
Here's a translation of the equation <span class="legacy-equation-inline">\(p \leftrightarrow \neg(\Box p \vee \Box\Box\Box p)\)</span>:

</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTl3Fq_GwQA6u6VzMUtncCHvRczrIj0qsLaNp9gQZ7vN7N0QoJdrrCoxjoPOceBvoY8Xu1tZJ_CzlKlnKQFVEsdd0AtnGQFD8rifrxKuPO6lZN9I3OK_Eup1H-vESpMQqDgNql/s1600/animated.gif" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="210" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTl3Fq_GwQA6u6VzMUtncCHvRczrIj0qsLaNp9gQZ7vN7N0QoJdrrCoxjoPOceBvoY8Xu1tZJ_CzlKlnKQFVEsdd0AtnGQFD8rifrxKuPO6lZN9I3OK_Eup1H-vESpMQqDgNql/s640/animated.gif" width="640"/></a></div>

I'll let you try to convince yourself that such circuits always eventually output all 0's or all 1's.
When we run the circuit we get the output <tt>...1111000 = -8</tt>.
As this is not -1 we know that the fixed point isn't a theorem.
If I'd defined <span class="legacy-equation-inline">\(\phi\)</span> above you could use it to turn the bitstream back into a proposition.
<p><br/>
<br/><b>The same, syntactically (optional section)</b></p><p>
I have a Haskell library on github for working with GL: <a href="https://github.com/dpiponi/provability">provability</a>.
This uses a syntactic approach and checks propositions for theoremhood using a <a href="https://en.wikipedia.org/wiki/Method_of_analytic_tableaux">tableau method</a>.
We can use it to analyse the above example with feedback.
I have implemented a function, currently called <tt>value'</tt>, to perform the evaluation of the bitstream for a proposition.
However, in this case the <tt>fixedpoint</tt> function computes the fixed point proposition first and then converts to a bitstream rather than computing the bitstream directly from the circuit for F:
</p><p><br/>
</p><pre>&gt; let f p = Neg (Box p \/ Box (Box (Box p)))
&gt; let Just p = fixedpoint f
&gt; p
Dia T /\ Dia (Dia T /\ Dia (Dia T /\ Dia T))
&gt; value' p
-8
<p><br/>
</p></pre>
(Note that <tt>Dia p</tt> means <span class="legacy-equation-inline">\(\Diamond p = \neg\Box\neg p\)</span>.)
<p><br/>
The function <tt>fixedpoint</tt> does a lot of work under the hood.
(It uses a tableau method to carry out <a href="https://en.wikipedia.org/wiki/Craig_interpolation">Craig interpolation</a>.)
The circuit approach requires far less work.
</p><p><br/>
<br/><b>Applications</b></p><p>
<i>1. Programs that reason about themselves</i>
</p><p><br/>
In principle we can write a program that enumerates all theorems of PA.
That means we can use a quine trick to write a computer program that searches for a proof, in PA, of its own termination. Does such a program terminate?
</p><p><br/>
We can answer this with Löb's theorem.
Let <span class="legacy-equation-inline">\(p =\)</span> "The program terminates".
The program terminates if it can prove its termination.
Formally this means we assume <span class="legacy-equation-inline">\(\Box p\rightarrow p\)</span>.
Using one of the derivation rules of GL we get <span class="legacy-equation-inline">\(\Box(\Box p\rightarrow p)\)</span>.
Löb's theorem now gives us <span class="legacy-equation-inline">\(\Box p\)</span>.
Feed that back into our original hypothesis and we get <span class="legacy-equation-inline">\(p\)</span>.
In other words, we deduce that our program does in fact terminate.
(Thanks to Sridhar Ramesh for pointing this out to me.)
</p><p><br/>
But we can deduce this using a circuit.
We want a solution to <span class="legacy-equation-inline">\(p\leftrightarrow \Box p\)</span>.
Here's the corresponding circuit:

</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaEDCbfnZHW5jO-BEpAQk8XbO7VXaberWk-PV5ArUWGQYsndGnslr_1WZ7S1r-8w1RgWPVGb51hEIs3S7TijGLgW-sKXfEfoGZSs9IQNs5W1uuGCsNfh9zqeEmY2fc3zNv_Jj8/s1600/loop1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="120" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaEDCbfnZHW5jO-BEpAQk8XbO7VXaberWk-PV5ArUWGQYsndGnslr_1WZ7S1r-8w1RgWPVGb51hEIs3S7TijGLgW-sKXfEfoGZSs9IQNs5W1uuGCsNfh9zqeEmY2fc3zNv_Jj8/s320/loop1.png" width="320"/></a></div>

It starts by outputting 1's and doesn't stop.
In other words, the fixed point is a theorem.
And that tells us <span class="legacy-equation-inline">\(p\)</span> is a theorem.
And hence that the program terminates.
<p><br/>
<i>2. Robots who reason about each others play in Prisoner's Dilemma</i>
</p><p><br/>
For the background to this problem see <a href="http://lesswrong.com/lw/hmw/robust_cooperation_in_the_prisoners_dilemma/">Robust Cooperation in the Prisoner's Dilemma</a> at LessWrong.
We have two robot participants <span class="legacy-equation-inline">\(A\)</span> and <span class="legacy-equation-inline">\(B\)</span> playing Prisoner's Dilemma.
Each can examine the other's source code and can search for proofs that the opponent will cooperate.
Suppose each robot is programmed to enumerate all proofs of PA and cooperate if it finds a proof that its opponent will cooperate.
Here we have <span class="legacy-equation-inline">\(p =\)</span> "A will cooperate" and <span class="legacy-equation-inline">\(q =\)</span> "B will cooperate".
Our assumptions about the behaviour of the robots are <span class="legacy-equation-inline">\(p \leftrightarrow \Box q\)</span> and <span class="legacy-equation-inline">\(q \leftrightarrow \Box p\)</span>, and hence that <span class="legacy-equation-inline">\(p \leftrightarrow \Box\Box p\)</span>.
This corresponds to the circuit:

</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6YAAGpVUznaDE-J7wpouoDbJ9vE5Nty7ITT0w4mO8pLHHBxnymg3INgOwFYWYekWY105_T7JKJ1aPoR286TBGLCwvlopdA6xAEpoH9R28IOn5siR4kobXVrou-iVAko3Rjc3b/s1600/loop2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="83" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6YAAGpVUznaDE-J7wpouoDbJ9vE5Nty7ITT0w4mO8pLHHBxnymg3INgOwFYWYekWY105_T7JKJ1aPoR286TBGLCwvlopdA6xAEpoH9R28IOn5siR4kobXVrou-iVAko3Rjc3b/s320/loop2.png" width="320"/></a></div>

This outputs <tt>...1111 = -1</tt> so we can conclude <span class="legacy-equation-inline">\(p\)</span> and hence that these programs will cooperate.
(Note that this doesn't work out nicely if robot B has a program that doesn't terminate but whose termination isn't provable in the formal system A is using.
That means this approach is only good for robots that want to cooperate and want to confirm such cooperation. See the <a href="https://arxiv.org/abs/1401.5577">paper</a> for more on this.)
<p><br/>
At this point I really must emphasise that these applications are deceptively simple.
I've shown how these simple circuits can answer some tricky problems about provability.
But these aren't simply the usual translations from boolean algebra to logic gates.
They work because circuits with delay-latch provide a model for letterless provability logic and that's only the case because of a lot of non-trivial theorem proving in Boolos that I haven't reproduced here.
You're only allowed to use these simple circuits once you've seen the real proofs :-)
</p><p><br/>
<br/><b>Things I didn't say above</b></p><p>
1. I described the translation from propositions to circuits that I called <span class="legacy-equation-inline">\(\psi\)</span> above.
But I didn't tell you what <span class="legacy-equation-inline">\(\phi\)</span> looks like.
I'll leave this as an exercise.
(Hint: consider the output from the translation of <span class="legacy-equation-inline">\(\Box^n\bot\)</span> into a circuit.)
</p><p><br/>
2. The integers, considered as bistreams, with the bitwise operators, and the unary operator <tt>□p=p^(p+1)</tt>, form an algebraic structure.
For example, if we define <tt>⋄p=~□~p</tt> we have a <a href="https://ncatlab.org/nlab/show/Magari+algebra">Magari algebra</a>.
Structures like these are intended to capture the essential parts of self-referential arguments in an algebraic way.
</p><p><br/>
3. Because of the interpretation of □ as a delayed latch in a circuit you could view it as saying "my input was always true until a moment ago".
This surely embeds provability logic in a <a href="https://en.wikipedia.org/wiki/Temporal_logic">temporal logic</a> of some sort.
</p><p><br/>
4. (Deleted speculations about tit-for-tat that need rethinking.)
</p><p><br/>
5. For even the most complex letterless proposition in Boolos you could check its theoremhood with a pretty small circuit.
You could even consider doing this with a steam powered <a href="https://en.wikipedia.org/wiki/Pneumatic_circuit">pneumatic circuit</a>.
I had to say that to fulfil a prophecy and maintain the integrity of the timeline.
</p><p><br/>

<a id="appendix"/>

<br/><b>Appendix on provability</b></p><p>
The modern notion of a proof is that it is a string of symbols generated from some initial strings called "axioms" and some derivation rules that make new strings from both axioms and strings you've derived previously.
Usually we pick axioms that represent "self-evident" truths and we pick derivation rules that are "truth-preserving" so that every proof ends at a true proposition of which it is a proof.
The derivation rules are mechanical in nature: things like "if you have this symbol here and that symbol there then you can replace this symbol with that string you derived earlier" etc.
</p><p><br/>
You can represent strings of symbols using numbers, so-called Gödel numbers.
Let's pick a minimal mathematical framework for working with numbers: <a href="https://en.wikipedia.org/wiki/Peano_axioms#First-order_theory_of_arithmetic">Peano Arithmetic</a>, aka PA.
Let's assume we've made some choice of Gödel numbering scheme and when <span class="legacy-equation-inline">\(p\)</span> is a proposition, write <span class="legacy-equation-inline">\([p]\)</span> for the number representing <span class="legacy-equation-inline">\(p\)</span>.
You can represent the mechanical derivation rules as operations on numbers.
And that makes it possible to define a mathematical predicate <span class="legacy-equation-inline">\(Prov\)</span> that is true if and only if its argument represents a provable proposition.
</p><p><br/>
In other words, we can prove <span class="legacy-equation-inline">\(Prov([p])\)</span> using PA if and only if <span class="legacy-equation-inline">\(p\)</span> is a proposition provable in PA.
</p><p><br/>
The predicate <span class="legacy-equation-inline">\(Prov\)</span> has some useful properties:
</p><p><br/>
1.<i>If we can prove <span class="legacy-equation-inline">\(p\)</span>, then we can prove <span class="legacy-equation-inline">\(Prov([p])\)</span>.</i>
</p><p><br/>
We take the steps we used to prove <span class="legacy-equation-inline">\(p\)</span>, and convert everything to propositions about numbers.
If <span class="legacy-equation-inline">\(Prov\)</span> is defined correctly then we can convert that sequence of numbers into a sequence of propositions about those numbers that makes up a proof of <span class="legacy-equation-inline">\(Prov(p)\)</span>.
</p><p><br/>
2.<i><span class="legacy-equation-inline">\(Prov([p\rightarrow q])\)</span> and <span class="legacy-equation-inline">\(Prov([p])\)</span> imply <span class="legacy-equation-inline">\(Prov([q])\)</span></i>
</p><p><br/>
A fundamental step in any proof is <i>modus ponens</i>, i.e. that <span class="legacy-equation-inline">\(p\rightarrow q\)</span> and <span class="legacy-equation-inline">\(q\)</span> implies <span class="legacy-equation-inline">\(p\)</span>.
If <span class="legacy-equation-inline">\(Prov\)</span> does its job correctly then it had better know about this.
</p><p><br/>
3.<i><span class="legacy-equation-inline">\(Prov([p])\)</span> implies <span class="legacy-equation-inline">\(Prov([Prov([p])])\)</span></i>
</p><p><br/>
One way is to prove this is to use Löb's theorem.
</p><p><br/>
4. <i><span class="legacy-equation-inline">\(Prov([\top])\)</span></i>
</p><p><br/>
The trivially true statement had better be provable or <span class="legacy-equation-inline">\(Prov\)</span> is broken.
</p><p><br/>
Constructing <span class="legacy-equation-inline">\(Prov\)</span> is conceptually straightforward but hard work.
I'm definitely not going to do it here.
</p><p><br/>
And there's one last thing we need: self-reference.
If <span class="legacy-equation-inline">\(p\)</span> is a proposition, how can we possibly assert <span class="legacy-equation-inline">\(Prov([p])\)</span> without squeezing a copy of <span class="legacy-equation-inline">\([p]\)</span> inside <span class="legacy-equation-inline">\(p\)</span>?
I'm not going to do that here either - just mention that we can use a variation of <a href="https://en.wikipedia.org/wiki/Quine_%28computing%29">quining</a> to achieve this.
That allows us to form a proposition <span class="legacy-equation-inline">\(p\)</span> for which we can prove <span class="legacy-equation-inline">\(p\leftrightarrow Prov([p])\)</span>.
In fact, we can go further.
We can find propositions that solve <span class="legacy-equation-inline">\(p\leftrightarrow F(p)\)</span> for any predicate <span class="legacy-equation-inline">\(F(p)\)</span> built from the usual boolean operations and <span class="legacy-equation-inline">\(p\)</span> as long as all of the occurrences of <span class="legacy-equation-inline">\(p\)</span> are inside the appearances of <span class="legacy-equation-inline">\(Prov\)</span>.
Even though we can't form a proposition that directly asserts its own falsity, we can form one that asserts that it is unprovable, or one that asserts that you can't prove that you can't prove that you can prove it, or anything along those lines.
</p><p><br/>
Anyway, all that <span class="legacy-equation-inline">\([]\)</span> and <span class="legacy-equation-inline">\(Prov\)</span> business is a lot of hassle.
Provability logic, also known as GL, is intended to capture specifically the parts of PA that relate to provability.
GL is propositional calculus extended with the provability operator <span class="legacy-equation-inline">\(\Box\)</span>.
The intention is that if <span class="legacy-equation-inline">\(p\)</span> is a proposition, <span class="legacy-equation-inline">\(\Box p\)</span> is a proposition in GL that represents <span class="legacy-equation-inline">\(Prov([p])\)</span> in PA.
The properties of <span class="legacy-equation-inline">\(Prov\)</span> above become the axioms and derivation rules of GL in the main text.</p></div>
    </summary>
    <updated>2026-04-22T23:29:47Z</updated>
    <published>2017-07-15T16:09:00Z</published>
    <author>
      <name>sigfpe</name>
      <email>noreply@blogger.com</email>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-11295132</id>
      <category term="mathematics"/>
      <category term="haskell"/>
      <category term="physics"/>
      <category term="monad"/>
      <category term="programming"/>
      <category term="types"/>
      <category term="astronomy"/>
      <category term="quantum"/>
      <category term="comonads"/>
      <category term="self-reference"/>
      <category term="category theory"/>
      <category term="lawvere theories"/>
      <category term="optimisation"/>
      <category term="probability"/>
      <author>
        <name>sigfpe</name>
        <email>noreply@blogger.com</email>
      </author>
      <link href="http://blog.sigfpe.com/" rel="alternate" type="text/html"/>
      <link href="http://sigfpe.blogspot.com/rss.xml" rel="self" type="application/rss+xml"/>
      <title>A Neighborhood of Infinity</title>
      <updated>2026-05-19T09:26:13Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-11295132.post-751712815454057762</id>
    <link href="http://blog.sigfpe.com/2016/10/expectation-maximization-with-less.html" rel="alternate" type="text/html"/>
    <title>Expectation-Maximization with Less Arbitrariness</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><b>Introduction</b><p>

</p><div style="border: 1px solid #ccc; padding: 10px; background-color: #f9e9e9; margin: 10px 0;">
Google have stopped supporting the Chart API so all of the mathematics notation below is missing. There is a PDF version of this article at <a href="https://github.com/dpiponi/em/blob/master/em.pdf">GitHub</a>.
</div>

<p>
There are many introductions to the Expectation-Maximisation algorithm.
Unfortunately every one I could find uses arbitrary seeming tricks that seem to be plucked out of a hat by magic.
They can all be justified in retrospect, but I find it more useful to learn from reusable techniques that you can apply to further problems.
Examples of tricks I've seen used are:
</p><ol><li>Using Jensen's inequality.  It's easy to find inequalities that apply in any situation.  But there are often many ways to apply them.  Why apply it to <i>this</i> way of writing this expression and not that one which is equal?</li>
<li>Substituting <span class="legacy-equation-inline">\(1=A/A\)</span> in the middle of an expression.  Again, you can use <span class="legacy-equation-inline">\(1=A/A\)</span> just about anywhere.  Why choose this <span class="legacy-equation-inline">\(A\)</span> at this time? Similarly I found derivations that insert a <span class="legacy-equation-inline">\(B-B\)</span> into an expression.</li>
<li>Majorisation-Minimisation.  This is a great technique, but involves choosing a function that majorises another.  There are so many ways to do this, it's hard to imagine any general purpose method that tells you how to narrow down the choice.</li>
</ol>
My goal is to fill in the details of one key step in the derivation of the EM algorithm in a way that makes it inevitable rather than arbitrary.
There's nothing original here, I'm merely expanding on a <a href="http://stats.stackexchange.com/questions/44513/the-relationship-between-expectation-maximization-and-majorization-minimization/59470#59470">stackexchange answer</a>.
<p><br/>
<b>Generalities about EM</b></p><p>
The EM algorithm seeks to construct a maximum likelihood estimator (MLE) with a twist: there are some variables in the system that we can't observe.
</p><p><br/>
First assume no hidden variables.
We assume there is a vector of parameters <span class="legacy-equation-inline">\(\theta=(\theta_i)\)</span> that defines some model.
We make some observations <span class="legacy-equation-inline">\(x=(x_j)\)</span>.
We have a probability density <span class="legacy-equation-inline">\(P(x|\theta)\)</span> that depends on <span class="legacy-equation-inline">\(\theta\)</span>.
The likelihood of <span class="legacy-equation-inline">\(\theta\)</span> given the observations <span class="legacy-equation-inline">\(x\)</span> is <span class="legacy-equation-inline">\(l(\theta|x)=P(x|\theta)\)</span>.
The maximum likelhood estimator for <span class="legacy-equation-inline">\(\theta\)</span> is the choice of <span class="legacy-equation-inline">\(\theta\)</span> that maximises <span class="legacy-equation-inline">\(l(\theta|x)\)</span> for the <span class="legacy-equation-inline">\(x\)</span> we have observed.
</p><p><br/>
Now suppose there are also some variables <span class="legacy-equation-inline">\(z=(z_k)\)</span> that we didn't get to observe.
We assume a density <span class="legacy-equation-inline">\(P(x,z|\theta)\)</span>.
We now have
</p><blockquote>
<span class="legacy-equation-inline">\(P(x|\theta)=\sum_z P(x,z|\theta)\)</span>
</blockquote>
where we sum over all possible values of <span class="legacy-equation-inline">\(z\)</span>.
The MLE approach says we now need to maximise
<blockquote>
<span class="legacy-equation-inline">\(l(\theta|x)=\sum_z P(x,z|\theta).\)</span>
</blockquote>
One of the things that is a challenge here is that the components of <span class="legacy-equation-inline">\(\theta\)</span> might be mixed up among the terms in the sum.
If, instead, each term only referred to its own unique block of <span class="legacy-equation-inline">\(\theta_i\)</span>, then the maximisation would be easier as we could maximise each term independently of the others.
Here's how we might move in that direction.
Consider instead the log-likelihood
<blockquote>
<span class="legacy-equation-inline">\(\log l(\theta|x)=\log\sum_z P(x,z|\theta).\)</span>
</blockquote>
Now imagine that by magic we could commute the logarithm with the sum.
We'd need to maximise
<blockquote>
<span class="legacy-equation-inline">\(\sum_z \log P(x,z|\theta).\)</span>
</blockquote>
One reason this would be to our advantage is that <span class="legacy-equation-inline">\(P(x,z|\theta)\)</span> often takes the form <span class="legacy-equation-inline">\(\exp(f(x,z,\theta))\)</span> where <span class="legacy-equation-inline">\(f\)</span> is a simple function to optimise.
In addition, <span class="legacy-equation-inline">\(f\)</span> may break up as a sum of terms, each with its own block of <span class="legacy-equation-inline">\(\theta_i\)</span>'s.
Moving the logarithm inside the sum would give us something we could easily maximise term by term.
What's more, the <span class="legacy-equation-inline">\(P(x,z|\theta)\)</span> for each <span class="legacy-equation-inline">\(z\)</span> is often a standard probability distribution whose likelihood we already know how to maximise.
But, of course, we can't just move that logarithm in.
<p><br/>
<b>Maximisation by proxy</b></p><p>
Sometimes a function is too hard to optimise directly.
But if we have a guess for an optimum, we can replace our function with a proxy function that approximates it in the neighbourhood of our guess and optimise that instead.
That will give us a new guess and we can continue from there.
This is the basis of gradient descent.
Suppose <span class="legacy-equation-inline">\(f\)</span> is a differentiable function in a neighbourhood of <span class="legacy-equation-inline">\(x_0\)</span>.
Then around <span class="legacy-equation-inline">\(x_0\)</span> we have
</p><blockquote>
<span class="legacy-equation-inline">\(f(x) \approx f(x_0) f'(x_0)\cdot (x-x_0).\)</span>
</blockquote>
We can try optimising <span class="legacy-equation-inline">\(f(x_0) f'(x_0)\cdot (x-x_0)\)</span> with respect to <span class="legacy-equation-inline">\(x\)</span> within a neighbourhood of <span class="legacy-equation-inline">\(x_0\)</span>.
If we pick a small circular neighbourhood then the optimal value will be in the direction of steepest descent.
(Note that picking a circular neighbourhood is itself a somewhat arbitrary step,
but that's another story.)
For gradient descent we're choosing <span class="legacy-equation-inline">\(f(x_0) f'(x_0)\cdot (x-x_0)\)</span> because it matches both the value and derivatives of <span class="legacy-equation-inline">\(f\)</span> at <span class="legacy-equation-inline">\(x_0\)</span>.
We could go further and optimise a proxy that shares second derivatives too, and that leads to methods based on Newton-Raphson iteration.
<p><br/>
We want our logarithm of a sum to be a sum of logarithms.
But instead we'll settle for a proxy function that is a sum of logarithms.
We'll make the derivatives of the proxy match those of the original function
precisely so we're not making an arbitrary choice.
</p><p><br/>
Write
</p><blockquote>
<span class="legacy-equation-inline">\(\log l(\theta|x)
= \log\sum_z P(x,z|\theta)
\approx \sum_z\beta_z\log P(x,z|\theta) \text{constant}.\)</span>
</blockquote>
The <span class="legacy-equation-inline">\(\beta_z\)</span> are constants we'll determine.
We want to match the derivatives on either side of the <span class="legacy-equation-inline">\(\approx\)</span>
at <span class="legacy-equation-inline">\(\theta=\theta_0\)</span>:
<blockquote>
<span class="legacy-equation-inline">\(\frac{\partial \log l(\theta_0|x)}{\partial\theta_0}\)</span> <span class="legacy-equation-inline">\(=\frac{1}{l(\theta_0|x)} \frac{\partial l(\theta_0|x)}{\partial\theta_0} =\sum_z\frac{1}{l(\theta_0|x)} \frac{\partial P(x,z|\theta_0)}{\partial\theta_0}.\)</span>
</blockquote>
On the other hand we have
<blockquote>
<span class="legacy-equation-inline">\(\frac{\partial}{\partial\theta_0}\sum_z\beta_z\log P(x,z|\theta_0)
=\sum_z\beta_z\frac{1}{P(x,z|\theta_0)}\frac{\partial P(x,z|\theta_0)}{\partial\theta_0}\)</span>
</blockquote>
<p><br/>
To achieve equality we want to make these expressions match.
We choose
</p><blockquote>
<span class="legacy-equation-inline">\(\beta_z = \frac{P(x,z|\theta_0)}{l(\theta_0|x)}
= \frac{P(x,z|\theta_0)}{P(x|\theta_0)}
= P(z|x,\theta_0).\)</span>
</blockquote>
Our desired proxy function is:
<blockquote>
<span class="legacy-equation-inline">\(\sum_z P(z|x,\theta_0)\log P(x,z|\theta) + \text{const.}
= E_{Z|x,\theta_0}(\log P(x,Z|\theta)) + \text{const.}\)</span>
</blockquote>
<p><br/>
So the procedure is to take an estimated <span class="legacy-equation-inline">\(\theta_0\)</span> and obtain a new estimate
by optimising this proxy function with respect to <span class="legacy-equation-inline">\(\theta\)</span>.
This is the standard EM algorithm.
</p><p><br/>
It turns out that this proxy has some other useful properties.
For example, because of the concavity of the logarithm,
the proxy is always smaller than the original likelihood.
This means that when we optimise it we never optimise ``too far''
and that progress optimising the proxy is always progress optimising the
original likelihood.
But I don't need to say anything about this as it's all part of the standard literature.
</p><p><br/>
<b>Afterword</b></p><p>
As a side effect we have a general purpose optimisation algorithm that has nothing to do with statistics. If your goal is to compute
</p><blockquote>
<span class="legacy-equation-inline">\(\operatorname{argmax}_x\sum_i\exp(f_i(x))\)</span>
</blockquote>
you can iterate, at each step computing
<blockquote>
<span class="legacy-equation-inline">\(\operatorname{argmax}_x\sum_i\exp(f_i(x_0))f_i(x)\)</span>
</blockquote>
where <span class="legacy-equation-inline">\(x_0\)</span> is the previous iteration.
If the <span class="legacy-equation-inline">\(f_i\)</span> take a convenient form then this may turn out to be much easier.
<p><br/>
<b>Note</b></p><p>
This was originally written as a PDF using LaTeX. It'll be available <a href="https://t.co/hyZrCiAh6h">here</a> for a while. Some fidelity was lost when converting it to HTML.</p></div>
    </summary>
    <updated>2026-04-22T23:23:39Z</updated>
    <published>2016-10-16T23:04:00Z</published>
    <author>
      <name>sigfpe</name>
      <email>noreply@blogger.com</email>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-11295132</id>
      <category term="mathematics"/>
      <category term="haskell"/>
      <category term="physics"/>
      <category term="monad"/>
      <category term="programming"/>
      <category term="types"/>
      <category term="astronomy"/>
      <category term="quantum"/>
      <category term="comonads"/>
      <category term="self-reference"/>
      <category term="category theory"/>
      <category term="lawvere theories"/>
      <category term="optimisation"/>
      <category term="probability"/>
      <author>
        <name>sigfpe</name>
        <email>noreply@blogger.com</email>
      </author>
      <link href="http://blog.sigfpe.com/" rel="alternate" type="text/html"/>
      <link href="http://sigfpe.blogspot.com/rss.xml" rel="self" type="application/rss+xml"/>
      <title>A Neighborhood of Infinity</title>
      <updated>2026-05-19T09:26:13Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-11295132.post-8266076036196212490</id>
    <link href="http://blog.sigfpe.com/2017/02/logarithms-and-exponentials-of-functions.html" rel="alternate" type="text/html"/>
    <title>Logarithms and exponentials of functions</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><br/><b>Introduction</b><p>
A popular question in mathematics is this: given a function <span class="legacy-equation-inline">\(f\)</span>, what is its "square root" <span class="legacy-equation-inline">\(g\)</span> in the sense that <span class="legacy-equation-inline">\(g(g(x)) = f(x)\)</span>.
There are many questions about this on <a href="http://mathoverflow.net/questions/tagged/fractional-iteration">mathoverflow</a> but it's also a popular subject in mathematics forums for non-experts.
This question seems to have a certain amount of notoriety because it's easy to ask but hard to answer fully.
I want to look at an approach that works nicely for formal power series, following from the Haskell code I wrote <a href="http://blog.sigfpe.com/2007/11/small-combinatorial-library.html">here</a>.
There are some methods for directly finding "functional square roots" for formal power series that start as <span class="legacy-equation-inline">\(z a_2z^2 a_3z^3 \ldots\)</span>, but I want to approach the problem indirectly.
When working with real numbers we can find square roots, say, by using <span class="legacy-equation-inline">\(\sqrt{x}=\exp(\frac{1}{2}\log{x})\)</span>.
I want to use an analogue of this for functions.
So my goal is to make sense of the idea of the logarithm and exponential of a formal power series as composable functions.
Warning: the arguments are all going to be informal.
</p><p><br/>
<br/><b>Notation</b></p><p>
There's potential for a lot of ambiguous notation here, especially as the usual mathematical notation for <span class="legacy-equation-inline">\(n\)</span>th powers of trig functions is so misleading.
I'm going to use <span class="legacy-equation-inline">\(\circ\)</span> for composition of functions and power series, and I'm going to use the notation <span class="legacy-equation-inline">\(f^{\circ n}\)</span> to mean the <span class="legacy-equation-inline">\(n\)</span>th iterate of <span class="legacy-equation-inline">\(f\)</span>.
So <span class="legacy-equation-inline">\(f^{n 1}(x) = f(x)f^n(x)\)</span> and <span class="legacy-equation-inline">\(f^{\circ n 1}(x) = f(f^{\circ n}(x))\)</span>.
As I'll be working mostly in the ring of formal power series <span class="legacy-equation-inline">\(R[\![z]\!]\)</span> for some ring <span class="legacy-equation-inline">\(R\)</span>, I'll reserve the variable <span class="legacy-equation-inline">\(z\)</span> to refer only to the corresponding element in this ring.
I'll also use formal power series somewhat interchangeably with functions. So <span class="legacy-equation-inline">\(z\)</span> can be thought of as representing the identity function.
To make sure we're on the same page, here are some small theorems in this notation:
</p><ol><li><span class="legacy-equation-inline">\(z^mz^n = z^{m n}\)</span></li>
<li><span class="legacy-equation-inline">\(f^{\circ m}\circ f^{\circ n} = f^{\circ m n}\)</span></li>
<li><span class="legacy-equation-inline">\((1 z)^n = \sum_{i=0}^n{n\choose i}z^n\)</span></li>
<li><span class="legacy-equation-inline">\((1 z)^{\circ n}=n z\)</span>.</li>
</ol>
That last one simply says that adding one <span class="legacy-equation-inline">\(n\)</span> times is the same as adding <span class="legacy-equation-inline">\(n\)</span>.
<p><br/>
As I'm going to have ordinary logarithms and exponentials sitting around, as well as functional logarithms and exponentials, I'm going to introduce the notation <span class="legacy-equation-inline">\(\operatorname{LOG}\)</span> for functional logarithm and <span class="legacy-equation-inline">\(\operatorname{EXP}\)</span> for functional exponentiation.
</p><p><br/>
<br/><b>Preliminaries</b></p><p>
The first goal is to define a non-trivial function <span class="legacy-equation-inline">\(\operatorname{LOG}\)</span> with the fundamental property that <span class="legacy-equation-inline">\(\operatorname{LOG}(f^{\circ n})=n\operatorname{LOG}(f)\)</span>
</p><p><br/>
First, let's note some basic algebraic facts.
The formal power series form a commutative ring with operations <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=%2B" style="vertical-align: middle;"/> and <span class="legacy-equation-inline">\(\cdot\)</span> (ordinary multiplication) and with additive identity <span class="legacy-equation-inline">\(0\)</span> and multiplicative identity <span class="legacy-equation-inline">\(1\)</span>.
The formal power series form a ring-like algebraic structure with operation <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=%2B" style="vertical-align: middle;"/> and partial operation <span class="legacy-equation-inline">\(\circ\)</span> with additive identity <span class="legacy-equation-inline">\(0\)</span> and multiplicative identity <span class="legacy-equation-inline">\(z\)</span>.
But it's not actually ring or even a <a href="https://en.wikipedia.org/wiki/Near-ring">near-ring</a>.
Composition isn't defined for all formal power series and even when it's defined, we don't have distributivity.
For example, in general <span class="legacy-equation-inline">\(f\circ(g h)\ne f\circ g f\circ h\)</span>, after all there's no reason to expect <span class="legacy-equation-inline">\(f(g(x) h(x))\)</span> to equal <span class="legacy-equation-inline">\(f(g(x)) f(h(x))\)</span>.
We do have right-distributivity however, i.e.
</p><blockquote>
<span class="legacy-equation-inline">\((f g)\circ h = f\circ g f\circ h\)</span>,
</blockquote>
because
<blockquote>
<span class="legacy-equation-inline">\((f g)(h(x))=f(h(x)) g(h(x))\)</span>,
</blockquote>
more or less by definition of <img src="https://chart.googleapis.com/chart?cht=tx&amp;chl=%2B" style="vertical-align: middle;"/>.
<p><br/>
<br/><b>We can't use power series on our power series</b></p><p>
There's an obvious approach, just use power series of power series.
So we might tentatively suggest that
</p><blockquote>
<span class="legacy-equation-inline">\(\operatorname{LOG}(z f) = f-\frac{1}{2}f^{\circ 2} \frac{1}{3}f^{\circ 3} \ldots\)</span>.
</blockquote>
Note that I consider <span class="legacy-equation-inline">\(\operatorname{LOG}(z f)\)</span> rather than <span class="legacy-equation-inline">\(\operatorname{LOG}(1 f)\)</span> because <span class="legacy-equation-inline">\(z\)</span> is the multiplicative identity in our ring-like structure.
<p><br/>
Unfortunately this doesn't work.
The reason is this: if we try to use standard reasoning to show that the resulting function has the fundamental property we seek we end up using distributivity.
We don't have distributivity.
</p><p><br/>
<br/><b>Sleight of hand</b></p><p>
There's a beautiful trick I spotted on mathoverflow recently that allows us to bring back distributivity.
(I can't find the trick again, but when I do I'll come back and add a link and credit here.)
Consider the function <span class="legacy-equation-inline">\(R(g)\)</span> defined by <span class="legacy-equation-inline">\(R(g)(f) = f\circ g\)</span>.
In other words <span class="legacy-equation-inline">\(R(g)\)</span> is right-composition by <span class="legacy-equation-inline">\(g\)</span>.
(Ambiguity alert, I'm using <span class="legacy-equation-inline">\(R\)</span> here to mean <i>right</i>.
It has nothing to do with the ring underlying our formal power series.)
Because we have right-distributivity, <span class="legacy-equation-inline">\(R(g)\)</span> is a <i>bona fide</i> linear operator on the space of formal power series.
If you think of formal power series as being infinitely long vectors of coefficients then <span class="legacy-equation-inline">\(R(g)\)</span> can be thought of as an infinitely sized matrix.
This means that as long as we have convergence, we can get away with using power series to compute <span class="legacy-equation-inline">\(\log R(g)\)</span> with the property that <span class="legacy-equation-inline">\(\log(R(g)^n) = n\log R(g)\)</span>.
Define:
</p><blockquote>
<span class="legacy-equation-inline">\(\operator{LOG}(f) = \log(R(f))z\)</span>.
</blockquote>
We have:
<blockquote>
<span class="legacy-equation-inline">\(\operator{LOG}(f) = \log(R(f))z = \log(1 (R(f)-1))z\)</span>
</blockquote>
where I'm using <span class="legacy-equation-inline">\(1\)</span> to mean the identity linear operator.
And now have:
<blockquote>
<span class="legacy-equation-inline">\(\operator{LOG}(f) = (R(f)-1)z-\frac{1}{2}(R(f)-1)^2z \frac{1}{3}(R(f)-1)^3z \ldots\)</span>.
</blockquote>
But does it converge?
Suppose <span class="legacy-equation-inline">\(f\)</span> is of the form <span class="legacy-equation-inline">\(x a_2x^2 a_3x^3 \ldots\)</span>.
Then <span class="legacy-equation-inline">\((R(f)-1)g = g\circ f-g\)</span>.
The leading term in <span class="legacy-equation-inline">\(g\circ f\)</span> is the same as the leading term in <span class="legacy-equation-inline">\(g\)</span>.
So <span class="legacy-equation-inline">\(R(f)-1\)</span> kills the first term of whatever it is applied to, which means that when we sum the terms in <span class="legacy-equation-inline">\(\operatorname{LOG}(f)\)</span>, we only need <span class="legacy-equation-inline">\(n\)</span> to get a power series correct to <span class="legacy-equation-inline">\(n\)</span> coefficients.
Reusing my code from <a href="http://blog.sigfpe.com/2007/11/small-combinatorial-library.html">here</a>, I call <span class="legacy-equation-inline">\(\operatorname{LOG}\)</span> by the name <tt>flog</tt>.
Here is its implementation:
<p><br/>
</p><pre>&gt; import Data.Ratio
<p><br/>
&gt; flog :: (Eq a, Fractional a) =&gt; [a] -&gt; [a]
&gt; flog f@(0 : 1 : _) =
&gt;   flog' 1 (repeat 0) (0 : 1 : repeat 0)
&gt;      where flog' n total term = take (n+1) total ++ (
&gt;              drop (n+1) $
&gt;                 let pz = p term
&gt;                 in flog' (n+1) (total-map (((-1)^n / fromIntegral n) *) pz) pz)
&gt;            p total = (total ○ f) - total
</p><p><br/>
</p></pre>
The <tt>take</tt> and <tt>drop</tt> are how I tell Haskell when the first <span class="legacy-equation-inline">\(n 1\)</span> coefficients have been exactly computed and so no more terms are necessary.
<p><br/>
Does it work?
</p><p><br/>
Here's an example using the twice iterated sin function:
</p><p><br/>
</p><pre>&gt; ex1 = do
&gt;   let lhs = flog (sin (sin z))
&gt;   let rhs = 2*flog (sin z)
&gt;   mapM_ print $ take 20 (lhs-rhs)
<p><br/>
</p></pre>
Works to 20 coefficients. Dare we try an inverse function?
<p><br/>
</p><pre>&gt; ex2 = do
&gt;   let lhs = flog (sin z)
&gt;   let rhs = flog (asin z)
&gt;   mapM_ print $ take 20 (lhs+rhs)
<p><br/>
</p></pre>
Seems to work!
<p><br/>
<br/><b>Exponentials</b></p><p>
It's no good having logarithms if we can't invert them.
One way to think about the exponential function is that
</p><blockquote>
<span class="legacy-equation-inline">\(\exp(x) = \lim_{n\rightarrow \infty}(1 \frac{x}{n})^n\)</span>
</blockquote>
We get better and better approximations by writing the expression inside the limit as a product of more and more terms.
We can derive the usual power series for <span class="legacy-equation-inline">\(\exp\)</span> from this, but only if right-distributivity holds.
So let's try to use the above expression directly:
<blockquote>
<span class="legacy-equation-inline">\(\operatorname{EXP}(f) = \lim_{n\rightarrow \infty}(z \frac{f}{n})^{\circ n}\)</span>
</blockquote>
and get
<blockquote>
<span class="legacy-equation-inline">\(\operatorname{EXP}(f) = \lim_{n\rightarrow \infty}R(z \frac{f}{n})^nz\)</span>.
</blockquote>
Unfortunately, even though <span class="legacy-equation-inline">\(R(g)\)</span> is linear, <span class="legacy-equation-inline">\(R\)</span> itself isn't.
So it's going to take some extra work to raise <span class="legacy-equation-inline">\(R(z f/n)\)</span> to the power of <span class="legacy-equation-inline">\(n\)</span>.
<p><br/>
The good news is that we're dealing with the special case <span class="legacy-equation-inline">\(R(z \epsilon)\)</span> where <span class="legacy-equation-inline">\(\epsilon\)</span> is something small.
We have
</p><blockquote>
<span class="legacy-equation-inline">\(R(z \epsilon)f=f(z \epsilon)=f(z) \epsilon\frac{df}{dz} O(\epsilon^2)\)</span>.
</blockquote>
So <span class="legacy-equation-inline">\(R(z f/n)\)</span> is actually <span class="legacy-equation-inline">\(1 \frac{1}{n}f\frac{d}{dz}\)</span> modulo higher order terms.
This gives us
<blockquote>
<span class="legacy-equation-inline">\(\operatorname{EXP}(f) = \lim_{n\rightarrow \infty}(1 \frac{1}{n}f\frac{d}{dz})^nz=\exp(f\frac{d}{dz})z\)</span>.
</blockquote>
This is something we can implement using the power series for ordinary <span class="legacy-equation-inline">\(\exp\)</span>:
<blockquote>
<span class="legacy-equation-inline">\(\operatorname{EXP}(f) = z f \frac{1}{2!}f\frac{df}{dz} \frac{1}{3!}f\frac{d}{dz}(f\frac{df}{dz}) \ldots\)</span>.
</blockquote>
In code that becomes:
<p><br/>
</p><pre>&gt; fexp f@(0 : 0 : _) = fexp' f 0 z 1
&gt; fexp' f total term n = take (n-1) total ++ drop (n-1)
&gt;           (fexp' f (total+term) (map (/fromIntegral n) (f*d term)) (n+1))
<p><br/>
</p></pre>
Note how when we differentiate a power series we shift the coefficients down by one place.
To counter the effect of that so as to ensure convergence we need <span class="legacy-equation-inline">\(f\)</span> to look like <span class="legacy-equation-inline">\(a_2z^2 a_3a^3 \ldots\)</span>.
Luckily this is exactly the kind of series <span class="legacy-equation-inline">\(\operatorname{LOG}\)</span> gives us.
<p><br/>
But does it successfully invert <span class="legacy-equation-inline">\(\operatorname{LOG}\)</span>?
Let's try:
</p><p><br/>
</p><pre>&gt; ex3 = do
&gt;   let lhs = sin z
&gt;   let rhs = fexp (flog (sin z))
&gt;   mapM_ print $ take 20 (lhs-rhs)
<p><br/>
</p></pre>
Now we can start computing fractional iterates.
Square root first:
<p><br/>
</p><pre>&gt; ex4 = do
&gt;   mapM_ print $ take 20 $ fexp (flog (sin z)/2)
<p><br/>
</p></pre>
That matches the results at <a href="http://oeis.org/A048602">A048602</a> and <a href="http://oeis.org/A048603">A048603</a>.
<p><br/>
Cube root:
</p><p><br/>
</p><pre>&gt; ex5 = do
&gt;   mapM_ print $ take 20 $ fexp (flog (sin z)/3)
<p><br/>
</p></pre>
Matches <a href="http://oeis.org/A052132">A052132</a> and <a href="http://oeis.org/A052135">A052135</a>.
<p><br/>
And this gives an alternative to Lagrange inversion for computing power series for inverse functions:
</p><p><br/>
</p><pre>&gt; ex6 = do
&gt;   let lhs = fexp (-flog (sin z))
&gt;   let rhs = asin z
&gt;   mapM_ print $ take 20 (lhs-rhs)
<p><br/>
</p></pre>
<br/><b>What's really going on with <span class="legacy-equation-inline">\(\operatorname{EXP}\)</span>?</b><p>
Let's approach <span class="legacy-equation-inline">\(\operatorname{EXP}\)</span> in a slightly different way.
In effect, <span class="legacy-equation-inline">\(\operatorname{EXP}\)</span> is the composition of <span class="legacy-equation-inline">\(n\)</span> lots of <span class="legacy-equation-inline">\(z \frac{f}{n}\)</span> with <span class="legacy-equation-inline">\(z\)</span>.
So let's try composing these one at a time, with one composition every <span class="legacy-equation-inline">\(\frac{1}{n}\)</span> seconds.
After one second we should have our final result.
We can write this as:
</p><blockquote>
<span class="legacy-equation-inline">\(g(0) = z\)</span> and <span class="legacy-equation-inline">\(g(t \frac{1}{n}) = g(t) \frac{1}{n}f(g(t))\)</span> to first order.
</blockquote>
So we're solving the differential equation:
<blockquote>
<span class="legacy-equation-inline">\(g(0) = z\)</span> and <span class="legacy-equation-inline">\(\frac{dg}{dt} = f(g(t))\)</span>
</blockquote>
with <span class="legacy-equation-inline">\(\operatorname{EXP}(g) = g(1)\)</span>.
<p><br/>
So <span class="legacy-equation-inline">\(\operatorname{EXP}\)</span> is the function that solves one of the most fundamental differential equations.
This also means I can use Mathematica to solve symbolically and check my results.
For example, Mathematica says that the solution to
</p><blockquote>
<span class="legacy-equation-inline">\(\frac{dg}{dt}=sin(g(t))^2\)</span> and <span class="legacy-equation-inline">\(g(0)=x\)</span>
</blockquote>
at <span class="legacy-equation-inline">\(t=1\)</span> is
<blockquote>
<span class="legacy-equation-inline">\(g(1) = \frac{\tan z}{1-\tan z}\)</span>
</blockquote>
so let's check:
<p><br/>
</p><pre>&gt; ex7 = do
&gt;   let lhs = fexp ((sin z)^2)
&gt;   let rhs = atan (tan z/(1-tan z))
&gt;   mapM_ print $ take 20 (lhs-rhs)
<p><br/>
</p></pre>
I like this example because it leads to the generalized Catalan numbers <a href="http://oeis.org/A004148">A004148</a>:
<p><br/>
</p><pre>&gt; ex8 = do
&gt;     mapM_ print $ take 20 $ fexp (z^2/(1-z^2))
<p><br/>
</p></pre>
That suggests this question: what does <span class="legacy-equation-inline">\(\operatorname{EXP}\)</span> mean combinatorially?
I don't have a straightforward answer but solving this class of differential equation motivated the original introduction, by Cayley, of the abstract notion of a tree.
See <a href="https://arxiv.org/abs/1512.00906">here</a>.
<p><br/>
<br/><b>What is going on geometrically?</b></p><p>
For those who know some differential geometry,
The differential equation
</p><blockquote>
<span class="legacy-equation-inline">\(g(0) = z\)</span> and <span class="legacy-equation-inline">\(\frac{dg}{dt} = f(g(t))\)</span>
</blockquote>
describes a flow on the real line (or complex plane).
You can think of <span class="legacy-equation-inline">\(f\)</span> as being a one-dimensional vector field describing how points move from time <span class="legacy-equation-inline">\(t\)</span> to <span class="legacy-equation-inline">\(t dt\)</span>.
When we solve the differential equation we get <a href="https://en.wikipedia.org/wiki/Integral_curve">integral curves</a> that these points follow and <span class="legacy-equation-inline">\(\operatorname{EXP}\)</span> tells us where the points end up after one unit of time.
So <span class="legacy-equation-inline">\(\operatorname{EXP}\)</span> is the <a href="https://en.wikipedia.org/wiki/Exponential_map_%28Riemannian_geometry%29">exponential map</a>.
In fact, <span class="legacy-equation-inline">\(\operatorname{EXP}(f)=\exp(f\frac{d}{dz})z\)</span> is essentially the exponential of the vector field <span class="legacy-equation-inline">\(f\frac{d}{dz}\)</span> where we're now using the differential geometer's notion of a vector field as a differential operator.
<p><br/>
<br/><b>Final word</b></p><p>
Unfortunately the power series you get from using <span class="legacy-equation-inline">\(\operator{LOG}\)</span> and <span class="legacy-equation-inline">\(\operator{EXP}\)</span> don't always have good convergence properties.
For example, I'm not sure but I think the series for <span class="legacy-equation-inline">\(\sin^{\circ 1/2} z\)</span> has radius of convergence zero.
If you truncate the series you get a half-decent approximaion to a square root in the vicinity of the origin, but the approximation gets worse, not better, if you use more terms.
</p><p><br/>
<br/><b>And the rest of the code</b></p><p>
</p><p><br/>
</p><pre>&gt; (*!) _ 0 = 0
&gt; (*!) a b = a*b
&gt; (!*) 0 _ = 0
&gt; (!*) a b = a*b
&gt; (^+) a b = zipWith (+) a b
&gt; (^-) a b = zipWith (-) a b
<p><br/>
&gt; ~(a:as) ⊗ (b:bs) = (a *! b):
&gt;     ((map (a !*) bs) ^+ (as ⊗ (b:bs)))
&gt; (○) (f:fs) (0:gs) = f:(gs ⊗ (fs ○ (0:gs)))
&gt; inverse (0:f:fs) = x where x     = map (recip f *) (0:1:g)
&gt;                            _:_:g    = map negate ((0:0:fs) ○ x)
&gt; invert x = r where r = map (/x0)  ((1:repeat 0) ^- (r ⊗ (0:xs)))
&gt;                    x0:xs = x 
</p><p><br/>
&gt; (^/) (0:a) (0:b) = a ^/ b
&gt; (^/) a b = a ⊗ (invert b)
</p><p><br/>
&gt; z :: [Rational]
&gt; z = 0:1:repeat 0
</p><p><br/>
&gt; d (_:x) = zipWith (*) (map fromInteger [1..]) x
</p><p><br/>
&gt; integrate x = 0 : zipWith (/) x (map fromInteger [1..])
</p><p><br/>
&gt; instance (Eq r, Num r) =&gt; Num [r] where
&gt;     x+y  = zipWith (+) x y
&gt;     x-y  = zipWith (-) x y
&gt;     ~x*y = x ⊗ y
&gt;     fromInteger x      = fromInteger x:repeat 0
&gt;     negate x     = map negate x
&gt;     signum (x:_) = signum x : repeat 0
&gt;     abs (x:xs)   = error "Can't form abs of a power series"
</p><p><br/>
&gt; instance (Eq r, Fractional r) =&gt; Fractional [r] where
&gt;     x/y = x ^/ y
&gt;     fromRational x    = fromRational x:repeat 0
</p><p><br/>
&gt; sqrt' x = 1 : rs where rs = map (/2) (xs ^- (rs ⊗ (0:rs)))
&gt;                        _ : xs = x
&gt; instance (Eq r, Fractional r) =&gt; Floating [r] where
&gt;     sqrt (1 : x) = sqrt' (1 : x)
&gt;     sqrt _  = error "Can only find sqrt when leading term is 1"
&gt;     exp x   = e where e = 1+integrate (e * d x)
&gt;     log x   = integrate (d x/x)
&gt;     sin x   = integrate ((cos x)*(d x))
&gt;     cos x   = [1] ... negate (integrate ((sin x)*(d x)))
&gt;     asin x  = integrate (d x/sqrt(1-x*x))
&gt;     atan x  = integrate (d x/(1+x*x))
&gt;     acos x  = error "Unable to form power series for acos"
&gt;     sinh x  = integrate ((cosh x)*(d x))
&gt;     cosh x  = [1] ... integrate ((sinh x)*(d x))
&gt;     asinh x = integrate (d x/sqrt(1+x*x))
&gt;     atanh x = integrate (d x/(1-x*x))
&gt;     acosh x = error "Unable to form power series for acosh"
&gt;     pi      = error "There is no formal power series for pi"
</p><p><br/>
&gt; lead [] x = x
&gt; lead (a:as) x = a : (lead as (tail x))
&gt; a ... x = lead a x
</p><p><br/>
&gt; (//) :: Fractional a =&gt; [a] -&gt; (Integer -&gt; Bool) -&gt; [a]
&gt; (//) a c = zipWith (\a-&gt; \b-&gt;(if (c a :: Bool) then b else 0)) [(0::Integer)..] a
</p><p><br/>
</p></pre>
A direct functional square root that doesn't use <span class="legacy-equation-inline">\(\operatorname{LOG}\)</span> and <span class="legacy-equation-inline">\(\operatorname{EXP}\)</span>:
<p><br/>
</p><pre>&gt; fsqrt (0 : 1 : fs) =
&gt;     let gs = (fs-(0 : gs*((0 : delta gs gs)+((2 : gs)*(gs*g)))))/2
&gt;         g = 0 : 1 : gs
&gt;         delta (g : gs) h = let g' = delta gs h
&gt;                    in (0 : ((1 : h) * g')) + gs
&gt;     in g
</pre></div>
    </summary>
    <updated>2026-04-22T23:16:27Z</updated>
    <published>2017-02-05T18:30:00Z</published>
    <author>
      <name>sigfpe</name>
      <email>noreply@blogger.com</email>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-11295132</id>
      <category term="mathematics"/>
      <category term="haskell"/>
      <category term="physics"/>
      <category term="monad"/>
      <category term="programming"/>
      <category term="types"/>
      <category term="astronomy"/>
      <category term="quantum"/>
      <category term="comonads"/>
      <category term="self-reference"/>
      <category term="category theory"/>
      <category term="lawvere theories"/>
      <category term="optimisation"/>
      <category term="probability"/>
      <author>
        <name>sigfpe</name>
        <email>noreply@blogger.com</email>
      </author>
      <link href="http://blog.sigfpe.com/" rel="alternate" type="text/html"/>
      <link href="http://sigfpe.blogspot.com/rss.xml" rel="self" type="application/rss+xml"/>
      <title>A Neighborhood of Infinity</title>
      <updated>2026-05-19T09:26:13Z</updated>
    </source>
  </entry>

  <entry>
    <id>https://tweag.io/blog/2026-04-16-doc-it-like-its-hot/</id>
    <link href="https://tweag.io/blog/2026-04-16-doc-it-like-its-hot/" rel="alternate" type="text/html"/>
    <title>ð�•¯ð�–”ð�–ˆ ð�–Žð�–™ ð�–‘ð�–Žð�–�ð�–Š ð�–Žð�–™'ð�–˜ ð�–�ð�–”ð�–™</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><div class="lyrics">
<p><span class="gatsby-resp-image-wrapper" style="display: block; margin-left: auto; margin-right: auto;">
      <a class="gatsby-resp-image-link" href="https://www.tweag.io/static/762ffa5f48916f2ae5059d549abae602/5ff7e/pharrell-1.png" rel="noopener" style="display: block;" target="_blank">
    <span class="gatsby-resp-image-background-image" style="padding-bottom: 100%; display: block;"/>
  <img alt="Pharrell" class="gatsby-resp-image-image" src="https://www.tweag.io/static/762ffa5f48916f2ae5059d549abae602/5ff7e/pharrell-1.png" style="width: 100%; height: 100%; margin: 0; vertical-align: middle;" title="Pharrell"/>
  </a>
    </span></p>
<blockquote>
<p>You’ve got some nice code. That’s a nice trie. <br/>
I see those PRs. But no <code class="language-text">README</code>?</p>
</blockquote>
</div>
<p>Everybody knows documentation is essential to any software engineering
enterprise. And fo’ shizzle, everybody knows it gets deprioritised. An
afterthought; written by engineers who are thinking, “I should probably
write docs”. Nah. What they <em>should</em> be thinking is, “I <em>get</em> to write
docs, cuz!” Because when you doc it right, it ain’t a chore. It’s what
separates a project people use from a project people lose.</p>
<p>In this post, I’m walkin’ you through three real projects I’ve been
involved in at Tweag; each one levelling up the documentation game.
First, fixing docs that got out of hand: the reactive play. Then,
planning docs from day one: the <i>pro</i>active play. And finally,
making docs part of the code itself: the integrated play. By the end, I
think you’ll agree: to doc it like it’s hot is the only way to gizzo.</p>
<h2 id="when-your-readmes-a-monolith"><a class="anchor before" href="https://www.tweag.io/rss.xml#when-your-readmes-a-monolith"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>When your <code class="language-text">README</code>’s a monolith</h2>
<div class="lyrics">
<p><span class="gatsby-resp-image-wrapper" style="display: block; margin-left: auto; margin-right: auto;">
      <a class="gatsby-resp-image-link" href="https://www.tweag.io/static/4c6ea454e851d06070b463adc975197b/e45a9/snoop-1.png" rel="noopener" style="display: block;" target="_blank">
    <span class="gatsby-resp-image-background-image" style="padding-bottom: 100%; display: block;"/>
  <img alt="Snoop Dogg" class="gatsby-resp-image-image" src="https://www.tweag.io/static/4c6ea454e851d06070b463adc975197b/e45a9/snoop-1.png" style="width: 100%; height: 100%; margin: 0; vertical-align: middle;" title="Snoop Dogg"/>
  </a>
    </span></p>
<blockquote>
<p>Doc it like it’s hot</p>
</blockquote>
</div>
<p>Sometimes the docs are already a mess and you gotta clean house. That’s
the reactive play.</p>
<p>That was the case with <a href="https://topiary.tweag.io">Topiary</a>, Tweag’s universal formatting engine.
It uses Tree-sitter grammars and queries to format code; encoded in what
Tree-sitter calls “capture names”. All of our formatting capture names
needed to be documented, with their semantics described.</p>
<p>Moreover, our documentation covered usage instructions, which were
checked against the <code class="language-text">--help</code> output of each subcommand. Then there was
our project motivation and design philosophy, language support,
installation instructions, configuration details, usage guides…</p>
<p>…All in a single <code class="language-text">README.md</code> which had grown to over 7,000 words. Way
too big for the crib, homes. Ain’t nobody reading all that!</p>
<p>Drift and inconsistency were creeping in, making it harder for the team
to maintain. Worse, it was straight-up hostile to users: how you gonna
expect someone to sift through all that noise just to find what they
need?</p>
<p>Topiary OG Erin started work reconstructing the monolith into a book
format using — as it’s a Rust project — <a href="https://rust-lang.github.io/mdBook">mdBook</a>. I picked up where he
left off and finished it for Topiary v0.6.1. Yo, the <a href="https://topiary.tweag.io/book">Topiary Book</a> was
born!</p>
<p>But the move here wasn’t just splitting up the <code class="language-text">README.md</code> and calling
it a day. You need a crew and every member needs a role. That means a
framework; something to keep it tight, maintainable and user-friendly.
We rolled with <a href="https://diataxis.fr">Diátaxis</a>, which identifies four distinct documentation
types based on what the reader actually needs:</p>
<ul>
<li><strong>Tutorials</strong>, for learners. For example, <a href="https://topiary.tweag.io/book/guides/yann-tutorial.html">Yann’s step-by-step
guides</a> walk readers through creating a
formatter from scratch for a toy language, starting from zero. Its aim
is to actively reach understanding through engagement, rather than
just passive reading.</li>
<li><strong>How-to guides</strong>, for readers who want to accomplish a specific goal.
<a href="https://topiary.tweag.io/book/guides/adding-a-new-language.html">“Adding a new language”</a> assumes you already know
Topiary and gets straight to the point: register the grammar, create a
query file, update the test suite, rinse and repeat.</li>
<li><strong>Explanation</strong>, for those who need a deeper understanding. For
example, <a href="https://topiary.tweag.io/book/getting-started/on-tree-sitter.html">“Tree-sitter and its queries”</a> explains
the conceptual foundation — what Tree-sitter is, why Topiary uses it
and how queries relate to formatting — without asking the reader to
do anything.</li>
<li><strong>Reference</strong>, which describes what exists and how it behaves. Our
<a href="https://topiary.tweag.io/book/reference/capture-names/index.html">capture names chapter</a> documents every formatting
directive Topiary recognises, what it does, its syntax and its edge
cases. You’re not meant to read it cover-to-cover; it’s just there to
look up whenever you need it.</li>
</ul>
<p>Structure is a prerequisite for usefulness and frameworks exist so you
don’t have to invent your own. Rolling your own ain’t gangsta, use
what’s already out there…that’s real game.</p>
<h2 id="when-you-have-varied-audiences"><a class="anchor before" href="https://www.tweag.io/rss.xml#when-you-have-varied-audiences"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>When you have varied audiences</h2>
<div class="lyrics">
<p><span class="gatsby-resp-image-wrapper" style="display: block; margin-left: auto; margin-right: auto;">
      <a class="gatsby-resp-image-link" href="https://www.tweag.io/static/7af1ae3c9dc85afd82ec8bc9200ce7de/50ac3/snoop-2.png" rel="noopener" style="display: block;" target="_blank">
    <span class="gatsby-resp-image-background-image" style="display: block;"/>
  <img alt="Snoop Dogg" class="gatsby-resp-image-image" src="https://www.tweag.io/static/7af1ae3c9dc85afd82ec8bc9200ce7de/50ac3/snoop-2.png" style="width: 100%; height: 100%; margin: 0; vertical-align: middle;" title="Snoop Dogg"/>
  </a>
    </span></p>
<blockquote>
<p>Doc it like it’s hot</p>
</blockquote>
</div>
<p>Cleaning up after the fact is one thing, but why not come correct from
the start? That’s the proactive play: before you write a line of
documentation, you ask who’s gonna read it and what they need. Then you
build the structure around that.</p>
<p>So, while Topiary is a developer productivity tool with, broadly, a
developer audience, the second project I want to chop it up about is
different: an <a href="https://en.wikipedia.org/wiki/Omics">omics</a> data acquisition tool for a pharmaceutical
client’s computational biology needs.</p>
<p>This one had a whole different crowd to please. Bioinformaticians
running data processing pipelines, IT staff handling installation and
access control, administrators guiding users through workflows and
developers who might extend the project down the line…including,
potentially, yours truly, after returning from a long absence and having
forgotten how everything works!</p>
<p>Their needs, vocabulary and assumptions barely overlap, so a single set
of docs couldn’t serve them all without becoming an unfocused sprawl.
So I split the documentation three ways:</p>
<ul>
<li>A <strong>technical manual</strong>, covering every subcommand, flag and
configuration key. The kind of thing a user reaches for mid-pipeline,
an administrator references when guiding colleagues, or IT consults
when setting up the environment.</li>
<li>A <strong>developer manual</strong>, as its mirror image: module architecture, type
hierarchies, testing methodology and contribution workflow. All you
need to dig the codebase, but were too shook to ask!</li>
<li>A <strong>user manual</strong> sat between the two, covering key concepts, how-to
guides and troubleshooting. <a href="https://diataxis.fr">Diátaxis</a> was again the guiding framework
here: the concepts section is explanation, the how-to guides are
exactly that and the troubleshooting page addresses the practical edge
cases that tripped people up during user acceptance testing.</li>
</ul>
<p>Within the user manual, I also got to indulge in what you’ve probably
gathered is my favourite move. I weaved in a narrative through the
examples that borrowed — with some artistic licence — from Stevenson’s
<a href="https://en.wikipedia.org/wiki/Strange_Case_of_Dr_Jekyll_and_Mr_Hyde">Strange Case of Dr. Jekyll and Mr. Hyde</a>: An external
collaborator’s data arrives from Dr. Jekyll’s lab, making oblique
references to the novella throughout, and ultimately identifying the
<code class="language-text">evil-transcriptome</code> for downstream analysis.</p>
<p>Does this make the documentation sillier than it needs to be? Maybe. But
it makes the examples stick…and that ain’t just a vibe, it’s science,
dawg: our brains are straight-up wired to retain information delivered
<a href="https://en.wikipedia.org/wiki/Transportation_theory_(psychology)">through narrative</a> far better than through
isolated facts. A reader who skimmed the manual a month ago can still
go, “that’s the example where forward and reverse reads are named ‘front
door’ and ‘back door’” and find the section again. The story gives
continuity across otherwise disconnected examples; where each section
could stand alone, the recurring characters give readers a reason to
follow the arc from data acquisition to analysis. And the scenario is
deliberately awkward, which exercises more features than a vanilla
example ever could.</p>
<p>Different people need different things, that’s just how it is. A
bioinformatician never needs to know how the S3 client interface is
structured, just as a future developer doesn’t need a walkthrough of
dataset creation from <abbr title="National Center for Biotechnology Information">NCBI</abbr> metadata. When your audiences are distinct
enough, the realest thing you can do is acknowledge that up front,
rather than forcing everyone to wade through what ain’t for them…and
there’s never any harm in bringing a little levity into the world!</p>
<h2 id="when-you-need-to-have-clarity"><a class="anchor before" href="https://www.tweag.io/rss.xml#when-you-need-to-have-clarity"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>When you need to have clarity</h2>
<div class="lyrics">
<p><span class="gatsby-resp-image-wrapper" style="display: block; margin-left: auto; margin-right: auto;">
      <a class="gatsby-resp-image-link" href="https://www.tweag.io/static/77a4393a83eda677c52710aa429a9022/39e45/snoop-3.png" rel="noopener" style="display: block;" target="_blank">
    <span class="gatsby-resp-image-background-image" style="padding-bottom: 100%; display: block;"/>
  <img alt="Snoop Dogg" class="gatsby-resp-image-image" src="https://www.tweag.io/static/77a4393a83eda677c52710aa429a9022/39e45/snoop-3.png" style="width: 100%; height: 100%; margin: 0; vertical-align: middle;" title="Snoop Dogg"/>
  </a>
    </span></p>
<blockquote>
<p>Doc it like it’s hot</p>
</blockquote>
</div>
<p>Planning ahead is smooth, but the smoothest move of all? Making the docs
and the code one and the same. That’s the integrated play.</p>
<p>The previous case study included a developer manual, but my final
example? That’s <em>all</em> developer; front to back. <a href="https://crates.io/crates/cardano-scrawls">Scrawls</a> is a Rust
library implementing a verifiable file format for <a href="https://cardano.org">Cardano</a> ledger
state, as an independent implementation alongside a <a href="https://github.com/tweag/cardano-cls">Haskell
reference</a>. Its users are Rust developers pulling in the
crate as a dependency, so the documentation strategy needed to reflect
that.</p>
<p>In Rust, the idiomatic answer to this is <a href="https://doc.rust-lang.org/rustdoc">rustdoc</a>: in-band
documentation that lives alongside the types, functions and invariants
it describes. Then, while there is still a <code class="language-text">README.md</code>, it functions
more as a landing page than a manual: a brief orientation, a feature
summary and a handful of examples to get a new user from zero to
something.</p>
<p>Docstrings ain’t new, of course — <a href="https://www.doxygen.nl">Doxygen</a> has been around since the
’90s — but Rust’s ecosystem raises the bar. Between <a href="https://docs.rs">docs.rs</a>
publishing your crate’s documentation automatically and a community that
straight-up expects thorough doc comments, skipping them feels less like
a shortcut and more like showing up empty-handed. So, when the API
changes, the respective documentation change should be right there in
the diff, for reviewers to keep it real.</p>
<p>And here’s the thing: during implementation, the specification was still
maturing and encoding its requirements into Rust exposed ambiguities
that were lurking in the prose. Should certain orderings be strict? How
should the Merkle tree be rolled up? Is this field optional, or merely
absent? Each ambiguity became a clarification fed back into the spec.
And each clarification, a documented precondition in the API.</p>
<p>A specification is, at the end of the day, documentation too…and the
same principle applies: vagueness is a bug. This ain’t documentation as
prose; it’s documentation as a contract, forged on the streets between
spec and implementation. Sometimes the most valuable work you can do is
keep it tight, not make it long.</p>
<h2 id="document-your-code-ma"><a class="anchor before" href="https://www.tweag.io/rss.xml#document-your-code-ma"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>Document your code, ma</h2>
<div class="lyrics">
<p><span class="gatsby-resp-image-wrapper" style="display: block; margin-left: auto; margin-right: auto;">
      <a class="gatsby-resp-image-link" href="https://www.tweag.io/static/d4779a85b30d02db57f93f6d6205dafb/5ff7e/pharrell-2.png" rel="noopener" style="display: block;" target="_blank">
    <span class="gatsby-resp-image-background-image" style="padding-bottom: 100%; display: block;"/>
  <img alt="Pharrell" class="gatsby-resp-image-image" src="https://www.tweag.io/static/d4779a85b30d02db57f93f6d6205dafb/5ff7e/pharrell-2.png" style="width: 100%; height: 100%; margin: 0; vertical-align: middle;" title="Pharrell"/>
  </a>
    </span></p>
<blockquote>
<p>That’s how you get ahizzead</p>
</blockquote>
</div>
<p>Reactive. Proactive. Integrated. Three different plays for three
different games…though ideally you won’t need the first! And what ties
them all together is that none of the documentation I’ve described was
written reluctantly. It wasn’t tacked on after the fact because someone
asked, “Where are the docs?” It was thought about — its structure, its
audience, its precision — as part of the work itself.</p>
<p>That’s the shift I want to put you on to. Documentation ain’t a tax you
pay for writing code; it <em>is</em> part of writing code. And when you
approach it that way — when you reach for a framework instead of a
blank page; when you ask “who’s this for?” before you start typing; when
you treat ambiguity as a bug — then you’re doc’ing it like it’s hot!
The result is something you’re genuinely proud of, not something you
hope nobody reads too carefully.</p>
<p>Now if documentation alongside code is good, then documentation <em>before</em>
code — as a design tool; a sketch in prose before you commit to
implementation — is the next level. While I ain’t taken that step
myself, my Scrawls experience, where the spec and the code kept each
other honest, showed me how close that workflow already is.</p>
<p>In practice, pure docs-first has the same problem as pure test-driven
development: you can’t document what you don’t know yet. But that
feedback loop — where the docs sharpen the code and the code sharpens
the docs — that’s the real endgame right there. You might notice this
sounds a bit like vibe-coding, and it is…in the same way that an
architect’s blueprint is a bit like a napkin sketch. Same ‘hood,
different zip codes, dawg. Something to aspire to, fo’ shizzle.</p>
<p>So now, just like my man S-to the N-to the double O-P, you too can
say…</p>
<div class="lyrics">
<p><span class="gatsby-resp-image-wrapper" style="display: block; margin-left: auto; margin-right: auto;">
      <a class="gatsby-resp-image-link" href="https://www.tweag.io/static/f0d351ee79b57822b54a1ff8abcdc0d0/d4635/snoop-4.png" rel="noopener" style="display: block;" target="_blank">
    <span class="gatsby-resp-image-background-image" style="display: block;"/>
  <img alt="Snoop Dogg" class="gatsby-resp-image-image" src="https://www.tweag.io/static/f0d351ee79b57822b54a1ff8abcdc0d0/d4635/snoop-4.png" style="width: 100%; height: 100%; margin: 0; vertical-align: middle;" title="Snoop Dogg"/>
  </a>
    </span></p>
<blockquote>
<p>I got a Rollie on my arm and I’m pourin’ Chandon <br/>
And I write the best docs, ‘cause I got it goin’ on.</p>
</blockquote>
</div>

<section class="acknowledgements">
<p>With thanks to Simeon Carstens, Facundo Domínguez, Valentin Gagarin,
Xavier Góngora, Arnaud Spiwack, Snoop Dogg and Pharrell Williams for
their reviews and input on this post.</p>
</section>

</div>
    </summary>
    <updated>2026-04-16T00:00:00Z</updated>
    <published>2026-04-16T00:00:00Z</published>
    <source>
      <id>https://tweag.io</id>
      <author>
        <name>Tweag I/O</name>
      </author>
      <link href="https://tweag.io" rel="alternate" type="text/html"/>
      <link href="http://www.tweag.io/rss.xml" rel="self" type="application/rss+xml"/>
      <subtitle>Scale your engineering power. We enable deep-tech startups to achieve
their vision, from research to product delivery.</subtitle>
      <title>Tweag - Engineering blog</title>
      <updated>2026-06-12T11:01:45Z</updated>
    </source>
  </entry>

  <entry xml:lang="en-us">
    <id>Buzzsprout-18995056</id>
    <link href="https://www.buzzsprout.com/1817535/episodes/18995056-80-popl-2026-part-1.mp3" length="30930364" rel="enclosure" type="audio/mpeg"/>
    <title>80: POPL 2026 - Part 1</title>
    <summary>This is the first part of a miniseries on this year’s Symposium on Principles of Programming Languages, a.k.a. POPL 2026, hosted by Jessica Foster.  In this episode, we talk about: undergrad funding and participation, the behind the scenes of AV, choreographic programming, quantum languages, conference catering, and the joy of theory. And at one point, you’ll even hear us get kicked out the venue mid interview. Enjoy!</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>This is the first part of a miniseries on this year’s Symposium on Principles of Programming Languages, a.k.a. POPL 2026, hosted by Jessica Foster.<br/><br/>In this episode, we talk about: undergrad funding and participation, the behind the scenes of AV, choreographic programming, quantum languages, conference catering, and the joy of theory. And at one point, you’ll even hear us get kicked out the venue mid interview. Enjoy!</p></div>
    </content>
    <updated>2026-04-13T05:00:00Z</updated>
    <published>2026-04-13T05:00:00Z</published>
    <author>
      <name>Haskell Podcast</name>
    </author>
    <source>
      <id>https://haskell.foundation/podcast/</id>
      <logo>https://storage.buzzsprout.com/tnk1ztokn5vmeiufqmr4kkp37mw2?.jpg</logo>
      <category scheme="http://www.itunes.com/" term="Technology"/>
      <author>
        <name>Haskell Podcast</name>
      </author>
      <link href="https://rss.buzzsprout.com/1817535.rss" rel="self" type="application/rss+xml"/>
      <link href="https://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="https://haskell.foundation/podcast/" rel="alternate" type="text/html"/>
      <rights>Â© 2026 The Haskell Interlude</rights>
      <subtitle>This is the Haskell Interlude, where the five co-hosts (Wouter Swierstra, Andres LÃ¶h, Alejandro Serrano, Niki Vazou, and Joachim Breitner) chat with Haskell guests!</subtitle>
      <title>The Haskell Interlude</title>
      <updated>2026-05-19T12:36:05Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-9757377.post-3700094658306171494</id>
    <link href="https://wadler.blogspot.com/feeds/3700094658306171494/comments/default" rel="replies" title="Post Comments" type="application/atom+xml"/>
    <link href="https://www.blogger.com/comment/fullpage/post/9757377/3700094658306171494" rel="replies" title="0 Comments" type="text/html"/>
    <link href="https://www.blogger.com/feeds/9757377/posts/default/3700094658306171494" rel="edit" type="application/atom+xml"/>
    <link href="https://www.blogger.com/feeds/9757377/posts/default/3700094658306171494" rel="self" type="application/atom+xml"/>
    <link href="https://wadler.blogspot.com/2026/04/wet-sidewalks-and-odd-numbers.html" rel="alternate" title="Wet Sidewalks and Odd Numbers" type="text/html"/>
    <title>Wet Sidewalks and Odd Numbers</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p/><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEij_CIKOMnrRH3Aa4_K7emngkVT1D39qIa_4v8foa-HMuWLPQMR8BL7kHbLbO1luZz7XK_8WKvHatJctvdSqo6LBXgKtENq55oDuLCgCBD8HdFXlup_VPR66psESR0Kjh9YQh6R0FXNPfRmBqWg5K33tmPdM28ArIxzvbEtC2VWHMpyFV2OsUwR" style="margin-left: 1em; margin-right: 1em;"><img alt="" height="334" src="https://blogger.googleusercontent.com/img/a/AVvXsEij_CIKOMnrRH3Aa4_K7emngkVT1D39qIa_4v8foa-HMuWLPQMR8BL7kHbLbO1luZz7XK_8WKvHatJctvdSqo6LBXgKtENq55oDuLCgCBD8HdFXlup_VPR66psESR0Kjh9YQh6R0FXNPfRmBqWg5K33tmPdM28ArIxzvbEtC2VWHMpyFV2OsUwR=w640-h334" width="640"/></a></div><br/>Phil Crissman <a href="https://philcrissman.net/posts/wet-sidewalks-and-odd-numbers/">explains</a> Propositions as Types with a dialogue between Achilles and the Tortoise, in the style of Douglas Hofstadter (who in turn was inspired by Lewis Carrol). Lambda Man makes an appearance.<p/></div>
    </content>
    <updated>2026-04-09T15:22:05Z</updated>
    <published>2026-04-09T15:22:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="Logic"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="Programming Languages"/>
    <author>
      <name>Philip Wadler</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/12009347515095774366</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-9757377</id>
      <category term="Politics"/>
      <category term="Programming Languages"/>
      <category term="Functional Programming"/>
      <category term="Computing"/>
      <category term="Scotland"/>
      <category term="Independence"/>
      <category term="Haskell"/>
      <category term="Yes!"/>
      <category term="Academia"/>
      <category term="UK"/>
      <category term="Edinburgh"/>
      <category term="Science"/>
      <category term="Cycling"/>
      <category term="Graphics"/>
      <category term="Types"/>
      <category term="Mathematics"/>
      <category term="US"/>
      <category term="Logic"/>
      <category term="Covid-19"/>
      <category term="Security"/>
      <category term="Web"/>
      <category term="Comics"/>
      <category term="EU"/>
      <category term="Climate Change"/>
      <category term="Israel"/>
      <category term="Theory"/>
      <category term="Blockchain"/>
      <category term="Comedy"/>
      <category term="Education"/>
      <category term="IOHK"/>
      <category term="Writing"/>
      <category term="AI"/>
      <category term="Agda"/>
      <category term="University"/>
      <category term="Cryptocurrency"/>
      <category term="Developers"/>
      <category term="Internet"/>
      <category term="SIGPLAN"/>
      <category term="Scala"/>
      <category term="Status"/>
      <category term="ACM"/>
      <category term="Concurrency"/>
      <category term="DSL"/>
      <category term="Databases"/>
      <category term="Dynamic and Static Typing"/>
      <category term="F#"/>
      <category term="Green"/>
      <category term="JavaScript"/>
      <category term="Lego"/>
      <category term="Privacy"/>
      <category term="Recursion"/>
      <category term="Session Types"/>
      <category term="Strange Loop"/>
      <category term="Category Theory"/>
      <category term="Formal Methods"/>
      <category term="Java"/>
      <category term="Object-Oriented"/>
      <category term="Technology"/>
      <category term="Architecture"/>
      <category term="Copyright"/>
      <category term="Distributed Computing"/>
      <category term="Europe"/>
      <category term="Productivity"/>
      <category term="Racket"/>
      <category term="Science Fiction"/>
      <category term="Theatre"/>
      <category term="BLM"/>
      <category term="Brexit"/>
      <category term="Communication"/>
      <category term="DRM"/>
      <category term="Environment"/>
      <category term="Erlang"/>
      <category term="Finance"/>
      <category term="Gender"/>
      <category term="Palestine"/>
      <category term="BDS"/>
      <category term="Books"/>
      <category term="Cinema"/>
      <category term="Japan"/>
      <category term="Net Neutrality"/>
      <category term="Open Access"/>
      <category term="Pyret"/>
      <category term="Scheme"/>
      <category term="Sweden"/>
      <author>
        <name>Philip Wadler</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/12009347515095774366</uri>
      </author>
      <link href="https://wadler.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="https://www.blogger.com/feeds/9757377/posts/default?alt=atom" rel="self" type="application/atom+xml"/>
      <link href="https://wadler.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="https://www.blogger.com/feeds/9757377/posts/default?alt=atom&amp;start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <title>Wadler's Blog</title>
      <updated>2026-06-04T17:46:04Z</updated>
    </source>
  </entry>

  <entry>
    <id>https://r6.ca/blog/20260402T135216Z.html</id>
    <link href="https://r6.ca/blog/20260402T135216Z.html" rel="alternate" type="text/html"/>
    <title>Nash Equilibrium for Terminal Maneuvers</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Last year Ethan Heilman wrote about a simple game he calls <a href="https://www.ethanheilman.com/x/31/index.html" title="Missile vs. Laser: The Game of Terminal Maneuvers">Terminal Maneuvers</a>.
This game simulates a missile attacking an interstellar ship.
The ship has a laser defence system.
One player controls the missile, and the other player controls the laser.
If the missile hits the ship, Missile wins.
If the laser hits the missile, the missile is destroyed and Laser wins.

</p><p>The complicating factor is that, due to the relative motion of the laser and the ship being a significant fraction of the speed of light, Laser has to aim not at the missile but where the missile will be.
This distance allows the missile to perform erratic manoeuvers to prevent Laser from knowing what its future position will be.
However, Missile must expend fuel to perform these manoeuvers.

</p><p>The Terminal Maneuvers game proceeds in five rounds, giving the laser five opportunities to hit the missile.
In each round, Missile secretly commits to an amount of fuel they will expend.
Laser must “aim” by guessing the amount of fuel expended by Missile.
If they guess correctly, there is some probability of destroying the missile, which depends on how far away the missile is and how much fuel the missile expended.
The table below shows the probabilities of the missile being destroyed in the various rounds.

<table summary="A matrix of probabilities with rows being fuel burned and columns being the round number.">
<caption>Probability of Laser destroying the missile when correctly guessing Missile’s fuel expenditure</caption>
<thead>
<tr>
<th>Fuel Cost</th>
<th>Round 1</th>
<th>Round 2</th>
<th>Round 3</th>
<th>Round 4</th>
<th>Round 5</th>
</tr>
</thead>
<tbody>
<tr>
<th>0 Fuel</th>
<td>100%</td>
<td>100%</td>
<td>100%</td>
<td>100%</td>
<td>100%</td>
</tr>
<tr>
<th>1 Fuel</th>
<td>1/6</td>
<td>2/6</td>
<td>3/6</td>
<td>4/6</td>
<td>5/6</td>
</tr>
<tr>
<th>2 Fuel</th>
<td>0%</td>
<td>1/6</td>
<td>2/6</td>
<td>3/6</td>
<td>4/6</td>
</tr>
<tr>
<th>3 Fuel</th>
<td/>
<td>0%</td>
<td>1/6</td>
<td>2/6</td>
<td>3/6</td>
</tr>
<tr>
<th>4 Fuel</th>
<td/>
<td/>
<td>0%</td>
<td>1/6</td>
<td>2/6</td>
</tr>
<tr>
<th>5 Fuel</th>
<td/>
<td/>
<td/>
<td>0%</td>
<td>1/6</td>
</tr>
<tr>
<th>6 Fuel</th>
<td/>
<td/>
<td/>
<td/>
<td>0%</td>
</tr>
</tbody>
</table>

</p><p>The missile has a limited amount of fuel at the start of the game.
Fuel spent earlier in the game means less fuel available later in the game when it is most needed.
The amount of starting fuel selects the difficulty of the game.
Ethan suggests <a href="https://www.ethanheilman.com/x/31/index.html" title="Missile vs. Laser: The Game of Terminal Maneuvers">starting with seven fuel</a>, which empirically gives Missile about a 25% chance of winning.

</p><p>Laser knows how much fuel the missile has at the start of each round, so it is imperative that Missile does not run out of fuel in the middle of the game.
If Laser knows the missile is out of fuel, Laser will predict zero fuel used and will always successfully destroy the missile.
That said, as long as Missile has some fuel, choosing to burn zero fuel is still a legitimate option.

</p><p>Starting with seven fuel, one strategy for Missile would be to burn one fuel on the first four rounds and burn the remaining three fuel on the last round.
However, if Laser realizes this is Missile’s strategy, Laser can always predict the correct amount of fuel that will be used by the missile.
Taking the product of all the probabilities of Missile’s survival in each round, Missile only has a 4.6% chance of winning.
Clearly, Missile’s optimal strategy should be non-deterministic.

</p><p>I figured this game would be a fun exercise in learning about mixed-strategy (i.e., non-deterministic) Nash equilibrium.
This game is a small finite game, so it is reasonably easy to analyze, but it is significantly more complicated than trivial games often used in Nash equilibrium examples.

</p><p>For these calculations, it is best to find the Nash equilibrium strategy at the endgame and work backward from there.
To that end, let us start with the simplest non-trivial endgame.
Missile has survived to Round 5 and has 1 fuel left.
Missile can choose to burn their last fuel or not, and Laser can choose to aim at no fuel burned or not.
This yields the following, game-theoretic payoff matrix, listing the probabilities of missile or laser winning:

<table summary="Matrix has rows for Missile&#x2019;s burn choice and columns for Laser&#x2019;s predictions.">
<caption>Payoff matrix for Round 5 with 1 fuel remaining</caption>
<tbody>
<tr>
<td/>
<th>Predict 0</th>
<th>Predict 1</th>
</tr>
<tr>
<th>Burn 0</th>
<td class="payoff">0, 1</td>
<td class="payoff">1, 0</td>
</tr>
<tr>
<th>Burn 1</th>
<td class="payoff">1, 0</td>
<td class="payoff">1⁄6, 5⁄6</td>
</tr>
</tbody>
</table>

</p><p>This is a constant-sum game, because the total score of all players is always the same, no matter the outcome.
Constant-sum games are also known as zero-sum games since they can be translated into games where the sum of each outcome is zero without affecting any strategy.

</p><p>The definition of Nash equilibrium is a pair of strategies, one for each player, where neither player individually can change strategies to improve their outcome.
Therefore, one potential way for Missile to devise a strategy is to find one where Laser’s chance of winning is the same regardless of the move that they make.
Such a strategy is not necessarily going to be possible, but we can give it a try.

</p><p>Let <var>p</var> be the probability that Missile will burn 0, and let <var>q</var> be the probability that Missile will burn 1.
If Laser predicts 0, the probability of them winning is <var>p</var>.
If Laser predicts 1, the probability of them winning is 5⁄6 ⁢<var>q</var>.
If Laser cannot make a choice between these two options to improve their odds, then <var>p</var> = 5⁄6 ⁢<var>q</var>.
Missile’s probabilities must add up to 1, so we also require <var>p</var> + <var>q</var> = 1.

</p><p>We have a linear system of two equations and two unknowns, so we can try to solve it.
The solution is <var>p</var> = 5⁄11 and <var>q</var> = 6⁄11.
Missile burns no fuel with probability 5⁄11 and burns its one fuel with probability 6⁄11.
This provides Missile a 6⁄11 chance of winning, regardless of which prediction Laser makes.

</p><p>On the flip side, Laser’s Nash equilibrium can be computed by choosing a set of probabilities so that Missile’s outcome is the same regardless of whether they choose to burn fuel or not.
This time, let <var>p</var> be the probability that Laser will predict 0, and let <var>q</var> be the probability that Laser will predict 1.
If Missile burns 0, the probability of them winning is <var>q</var>.
If Missile burns 1, the probability of them winning is <var>p</var> + 1⁄6 ⁢<var>q</var>.
Again, if Missile cannot make a choice between these two options to improve their odds, then <var>q</var> = <var>p</var> + 1⁄6 ⁢<var>q</var>.
Laser’s probabilities also must add up to 1, so we also require <var>p</var> + <var>q</var> = 1.

</p><p>Rearranging <var>q</var> = <var>p</var> + 1⁄6 ⁢<var>q</var>, we get 5⁄6 ⁢<var>q</var> = <var>p</var>, which happens to be the exact same equation Missile had.
Thus, their solutions are identical.
Laser predicts no fuel burned with a probability of 5⁄11 and predicts one fuel burned with a probability of 6⁄11.
This provides Laser a 5⁄11 chance of winning no matter whether Missile has chosen to burn their fuel or not.
This chance is the complement to Missile’s 6⁄11 chance of winning, as it has to be.

<table summary="Matrix has rows for Missile&#x2019;s burn choice and columns for Laser&#x2019;s predictions.">
<caption>Payoff matrix for Round 5 with 2 fuel remaining</caption>
<tbody>
<tr>
<td/>
<th>Predict 0</th>
<th>Predict 1</th>
<th>Predict 2</th>
</tr>
<tr>
<th>Burn 0</th>
<td class="payoff">0, 1</td>
<td class="payoff">1, 0</td>
<td class="payoff">1, 0</td>
</tr>
<tr>
<th>Burn 1</th>
<td class="payoff">1, 0</td>
<td class="payoff">1⁄6, 5⁄6</td>
<td class="payoff">1, 0</td>
</tr>
<tr>
<th>Burn 2</th>
<td class="payoff">1, 0</td>
<td class="payoff">1, 0</td>
<td class="payoff">2⁄6, 4⁄6</td>
</tr>
</tbody>
</table>

</p><p>If the game ends in Round 5 with Missile having 2 fuel left, we have the above payoff matrix.
We can solve similar linear algebra problems on three variables to find strategies for each player so that the other player’s outcome is the same no matter which of their three choices they make.
The solution has Missile burn 0 fuel with probability 10⁄37, burn 1 fuel with probability 12⁄37, and burn 2 fuel with probability 15⁄37, giving Missile a 27⁄37 chance of winning regardless of what Laser’s prediction is.

</p><p>Laser makes the predictions with the same probability distribution, giving Laser a 10⁄37 chance of winning no matter how much fuel Missile chooses to burn.
This sort of distribution is what we might expect: somewhat evenly distributed with a bias towards burning more fuel, which provides some evasion for Missile.

</p><p>What I found surprising is how when Laser plays at their Nash equilibrium, they simply do not care how much fuel Missile has secretly chosen to burn.
Their odds of winning are the same regardless of what Missile reveals.
It is as if Laser is no longer playing against Missile at all.
Missile’s choices no longer matter.
This result is called the “indifference principle.”
Later we will see that Missile’s choices sometimes can matter.

</p><p>Missile feels the same when playing at their equilibrium.
No matter what prediction Laser ultimately makes, Missile’s odds of winning have already been fixed by playing at the Nash equilibrium.

</p><p>In theory, this is what playing poker at a Nash equilibrium should feel like.
Based on the state of the board, you make a random selection of calls, folds, or raises according to some appropriate distribution, and your distribution has fixed your expected payout at that point, independent of the choices the other players are going to make.
No need to stress over whether your bluff will be called or not.

</p><p>Before moving on to analyzing Round 4, we can complete a chart of the probability of Missile winning when playing at their Nash equilibrium depending on how much fuel they have remaining.

<table summary="Table columns are for the two players, Missile and Laser, with a row for each possible amount of remaining fuel at the start of the round.">
<caption>Probability table for Round 5</caption>
<tbody>
<tr>
<th>Remaining Fuel</th>
<th>Missile Win Probability</th>
<th>Laser Win Probability</th>
</tr>
<tr>
<td>0</td>
<td class="number">0%</td>
<td class="number">100%</td>
</tr>
<tr>
<td>1</td>
<td class="number">6⁄11 ≈ 54.5%</td>
<td class="number">5⁄11 ≈ 45.5%</td>
</tr>
<tr>
<td>2</td>
<td class="number">27⁄37 ≈ 73.0%</td>
<td class="number">10⁄37 ≈ 27.0%</td>
</tr>
<tr>
<td>3</td>
<td class="number">47⁄57 ≈ 82.5%</td>
<td class="number">10⁄57 ≈ 17.5%</td>
</tr>
<tr>
<td>4</td>
<td class="number">77⁄87 ≈ 88.5%</td>
<td class="number">10⁄87 ≈ 11.5%</td>
</tr>
<tr>
<td>5</td>
<td class="number">137⁄147 ≈ 93.2%</td>
<td class="number">10⁄147 ≈ 6.8%</td>
</tr>
<tr>
<td>6+</td>
<td class="number">100%</td>
<td class="number">0%</td>
</tr>
</tbody>
</table>

</p><p>If Missile starts Round 4 with 1 fuel remaining, they are in big trouble.
They can only burn fuel in at most one of the two remaining rounds.
Therefore, Laser can win by predicting 0 fuel burned in both Round 4 and Round 5.
Laser is guaranteed to destroy the missile on one of those two rounds.
Missile must start Round 4 with at least 2 fuel remaining if they are to have a chance of winning.

</p><p>Since the game in each round depends only on the state of Missile’s remaining fuel and not on the specific choices of how that state came to be, we can simplify the analysis of Round 4’s payoff matrix by using each player’s probability of winning Round 5 as their scores in Round 4.
Note that Missile does not have the option of burning all their fuel in Round 4, since starting Round 5 with 0 fuel is a guaranteed loss for them, and Laser knows it.

<table summary="Matrix has rows for Missile&#x2019;s burn choice and columns for Laser&#x2019;s predictions.">
<caption>Payoff matrix for Round 4 with 2 fuel remaining</caption>
<tbody>
<tr>
<td/>
<th>Predict 0</th>
<th>Predict 1</th>
</tr>
<tr>
<th>Burn 0</th>
<td class="payoff">0, 1</td>
<td class="payoff">27⁄37, 10⁄37</td>
</tr>
<tr>
<th>Burn 1</th>
<td class="payoff">6⁄11, 5⁄11</td>
<td class="payoff">2⁄11, 9⁄11</td>
</tr>
</tbody>
</table>

</p><p>To compute Missile’s strategy, we define <var>p</var> and <var>q</var> as before.
This time Missile needs to solve the equations
<var>p</var> + 5⁄11 ⁢<var>q</var> = 10⁄37 ⁢<var>p</var> + 9⁄11 ⁢<var>q</var> and <var>p</var> + <var>q</var> = 1.
The solution has Missile burn 0 fuel with a probability of 148⁄445 and burn 1 fuel with a probability of 297⁄445, which is roughly a 1⁄3<sup>rd</sup>–2⁄3<sup>rd</sup> split.
This provides Missile a chance of winning with a probability of 162⁄445, or about 36.4%.

</p><p>Meanwhile, Laser needs to solve the equations 27⁄37 ⁢<var>q</var> = 6⁄11 ⁢<var>p</var> + 2⁄11 ⁢<var>q</var> and <var>p</var> + <var>q</var> = 1.
The solution has Laser predict 0 fuel with probability 223⁄445 and predict 1 fuel with probability 222⁄445, which is nearly evenly split.
This provides Laser a chance of winning of 283⁄445, or about 63.6%.

</p><p>In Round 5, each player’s individual payoff matrix was symmetric, which led to Missile and Laser having identical strategies.
In Round 4, the individual player’s payoff matrices are no longer symmetric, and Missile and Laser end up with different strategies.
Laser picks a nearly 50–50 split because the differences of column scores, 5⁄11 − 1 vs. 9⁄11 − 10⁄37, are nearly equal in magnitude.
Whereas Missile picks a 1⁄3<sup>rd</sup>–2⁄3<sup>rd</sup> split because the difference of row scores, 27⁄37 vs. 2⁄11 − 6⁄11, differs in magnitude by close to a factor of two.

</p><p>We can proceed as before, using linear algebra to compute equilibrium strategies for Round 4 with various states of remaining fuel for the missile.
However, we run into a problem when Missile has 4 fuel remaining.

<table summary="Matrix has rows for Missile&#x2019;s burn choice and columns for Laser&#x2019;s predictions.">
<caption>Payoff matrix for Round 4 with 4 fuel remaining.</caption>
<tbody>
<tr>
<td/>
<th>Predict 0</th>
<th>Predict 1</th>
<th>Predict 2</th>
<th>Predict 3</th>
</tr>
<tr>
<th>Burn 0</th>
<td class="payoff">0, 1</td>
<td class="payoff">77⁄87, 10⁄87</td>
<td class="payoff">77⁄87, 10⁄87</td>
<td class="payoff">77⁄87, 10⁄87</td>
</tr>
<tr>
<th>Burn 1</th>
<td class="payoff">47⁄57, 10⁄57</td>
<td class="payoff">47⁄171, 124⁄171</td>
<td class="payoff">47⁄57, 10⁄57</td>
<td class="payoff">47⁄57, 10⁄57</td>
</tr>
<tr>
<th>Burn 2</th>
<td class="payoff">27⁄37, 10⁄37</td>
<td class="payoff">27⁄37, 10⁄37</td>
<td class="payoff">27⁄74, 47⁄74</td>
<td class="payoff">27⁄37, 10⁄37</td>
</tr>
<tr>
<th>Burn 3</th>
<td class="payoff">6⁄11, 5⁄11</td>
<td class="payoff">6⁄11, 5⁄11</td>
<td class="payoff">6⁄11, 5⁄11</td>
<td class="payoff">4⁄11, 7⁄11</td>
</tr>
</tbody>
</table>

</p><p>Let us try to solve for Laser’s equilibrium strategy, the probability distribution where Missile’s outcome is the same no matter what move they make.
We let <var>p</var>, <var>q</var>, <var>r</var>, and <var>s</var> be the probabilities of predicting 0 through 3 fuel burned, respectively.
In addition to having <var>p</var> + <var>q</var> + <var>r</var> + <var>s</var> = 1, we require</p><ul>
<li>77⁄87 ⁢(<var>q</var> + <var>r</var> + <var>s</var>),</li>
<li>47⁄57 ⁢(<var>p</var> + <var>r</var> + <var>s</var>) + 47⁄171 ⁢<var>q</var>,</li>
<li>27⁄37 ⁢(<var>p</var> + <var>q</var> + <var>s</var>) + 27⁄74 ⁢<var>r</var>, and</li>
<li>6⁄11 ⁢(<var>p</var> + <var>q</var> + <var>r</var>) + 4⁄11 ⁢<var>s</var></li>
</ul>
all be equal to each other.
Solving this system of equations gives us
<ul>
<li><var>p</var> ≈ 34.4%,</li>
<li><var>q</var> ≈ 44.3%,</li>
<li><var>r</var> ≈ 40.8%, and</li>
<li><var>s</var> ≈ −19.5%.</li>
</ul>

<p>Apparently, predicting 3 fuel used is such a terrible move for Laser that our “optimal” solution wants us to predict it with a <em>negative</em> 19.5% probability!
Unfortunately, Laser cannot actually select moves with negative probability.
We have to add constrains to our acceptable solutions to ensure all probabilities are non-negative.

</p><p>Adding linear constraints to our problem brings us into the realm of linear programming.
Since we are entering this realm, we can take this opportunity to compute the minimax solution for each player.
For Laser, the minimax solution is to compute a probability distribution that minimizes Missile’s score, i.e., their probability of winning, which we will denote by <var>z</var>, subject to the constraint that Missile will choose the move that maximizes their score for that distribution.
This leads to the following system of linear constraints:

</p><ul>
<li>77⁄87 ⁢(<var>q</var> + <var>r</var> + <var>s</var>) ≤ <var>z</var></li>
<li>47⁄57 ⁢(<var>p</var> + <var>r</var> + <var>s</var>) + 47⁄171 ⁢<var>q</var> ≤ <var>z</var></li>
<li>27⁄37 ⁢(<var>p</var> + <var>q</var> + <var>s</var>) + 27⁄74 ⁢<var>r</var> ≤ <var>z</var></li>
<li>6⁄11 ⁢(<var>p</var> + <var>q</var> + <var>r</var>) + 4⁄11 ⁢<var>s</var> ≤ <var>z</var></li>
<li>0 ≤ <var>p</var></li>
<li>0 ≤ <var>q</var></li>
<li>0 ≤ <var>r</var></li>
<li>0 ≤ <var>s</var></li>
<li><var>p</var> + <var>q</var> + <var>r</var> + <var>s</var> = 1</li>
</ul>
where we want to minimize <var>z</var>.

<p>Using <a href="https://online-optimizer.appspot.com/" title="Linear Optimization">linear programming</a>, we can optimize this system.
The <a href="https://online-optimizer.appspot.com/?model=https:%2F%2Fr6.ca%2Fblog%2Ftext%2F77ad58fbd4a4ff615adeae04c64de276340e079f23affac9337f42f52e9e7f9e.txt" title="Linear Optimization">optimal solution</a> is</p><ul>
<li><var>p</var> ≈ 30.5%,</li>
<li><var>q</var> ≈ 38.1%,</li>
<li><var>r</var> ≈ 31.4%,</li>
<li><var>s</var> ≈ 0%, and</li>
<li><var>z</var> ≈ 61.5%.</li>
</ul>
That is, Laser’s strategy is to
predict 0 fuel burned 30.5% of the time,
predict 1 fuel burned 38.1% of the time,
predict 2 fuel burned 31.4% of the time,
and <em>never</em> predict 3 fuel burned.
This lets Missile win at most 61.5% of the time, or equivalently, it lets Laser win at least 38.5% of the time.

<p>Is this minimax strategy really an optimal strategy?
Let us look at Missile’s minimax strategy.
For Missile, we need to optimize the following system of linear constraints:

</p><ul>
<li><var>p</var> + 10⁄57 ⁢<var>q</var> + 10⁄37 ⁢<var>r</var> + 5⁄11 ⁢<var>s</var> ≤ <var>z</var></li>
<li>10⁄87 ⁢<var>p</var> + 124⁄171 ⁢<var>q</var> + 10⁄37 ⁢<var>r</var> + 5⁄11 ⁢<var>s</var> ≤ <var>z</var></li>
<li>10⁄87 ⁢<var>p</var> + 10⁄57 ⁢<var>q</var> + 47⁄74 ⁢<var>r</var> + 5⁄11 ⁢<var>s</var> ≤ <var>z</var></li>
<li>10⁄87 ⁢<var>p</var> + 10⁄57 ⁢<var>q</var> + 10⁄37 ⁢<var>r</var> + 7⁄11 ⁢<var>s</var> ≤ <var>z</var></li>
<li>0 ≤ <var>p</var></li>
<li>0 ≤ <var>q</var></li>
<li>0 ≤ <var>r</var></li>
<li>0 ≤ <var>s</var></li>
<li><var>p</var> + <var>q</var> + <var>r</var> + <var>s</var> = 1</li>
</ul>
to minimize <var>z</var>.

<p>The <a href="https://online-optimizer.appspot.com/?model=https:%2F%2Fr6.ca%2Fblog%2Ftext%2F799b154aeb4b2b968b0d8b0895c20334dab3d7a5244d3b5a26a3df2b94e29f6e.txt" title="Linear Optimization">optimal solution</a> is</p><ul>
<li><var>p</var> ≈ 19.9%,</li>
<li><var>q</var> ≈ 32.0%,</li>
<li><var>r</var> ≈ 48.2%,</li>
<li><var>s</var> ≈ 0%, and</li>
<li><var>z</var> ≈ 38.5%.</li>
</ul>
That is, Missile’s strategy is to
burn 0 fuel 19.9% of the time,
burn 1 fuel 32.0% of the time,
burn 2 fuel 48.2% of the time,
and <em>never</em> burn 3 fuel.
This lets Laser win at most 38.5% of the time, or equivalently, it lets Missile win at least 61.5% of the time.

<p>This pair of strategies is optimal because Laser wins at least 38.5% of the time by their strategy, and Missile wins at least 61.5% of the time by their strategy, which adds up to 100%.
It turns out that <a href="https://www.cs.mcgill.ca/~cai/COMP_MATH_553_2016/lec3.pdf" title="6.891 Games, Decision, and Computation: Lecture 3">for zero-sum games, the minimax, maximin, and Nash equilibrium strategy sets are all identical, and furthermore, these strategies form a convex set</a>.
Using <a href="https://cgi.csc.liv.ac.uk/~rahul/bimatrix_solver/" title="Solve a Bimatrix Game">a general-purpose Nash equilibrium solver</a> will produce the same pair of optimal strategies.


</p><p>Still, these strategies surprised me.
Laser is not even aiming at Missile burning 3 fuel.
Shouldn’t Missile avoid being hit by Laser entirely by choosing to burn 3 fuel?
But Missile’s optimal strategy also says to avoid burning 3 units of fuel.
Why?

</p><p>Upon closer examination, we see that with Missile’s computed optimal strategy, they have a 61.5% chance of winning.
If Missile were to burn 3 fuel, yes, they would avoid being hit by Laser in Round 4.
However, they would begin Round 5 with only 1 remaining fuel.
In that state they would only have a 54.5% chance of winning, worse odds than their optimal strategy that avoids burning 3 fuel.

</p><p>Laser is not aiming at Missile burning 3 fuel because Laser would <em>love</em> for Missile to burn 3 fuel.
Doing so would increase Laser’s odds of winning from 38.5% to 45.5%.
We see that Laser’s strategy does not entirely rule out all consequences of Missile’s choices.
It only makes it indifferent to Missile’s choices within the support of Missile’s optimal mixed set of moves.
Technically an opponent’s choices can affect the outcome of the game; they can still make moves that benefit the other player.

</p><p>Continuing with linear programming, we can fill out the  table for the probability of winning for Round 4.

<table summary="Table columns are for the two players, Missile and Laser, with a row for each possible amount of remaining fuel at the start of the round.">
<caption>Probability table for Round 4</caption>
<tbody>
<tr>
<th>Remaining Fuel</th>
<th>Missile Win Probability</th>
<th>Laser Win Probability</th>
</tr>
<tr>
<td>1-</td>
<td class="number">0%</td>
<td class="number">100%</td>
</tr>
<tr>
<td>2</td>
<td class="number">≈ 36.4%</td>
<td class="number">≈ 63.6%</td>
</tr>
<tr>
<td>3</td>
<td class="number">≈ 50.5%</td>
<td class="number">≈ 49.5%</td>
</tr>
<tr>
<td>4</td>
<td class="number">≈ 61.5%</td>
<td class="number">≈ 38.5%</td>
</tr>
<tr>
<td>5</td>
<td class="number">≈ 69.9%</td>
<td class="number">≈ 30.1%</td>
</tr>
<tr>
<td>6</td>
<td class="number">≈ 76.4%</td>
<td class="number">≈ 23.6%</td>
</tr>
<tr>
<td>7</td>
<td class="number">≈ 81.6%</td>
<td class="number">≈ 18.4%</td>
</tr>
</tbody>
</table>

</p><p>Continuing this way, we can work backwards and compute probability tables for all the rounds until we reach round 1.

<table summary="Table columns are for the two players, Missile and Laser, with a row for each possible amount of remaining fuel at the start of the round.">
<caption>Probability table for Round 1</caption>
<tbody>
<tr>
<th>Starting Fuel</th>
<th>Missile Win Probability</th>
<th>Laser Win Probability</th>
</tr>
<tr>
<td>7</td>
<td class="number">1005005076075⁄3110959445024 ≈ 32.3%</td>
<td class="number">2105954368949⁄3110959445024 ≈ 67.7%</td>
</tr>
</tbody>
</table>

</p><p>In conclusion, we found that playing optimally, Missile has an approximately 32.3% chance of winning, which is a little higher than the 25% estimate given by Ethan.
I leave it as an exercise to determine the most fair amount of starting for Missile to start with.

</p></div>
    </content>
    <updated>2026-04-02T13:52:16Z</updated>
    <published>2026-04-02T13:52:16Z</published>
    <source>
      <id>https://r6.ca/blog/</id>
      <author>
        <name>Russell O’Connor</name>
        <uri>https://r6.ca/</uri>
      </author>
      <link href="https://r6.ca/blog/" rel="alternate" type="text/html"/>
      <link href="https://r6.ca/blog/feed.atom" rel="self" type="application/atom+xml"/>
      <title>Russell O’Connor’s Blog</title>
      <updated>2026-04-02T13:52:16Z</updated>
    </source>
  </entry>

  <entry>
    <id>https://tweag.io/blog/2026-04-02-making-bazel-builds-more-reliable/</id>
    <link href="https://tweag.io/blog/2026-04-02-making-bazel-builds-more-reliable/" rel="alternate" type="text/html"/>
    <title>Accessing external resources reliably with Bazel</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>We say that a system is reliable if it continues to function correctly
when events outside the system affect it.
Many factors can impact the reliability of Bazel builds,
especially dependencies on external services.
In this post, we’ll focus on what can go wrong
when your build needs resources you don’t control
and what you can do to reduce the risk of build failures.</p>
<h2 id="depending-on-external-resources"><a class="anchor before" href="https://www.tweag.io/rss.xml#depending-on-external-resources"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>Depending on external resources</h2>
<p>Some build actions triggered by Bazel might be accessing resources
that are external to your organization.
For Bazel builds, this typically applies to build rules (to build your first-party code) or
repository rules (utilities and tools those rules might need).
When Bazel starts a build, it emits data about network requests,
and you need to make those external requests visible
so that you know what external resources your builds depend on.
You can access this information via the <a href="https://bazel.build/remote/bep">Build Event Protocol (BEP)</a>
which can be written to disk or,
if you operate a remote cache service, your provider might have a BEP viewer.
You can also use the <a href="https://bazel.build/versions/8.2.0/reference/command-line-reference#flag--experimental_repository_resolved_file"><code class="language-text">--experimental_repository_resolved_file</code> flag</a>
to produce resolved information about all Starlark repository rules that were executed.</p>
<p>Building a target that depends on a repository rule such as this:</p>
<div class="gatsby-highlight"><pre class="language-python"><code class="language-python">http_archive<span class="token punctuation">(</span>
    name <span class="token operator">=</span> <span class="token string">"yq_cli"</span><span class="token punctuation">,</span>
    build_file <span class="token operator">=</span> <span class="token string">"@//tools/yq:BUILD.bazel.gen"</span><span class="token punctuation">,</span>
    sha256 <span class="token operator">=</span> <span class="token string">"7583d471d9bfe88e32005e9d287952382df0469135f691e044443f610d707f4d"</span><span class="token punctuation">,</span>
    url <span class="token operator">=</span> <span class="token string">"https://github.com/mikefarah/yq/releases/download/v4.47.1/yq_linux_amd64.tar.gz"</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span></code></pre></div>
<p>would result in the following build event (the snippet below is copied from the BEP output):</p>
<div class="gatsby-highlight"><pre class="language-text"><code class="language-text">...
children {
  fetch {
    url: "https://github.com/mikefarah/yq/releases/download/v4.47.1/yq_linux_amd64.tar.gz"
  }
}
...</code></pre></div>
<p>To get an idea of what kinds of artifacts a Bazel build for a reasonably large project might fetch,
let’s build a few open-source projects — <a href="https://github.com/envoyproxy/envoy">Envoy</a>, <a href="https://github.com/redpanda-data/redpanda">Redpanda</a>, and <a href="https://github.com/DataDog/datadog-agent">datadog-agent</a>.
These are some of the domains from which at least one resource was fetched
when building all targets from these projects:</p>
<div class="gatsby-highlight"><pre class="language-text"><code class="language-text">bcr.bazel.build             cdn.azul.com                dl.google.com
dl.grafana.com              dl.min.io                   download.gnome.org
files.pythonhosted.org      gcr.io                      github.com
go.dev                      mirror.bazel.build          mirrors.kernel.org
raw.githubusercontent.com   pkgconfig.freedesktop.org   pypi.org
static.crates.io            static.rust-lang.org        s3.amazonaws.com
www.antlr.org               www.colm.net                www.lua.org
www.sqlite.org              www.tcpdump.org</code></pre></div>
<p>While most of your external dependencies are going to be declared in build metadata files
such as <code class="language-text">MODULE.bazel</code> (or legacy <code class="language-text">WORKSPACE</code>),
some network requests are going to be made by build targets
such as <code class="language-text">genrule</code>s (e.g., by calling <code class="language-text">curl</code>) or toolchains (e.g., a <code class="language-text">pip</code> call to the PyPI index).
We’ll see a worked example of this later in the post.</p>
<h2 id="common-problems"><a class="anchor before" href="https://www.tweag.io/rss.xml#common-problems"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>Common problems</h2>
<p>In general, it is advised to rely on <code class="language-text">MODULE.bazel</code> or <code class="language-text">WORKSPACE</code> mechanisms
for accessing external dependencies instead of doing so via build or test actions.
Bazel by design lacks support and features for downloads to take place within build actions,
and when attempting to interact with external systems this way,
you will be limited in how you can manage and account for those requests.</p>
<p>Therefore, when building, the complete list of accessed online resources —
those that are accounted for by BEP and those that are not — might be much longer.
After doing a full build, it might be helpful to audit the network requests made
to discover what resources were fetched
and a complete inventory of external hosts your build depends on.</p>
<p>Given these external dependencies, these are common problems that could happen to any of them:</p>
<ul>
<li>Outages:
no service provides 100% uptime guarantee
and some providers, sadly, have incidents all too often.</li>
<li>Removed artifacts:
an archive file might be deleted due to retention policy.</li>
<li>Rate limiting:
many concurrent builds coming from the same cluster can accidentally trigger API
or download rate limits, especially with public registries.</li>
<li>Checksum drift:
content of an artifact at a given URL can change, intentionally or maliciously,
causing checksum mismatches.</li>
</ul>
<p>This post focuses on strategies to either remove these external
dependencies from the critical path, or make failures graceful and recoverable.</p>
<h2 id="remedies"><a class="anchor before" href="https://www.tweag.io/rss.xml#remedies"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>Remedies</h2>
<p>The remedies below are intentionally “stackable”: you can start with low-effort
safeguards (e.g., checksums and retries) and progress toward stronger guarantees
(e.g., mirrors and network blocking).
If you’re skimming, you can pick one external host that concerns you
(e.g., <code class="language-text">github.com</code> or <code class="language-text">pypi.org</code>) and follow the options
that would let you depend on it more reliably.</p>
<h3 id="using-checksums"><a class="anchor before" href="https://www.tweag.io/rss.xml#using-checksums"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>Using checksums</h3>
<p>External resources may not only vanish or become inaccessible, but also change in place.
Any artifact you download (unless there’s a strong guarantee from a provider), might change its contents
such as when a provider does in-place updates of their releases
(or it could also be a malicious attempt to inject code).
To prevent this issue, SHA-256 digests must be coupled with any artifact you download from the Internet.
Even though when declaring dependencies on external resources
such as with <code class="language-text">http_archive</code>, providing <code class="language-text">sha256</code> attribute is optional,
it is considered a security risk to omit specifying the SHA-256 for remote files to be fetched.</p>
<h3 id="using-github-releases"><a class="anchor before" href="https://www.tweag.io/rss.xml#using-github-releases"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>Using GitHub releases</h3>
<p>As the majority of build rules and open-source tools used by projects built with Bazel are hosted on GitHub,
there are some special concerns that are worth mentioning.</p>
<p>A public GitHub repository might be moved, deleted, or become private (this happened in 2025 with <code class="language-text">rules_mypy</code>).
If you do have to rely on external rulesets hosted on GitHub,
make sure they are hosted under the <a href="https://github.com/bazel-contrib/">bazel-contrib</a> organization
(or help get them migrated at some point) to avoid surprises.</p>
<p>Checksums of <a href="https://docs.github.com/en/repositories/working-with-files/using-files/downloading-source-code-archives">dynamically generated archives</a> might change;
this has caused Bazel outages before, in <a href="https://github.com/orgs/community/discussions/45830">2023</a>.
There was some <a href="https://github.blog/open-source/git/update-on-the-future-stability-of-source-code-archives-and-hashes/">confusion</a> about whether the stability of archives is guaranteed or not.
There might be some edge cases such as when a <a href="https://github.com/orgs/community/discussions/46034#discussioncomment-10572847">Git repository is renamed</a>,
and since Bazel builds rely on stability of archives (for reproducibility and caching among other reasons)
it might be best to play it safe and only use <a href="https://docs.github.com/en/repositories/releasing-projects-on-github/about-releases">releases</a> instead of using source downloads.</p>
<h3 id="using-retries"><a class="anchor before" href="https://www.tweag.io/rss.xml#using-retries"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>Using retries</h3>
<p>It is possible that some of your dependencies need to be obtained from an online resource
that is known to be unstable.
What’s worse, you may not even be able to cache it (or host yourself):
for example, imagine needing to download a short-lived license file for a commercial product from the manufacturer’s server
when starting a build.
To make downloading this file (via a repository rule) more likely to succeed,
consider using the <a href="https://bazel.build/reference/command-line-reference#common_options-flag--experimental_repository_downloader_retries"><code class="language-text">--experimental_repository_downloader_retries</code> flag</a>
to specify the maximum number of attempts to retry upon a download error.</p>
<h3 id="placing-binaries-under-version-control"><a class="anchor before" href="https://www.tweag.io/rss.xml#placing-binaries-under-version-control"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>Placing binaries under version control</h3>
<p>This varies a lot between organizations and the programming languages concerned,
but a common approach that is adopted by most organizations is
to check in the source code that is used to build a binary, and not the binary itself.</p>
<p>Many engineers would be strongly opposed to checking in any binary,
as Version Control Systems (VCS) are designed and optimised for managing the source code.
However, it is known that some organizations choose to place binary libraries
that are external dependencies of their first-party code
under version control.
This has been seen occasionally in Java projects where <code class="language-text">.jar</code> libraries
(that nowadays can be managed with Maven / Gradle) were checked in.
Today, this, arguably, might make sense only for legacy projects,
air-gapped or classified networks, and for vendored native libraries
that are hard to rebuild.</p>
<p>Unless you are able to provide top-notch automation for keeping your third-party dependencies
checked in under version control up-to-date, patched, and compliant with any licensing constraints,
it might be best to rely on a private artifact cache for hosting third-party dependencies.</p>
<h3 id="internal-repository-manager"><a class="anchor before" href="https://www.tweag.io/rss.xml#internal-repository-manager"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>Internal repository manager</h3>
<p>As your organization grows, you will likely need to invest in a tool
that would allow you to organize your resources
such as external tools and third-party code packages into repositories.
There are lots of commercial solutions on the market such as <a href="https://jfrog.com/artifactory/">JFrog Artifactory</a>,
<a href="https://www.sonatype.com/products/sonatype-nexus-repository">Sonatype Nexus</a>, <a href="https://aws.amazon.com/codeartifact/">AWS CodeArtifact</a>, and <a href="https://docs.gitlab.com/user/packages/">GitLab package registry</a> to name a few.</p>
<p>With a repository manager, once you discover a dependency on an external artifact,
you would upload it manually in your internal binary repository
and update your build metadata accordingly:</p>
<div class="gatsby-highlight"><pre class="language-python"><code class="language-python"><span class="token comment"># MODULE.bazel</span>
http_archive<span class="token punctuation">(</span>
  name <span class="token operator">=</span> <span class="token string">"tool"</span><span class="token punctuation">,</span>
  <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
  urls <span class="token operator">=</span> <span class="token punctuation">[</span>
    <span class="token string">"https://artifacts.company.com/artifactory/project/tools/tool-1.2.3.tar.gz"</span><span class="token punctuation">,</span>
    <span class="token string">"https://www.project.org/source/1.2.3/tool-1.2.3.tar.gz"</span><span class="token punctuation">,</span>
  <span class="token punctuation">]</span>
<span class="token punctuation">)</span></code></pre></div>
<p>URLs from the <a href="https://bazel.build/rules/lib/repo/http#http_archive-urls"><code class="language-text">urls</code></a> attribute are tried in order until one succeeds.
It is recommended to specify the local binary repository artifact first,
and if the hosted mirror happens to be down, your build would still succeed
provided that, in this case, <code class="language-text">project.org</code> is up and running.</p>
<h3 id="bazel-downloader-configuration"><a class="anchor before" href="https://www.tweag.io/rss.xml#bazel-downloader-configuration"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>Bazel downloader configuration</h3>
<p>You could also let your binary repository manager be the only place where Bazel builds can fetch resources from
if you don’t want to depend on external artifacts in any way at all.
This can be achieved by providing a configuration file for the remote downloader
using the <a href="https://bazel.build/reference/command-line-reference#common_options-flag--downloader_config"><code class="language-text">--downloader_config</code> flag</a>.</p>
<p>For example, a simple use case may be to block GitHub and instead rewrite fetches to go to an Artifactory instance.
This can be done with the following downloader configuration:</p>
<div class="gatsby-highlight"><pre class="language-text"><code class="language-text">rewrite github.com/([^/]+)/([^/]+)/releases/download/([^/]+)/(.*) artifacts.my-company.com/artifactory/github-releases-mirror/$1/$2/releases/download/$3/$4

# if you still have to rely on dynamically generated archives instead of releases
rewrite github.com/([^/]+)/([^/]+)/archive/(.+).(tar.gz|zip) artifacts.my-company.com/artifactory/github-releases-mirror/$1/$2/archive/$3.$4</code></pre></div>
<p>However, support for using Bazel’s downloader needs to be enabled in Bazel rulesets by their authors.
For instance, in <code class="language-text">rules_python</code>, the <a href="https://github.com/bazel-contrib/rules_python/blob/main/docs/pypi/download.md#bazel-downloader-and-multi-platform-wheel-hub-repository"><code class="language-text">pip</code> extension</a>
now supports pulling information from a PyPI compatible mirror
which means that the Bazel downloader can be used for downloading Python wheels.</p>
<p>Take a look at some downloader configurations used in other projects
(e.g., <a href="https://github.com/monogon/monogon/blob/main/build/bazel/bazel_downloader.cfg">1</a>, <a href="https://github.com/bazelbuild/bazel/blob/master/bazel_downloader.cfg">2</a>, <a href="https://github.com/google/tensorstore/blob/master/bazel/rewrite.config">3</a>)
to explore how others set up access to external resources
and learn the nuances of the configuration declaration syntax.</p>
<h3 id="blocking-network-requests"><a class="anchor before" href="https://www.tweag.io/rss.xml#blocking-network-requests"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>Blocking network requests</h3>
<p>Additional control of network access can be achieved by blocking some network requests in CI agents
using custom firewall rules or other tools of that nature.
However, as mentioned earlier, Bazel’s downloader configuration can only rewrite or block requests that Bazel
is aware of.
This means that not all network traffic in a Bazel build is Bazel-managed traffic.</p>
<p>To illustrate this, let’s declare a dependency on the <a href="https://github.com/bazelbuild/bazel-central-registry/tree/5978cdffb9fdb566dc0eca759f1aa57cb3604914/modules/gawk/5.3.2"><code class="language-text">gawk</code> binary</a>.
When running <code class="language-text">gawk</code>, its <a href="https://github.com/bazelbuild/bazel-central-registry/blob/5978cdffb9fdb566dc0eca759f1aa57cb3604914/modules/gawk/5.3.2/source.json#L2">sources</a> are going to be fetched from the <a href="https://ftp.gnu.org/gnu/gawk/gawk-5.3.2.tar.xz">GNU FTP server</a>.
Let’s also add a <code class="language-text">genrule</code> that will download an archive from the same FTP server:</p>
<div class="gatsby-highlight"><pre class="language-python"><code class="language-python"><span class="token comment"># MODULE.bazel</span>
bazel_dep<span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">"gawk"</span><span class="token punctuation">,</span> version <span class="token operator">=</span> <span class="token string">"5.3.2"</span><span class="token punctuation">)</span>

<span class="token comment"># BUILD.bazel</span>
genrule<span class="token punctuation">(</span>
    name <span class="token operator">=</span> <span class="token string">"diffutils"</span><span class="token punctuation">,</span>
    outs <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">"diffutils-3.12.tar.xz"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    cmd <span class="token operator">=</span> <span class="token triple-quoted-string string">"""wget -O "$@" https://ftp.gnu.org/gnu/diffutils/diffutils-3.12.tar.xz"""</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span></code></pre></div>
<p>We’ll configure Bazel to use a downloader configuration that blocks fetches from that FTP server:</p>
<div class="gatsby-highlight"><pre class="language-text"><code class="language-text"># bazel_downloader.cfg
block ftp.gnu.org

# .bazelrc
common --downloader_config=bazel_downloader.cfg</code></pre></div>
<p>When attempting to run the <code class="language-text">gawk</code> binary from the ruleset, an error is expectedly raised
since accessing the server is blocked:</p>
<div class="gatsby-highlight"><pre class="language-text"><code class="language-text">$ bazel run @gawk
...
ERROR: java.io.IOException: Configured URL rewriter blocked all URLs:
[https://ftp.gnu.org/gnu/gawk/gawk-5.3.2.tar.xz]</code></pre></div>
<p>However, building a <code class="language-text">genrule</code> still succeeds
because the downloader configuration does not apply here:</p>
<div class="gatsby-highlight"><pre class="language-text"><code class="language-text">$ bazel build //src:diffutils
...
INFO: From Executing genrule //src:diffutils:
--2026-01-19 10:48:54--  https://ftp.gnu.org/gnu/diffutils/diffutils-3.12.tar.xz
Resolving ftp.gnu.org (ftp.gnu.org)... 209.51.188.20, 2001:470:142:3::b
Connecting to ftp.gnu.org (ftp.gnu.org)|209.51.188.20|:443... connected.
HTTP request sent, awaiting response... 200 OK
Saving to: 'bazel-out/k8-fastbuild/bin/src/diffutils-3.12.tar.xz'</code></pre></div>
<p>External network requests of this nature are hard to audit in a large codebase
since they won’t show up as structured fetch events in BEP output.
To mitigate this, prefer using repository rules and <a href="https://bazel.build/external/extension">Bzlmod extensions</a>
for any downloads instead of ad hoc shell commands.
Going a step further, you might want to consider forbidding direct calls to applications
that might make network requests (such as <code class="language-text">curl</code> or <code class="language-text">wget</code>) in <code class="language-text">genrule</code> targets, unless explicitly approved.
Where unavoidable, configure targets to access internal repositories instead of public endpoints.</p>
<h3 id="sandboxing"><a class="anchor before" href="https://www.tweag.io/rss.xml#sandboxing"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>Sandboxing</h3>
<p>When triggering builds in a <a href="https://bazel.build/docs/sandboxing#sandboxing-strategies">Bazel sandbox</a>, they are run in a container (using Linux Namespaces)
to isolate the build actions from the host.
In addition to making your entire filesystem read-only (except for the sandbox directory),
you can also forbid actions access the network.
This is useful in some scenarios when you want to confirm that a build doesn’t make any network requests
such as when running unit tests or integration tests that are not supposed to make any network calls.
See <a href="https://bazel.build/reference/be/common-definitions">Bazel tags</a> <code class="language-text">requires-network</code> and <code class="language-text">block-network</code>
to learn how to control network access for individual build targets.</p>
<p>Keep in mind that cached results of build actions can still be fetched even when blocking the network in a sandbox.
So if artifacts needed for a build were uploaded to the Bazel cache previously,
you won’t know whether a particular build needs any network resources unless you run the build without cache access.
Also, none of the sandbox flags affect any cache as it’s expected
that these flags should not affect the output of hermetic actions
and making them part of a cache key would worsen the effectiveness of the cache.</p>
<p>With the network disabled in a sandbox, the <code class="language-text">genrule</code> target we declared earlier fails to build:</p>
<div class="gatsby-highlight"><pre class="language-text"><code class="language-text">$ bazel build //src:diffutils --spawn_strategy=linux-sandbox --nosandbox_default_allow_network
...
ERROR: Executing genrule //src:diffutils failed: (Exit 4): bash failed: ...
Resolving ftp.gnu.org (ftp.gnu.org)... failed: Temporary failure in name resolution.
wget: unable to resolve host address 'ftp.gnu.org'
Target //src:diffutils failed to build
...</code></pre></div>
<h3 id="mirrors"><a class="anchor before" href="https://www.tweag.io/rss.xml#mirrors"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>Mirrors</h3>
<p>Since Bazel 8.4, you can also use the <a href="https://bazel.build/reference/command-line-reference#common_options-flag--module_mirrors"><code class="language-text">--module_mirrors</code> flag</a>
to mirror the source archives.
To take advantage of this, add <code class="language-text">--module_mirrors=https://bcr.cloudflaremirrors.com</code> in your <code class="language-text">.bazelrc</code> file.
Keep in mind that this only applies to registry sources and not to other resources fetched by Bazel
(such as downloads happening in the <a href="https://bazel.build/rules/lib/builtins/repository_ctx#download">repository rules context</a>).</p>
<p>Note that for Bazel builds, the <a href="https://registry.bazel.build/">Bazel Central Registry (BCR)</a>
only stores metadata for a Bazel module;
the actual artifacts are usually fetched from URLs
that point to files hosted online (most often on GitHub).</p>
<p>BCR itself is a sort of external dependency for your builds, too.
Even though it’s hosted on production-grade infrastructure at Google, it can still be impacted by outages and operational mishaps.
The SSL certificate for <code class="language-text">mirror.bazel.build</code> has expired, causing worldwide CI breakages, at least twice:
once in <a href="https://github.com/bazelbuild/bazel/issues/15515">2022</a> and again in <a href="https://github.com/bazelbuild/bazel/issues/28101">2025</a>.
Refer to <a href="https://blog.bazel.build/2026/01/16/ssl-cert-expiry.html">Postmortem for bazel.build SSL certificate expiry</a> to learn more.</p>
<p>Configuring Bazel to use <code class="language-text">https://bcr.cloudflaremirrors.com</code> as a mirror for modules from the BCR helps,
but the Cloudflare mirror doesn’t cover the registry itself.
So if you want to go the extra mile, you might also consider setting up your <a href="https://bazel.build/external/registry#index_registry">own BCR index registry</a>
and point Bazel at that instead.
But if this is not feasible, <a href="https://github.com/DataDog/datadog-agent/pull/44621">write a playbook</a> for incident response
around build outages caused by external dependencies, so teams don’t have to improvise under pressure.</p>
<h3 id="pull-through-cache"><a class="anchor before" href="https://www.tweag.io/rss.xml#pull-through-cache"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>Pull-through cache</h3>
<p>If your repository manager supports it, you could let your builds download external resources,
but every resource that is being fetched is saved into the cache as well.
On subsequent builds, the resources are going to be fetched from the cache, if available.
This would let you turn random external downloads into a controlled internal dependency
without requiring you to pre-vendor everything up front.</p>
<p>If your CI agents are in the same network or cloud region (depending on your infrastructure setup),
this could also speed up the builds by having downloads complete faster.
Not relying on external resources makes your Bazel builds also a lot more
<a href="https://bmitch.net/blog/2025-08-22-ghrc-appears-malicious/">secure</a> as your CI agents will only download data from a trusted source.</p>
<p>If using an off-the-shelf solution, such as the popular JFrog Artifactory, is not possible,
there are some other options.
Bazel picks up <a href="https://bazel.build/versions/8.2.0/external/advanced#using_proxies">proxy addresses</a> from the <code class="language-text">HTTP_PROXY</code> and <code class="language-text">HTTPS_PROXY</code> environment variables
and uses these to download files over HTTP and HTTPS, respectively (if specified).
This means you might have success with caching proxy solutions such as <a href="https://www.squid-cache.org/">Squid</a> and <a href="https://www.charlesproxy.com">Charles</a>
or by combining <a href="https://nginx.org/">Nginx</a> and <a href="https://www.varnish-software.com/products/varnish-cache/">Varnish</a> HTTP reverse proxies.
Routing requests through a proxy might also help to avoid rate limiting issues
since the external service will see fewer direct requests.</p>
<p>With this configuration, your downloader configuration file would look something like this:</p>
<div class="gatsby-highlight"><pre class="language-text"><code class="language-text"># point all downloads at the mirror
rewrite (.*) {caching-service-url}/$1

# use the original location if the mirror is down
rewrite (.*) $1</code></pre></div>
<p>For a completely custom solution, take a look at the <a href="https://github.com/monogon/monogon/tree/main/build/mirror_proxy">Bazel downloader mirror from Monogon</a>
which can be used to mirror Bazel dependencies to a cloud bucket storage such as S3 or GCS.
Bazel’s <a href="https://github.com/bazelbuild/remote-apis">remote asset API</a> lets you use an existing remote cache
(content-addressable storage: CAS) as a downloader cache as well.
The cache provider service needs to support it, but many existing solutions, both commercial and open-source ones, are compatible.</p>
<p>The <a href="https://bazel.build/reference/command-line-reference#common_options-flag--experimental_remote_downloader"><code class="language-text">--experimental_remote_downloader</code> flag</a>
can be specified to provide a Remote Asset API endpoint URI to be used as a remote download proxy.
To get started, consider using <a href="https://github.com/buchgr/bazel-remote">bazel-remote</a>, which has out-of-the-box support for this use case.
Make sure to provide the <a href="https://bazel.build/rules/lib/repo/http#http_archive-sha256"><code class="language-text">sha256</code></a> for the assets to fetch
so that they can be cached just like any other CAS object.
A remote caching service will automatically download the assets from the URL if they are found in the CAS and cache it thereafter.</p>
<p>Bazel 9 adds support for <a href="https://github.com/bazelbuild/bazel/discussions/27509">remote repository caches</a>
which make Bazel builds (at least those requiring previously cached assets) extra resilient to external access issues.
During outages of external hosting services, those organizations that didn’t have a central repository manager
where repository rules artifacts could be stored had to extract files from cache directories on local developer machines
and save them to an accessible location within the internal network.</p>
<p>Now these artifacts will be saved into a remote cache similarly to build output results.
To confirm that your remote repository cache works as expected,
you can use the <a href="https://bazel.build/reference/command-line-reference#common_options-flag--repository_disable_download"><code class="language-text">--repository_disable_download</code> flag</a>
after doing a clean build (which should succeed as it will reuse the remote cache entries uploaded in the previous build).</p>
<h3 id="chaos-testing"><a class="anchor before" href="https://www.tweag.io/rss.xml#chaos-testing"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>Chaos testing</h3>
<p>Finally, instead of waiting for the next GitHub outage, you can test your resilience
by intentionally breaking access to certain external hosts.
In a staging CI environment, temporarily block access to key external systems with firewall rules and verify
that your mirrors and caches are used as expected, builds either still succeed,
or fail fast with clear error messages, and your runbooks are correct and sufficient.</p>
<h2 id="conclusion"><a class="anchor before" href="https://www.tweag.io/rss.xml#conclusion"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>Conclusion</h2>
<p>Bazel projects often depend on external services in subtle ways,
and any instability or change in those services can break otherwise healthy builds.
You can significantly improve build reliability by making all downloads explicit and verifiable,
routing them through managed infrastructure,
and tightening how and when network access is allowed.
Resilient Bazel builds come from treating external dependencies as first‑class operational risks
and turning unpredictable third‑party failures into controlled, recoverable events.</p></div>
    </summary>
    <updated>2026-04-02T00:00:00Z</updated>
    <published>2026-04-02T00:00:00Z</published>
    <source>
      <id>https://tweag.io</id>
      <author>
        <name>Tweag I/O</name>
      </author>
      <link href="https://tweag.io" rel="alternate" type="text/html"/>
      <link href="http://www.tweag.io/rss.xml" rel="self" type="application/rss+xml"/>
      <subtitle>Scale your engineering power. We enable deep-tech startups to achieve
their vision, from research to product delivery.</subtitle>
      <title>Tweag - Engineering blog</title>
      <updated>2026-06-12T11:01:45Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://www.well-typed.com/blog/2026/03/hs-bindgen-alpha2</id>
    <link href="https://well-typed.com/blog/2026/03/hs-bindgen-alpha2" rel="alternate" type="text/html"/>
    <title>Second pre-release of hs-bindgen</title>
    <summary>With heartfelt thanks to the many people who have already tried hs-bindgen and
given us feedback, we have steadily been working towards the first official
release (see Contributors for the full list). In case you missed
the announcement of the first alpha, hs-bindgen is a
tool for automatic construction [...]</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>With heartfelt thanks to the many people who have already tried <code>hs-bindgen</code> and
given us feedback, we have steadily been working towards the first official
release (see <a href="https://github.com/well-typed/hs-bindgen/tree/release-0.1-alpha2?tab=readme-ov-file#contributors">Contributors</a> for the full list). In case you missed
the <a href="https://well-typed.com/blog/2026/02/hs-bindgen-alpha/">announcement of the first alpha</a>, <code>hs-bindgen</code> is a
tool for automatic construction of Haskell bindings for C libraries: just point
it at a C header and let it handle the rest. Because we have fixed some critical
bugs in this alpha release, but we’re not quite ready yet for the first full
official release, we have <a href="https://github.com/well-typed/hs-bindgen/releases/tag/release-0.1-alpha2">tagged a second alpha release</a>. In the
remainder of this blog post we will briefly highlight the most important
changes; please refer to the <code>CHANGELOG.md</code> of
<a href="https://github.com/well-typed/hs-bindgen/blob/release-0.1-alpha2/hs-bindgen/CHANGELOG.md">hs-bindgen</a> and of
<a href="https://github.com/well-typed/hs-bindgen/blob/release-0.1-alpha2/hs-bindgen-runtime/CHANGELOG.md">hs-bindgen-runtime</a> for the full list of changes, as well as
for migration hints where we have introduced some minor backwards incompatible
changes.</p>

<h2 id="bugfixes">Bugfixes</h2>
<p>The most important fixes for bugs in the generated code are:</p>
<ul>
<li>The implementation of <code>peek</code> and <code>poke</code> for bitfields was broken, which could
lead to segfaults.</li>
<li>Duplicate record fields are now usable also in Template Haskell mode.</li>
<li>Patterns for unsigned enums now get the right value.</li>
</ul>
<p>We have also resolved a number of panics during code generation, but those would
not have resulted in incorrect generated code (merely in no code being generated
at all).</p>
<h2 id="new-features">New features</h2>
<ul>
<li><p><em>Implicit fields</em> arise when one struct (or union) is nested in another,
without any field name or tag:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb1-1"><a href="https://well-typed.com/blog/rss2.xml#cb1-1" tabindex="-1"/><span class="kw">struct</span> outer <span class="op">{</span></span>
<span id="cb1-2"><a href="https://well-typed.com/blog/rss2.xml#cb1-2" tabindex="-1"/>  <span class="dt">int</span> x<span class="op">;</span></span>
<span id="cb1-3"><a href="https://well-typed.com/blog/rss2.xml#cb1-3" tabindex="-1"/>  <span class="kw">struct</span> <span class="op">{</span></span>
<span id="cb1-4"><a href="https://well-typed.com/blog/rss2.xml#cb1-4" tabindex="-1"/>    <span class="dt">int</span> y<span class="op">;</span></span>
<span id="cb1-5"><a href="https://well-typed.com/blog/rss2.xml#cb1-5" tabindex="-1"/>    <span class="dt">int</span> z<span class="op">;</span></span>
<span id="cb1-6"><a href="https://well-typed.com/blog/rss2.xml#cb1-6" tabindex="-1"/>  <span class="op">};</span></span>
<span id="cb1-7"><a href="https://well-typed.com/blog/rss2.xml#cb1-7" tabindex="-1"/><span class="op">};</span></span></code></pre></div>
<p>We now support such implicit fields; both the inner (anonymous) struct as well
as the corresponding field of the outer struct will be named after the first
field of the inner struct<a class="footnote-ref" href="https://well-typed.com/blog/rss2.xml#fn1" id="fnref1"><sup>1</sup></a>:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb2-1"><a href="https://well-typed.com/blog/rss2.xml#cb2-1" tabindex="-1"/><span class="kw">data</span> <span class="dt">Outer</span> <span class="ot">=</span> <span class="dt">Outer</span> {</span>
<span id="cb2-2"><a href="https://well-typed.com/blog/rss2.xml#cb2-2" tabindex="-1"/><span class="ot">    x ::</span> <span class="dt">CInt</span></span>
<span id="cb2-3"><a href="https://well-typed.com/blog/rss2.xml#cb2-3" tabindex="-1"/>  ,<span class="ot"> y ::</span> <span class="dt">Outer_y</span></span>
<span id="cb2-4"><a href="https://well-typed.com/blog/rss2.xml#cb2-4" tabindex="-1"/>  }</span>
<span id="cb2-5"><a href="https://well-typed.com/blog/rss2.xml#cb2-5" tabindex="-1"/></span>
<span id="cb2-6"><a href="https://well-typed.com/blog/rss2.xml#cb2-6" tabindex="-1"/><span class="kw">data</span> <span class="dt">Outer_y</span> <span class="ot">=</span> <span class="dt">Outer_y</span> {</span>
<span id="cb2-7"><a href="https://well-typed.com/blog/rss2.xml#cb2-7" tabindex="-1"/><span class="ot">    y ::</span> <span class="dt">CInt</span></span>
<span id="cb2-8"><a href="https://well-typed.com/blog/rss2.xml#cb2-8" tabindex="-1"/>  ,<span class="ot"> z ::</span> <span class="dt">CInt</span></span>
<span id="cb2-9"><a href="https://well-typed.com/blog/rss2.xml#cb2-9" tabindex="-1"/>  }</span></code></pre></div>
<p>For this particular case we <em>could</em> also have chosen to flatten the structure
and add <code>y</code> and <code>z</code> directly to <code>Outer</code>, but that does not work in all cases
(for example, when we have an anonymous struct inside a union), so instead
we opt for consistency and always generate an explicit type for the
inner struct.</p></li>
<li><p>Unnamed bit-field declarations, which are used to control padding, are now
supported:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb3-1"><a href="https://well-typed.com/blog/rss2.xml#cb3-1" tabindex="-1"/><span class="kw">struct</span> bar <span class="op">{</span></span>
<span id="cb3-2"><a href="https://well-typed.com/blog/rss2.xml#cb3-2" tabindex="-1"/>  <span class="dt">signed</span> <span class="dt">char</span> x <span class="op">:</span> <span class="dv">3</span><span class="op">;</span></span>
<span id="cb3-3"><a href="https://well-typed.com/blog/rss2.xml#cb3-3" tabindex="-1"/>  <span class="dt">signed</span> <span class="dt">char</span>   <span class="op">:</span> <span class="dv">3</span><span class="op">;</span>  <span class="co">// Explicit padding</span></span>
<span id="cb3-4"><a href="https://well-typed.com/blog/rss2.xml#cb3-4" tabindex="-1"/>  <span class="dt">signed</span> <span class="dt">char</span> y <span class="op">:</span> <span class="dv">2</span><span class="op">;</span></span>
<span id="cb3-5"><a href="https://well-typed.com/blog/rss2.xml#cb3-5" tabindex="-1"/><span class="op">};</span></span></code></pre></div></li>
<li><p>We used to distinguish between <em>parse</em> predicates (which files should
<code>hs-bindgen</code> parse at all?) and <em>selection</em> predicates (for which C
declarations should we generate Haskell declarations?). This was confusing,
and as we are getting better at skipping over declarations with unsupported
features (and that list is dwinding anyway), parse predicates are not that
useful anymore. Parse predicates therefore have been removed entirely; we
simply always parse everything (<em>selection</em> predicates are still very much an
important feature of course).</p></li>
<li><p>Some infrastructure for and around binding specifications has been improved.
For example, we now distinguish between macros and non-macros of the same name,
and our treatment of arrays has changed slightly. For example, given</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb4-1"><a href="https://well-typed.com/blog/rss2.xml#cb4-1" tabindex="-1"/><span class="kw">typedef</span> <span class="dt">char</span> T <span class="op">[];</span></span>
<span id="cb4-2"><a href="https://well-typed.com/blog/rss2.xml#cb4-2" tabindex="-1"/><span class="dt">void</span> foo <span class="op">(</span>T xs<span class="op">);</span></span></code></pre></div>
<p>we now generate</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb5-1"><a href="https://well-typed.com/blog/rss2.xml#cb5-1" tabindex="-1"/><span class="ot">foo ::</span> <span class="dt">Ptr</span> (<span class="dt">Elem</span> <span class="dt">T</span>) <span class="ot">-&gt;</span> <span class="dt">IO</span> ()</span></code></pre></div>
<p>We do not use <code>Ptr CChar</code>, because <code>T</code> might have an existing binding in
another library (with an external binding specification), and we don’t know
what the type of the elements of <code>T</code> are (it could for example be some
newtype around <code>CChar</code>). <code>Elem</code> is a member of a new <code>IsArray</code> class, part of
the <code>hs-bindgen-runtime</code>.</p></li>
<li><p>Top-level anonymous enums are now supported. For example,</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb6-1"><a href="https://well-typed.com/blog/rss2.xml#cb6-1" tabindex="-1"/><span class="kw">enum</span> <span class="op">{</span>A<span class="op">,</span> B<span class="op">};</span></span></code></pre></div>
<p>results in</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb7-1"><a href="https://well-typed.com/blog/rss2.xml#cb7-1" tabindex="-1"/><span class="kw">pattern</span> <span class="dt">A</span><span class="ot"> ::</span> <span class="dt">CUInt</span></span>
<span id="cb7-2"><a href="https://well-typed.com/blog/rss2.xml#cb7-2" tabindex="-1"/><span class="kw">pattern</span> <span class="dt">A</span> <span class="ot">=</span> <span class="dv">0</span></span>
<span id="cb7-3"><a href="https://well-typed.com/blog/rss2.xml#cb7-3" tabindex="-1"/></span>
<span id="cb7-4"><a href="https://well-typed.com/blog/rss2.xml#cb7-4" tabindex="-1"/><span class="kw">pattern</span> <span class="dt">B</span><span class="ot"> ::</span> <span class="dt">CUInt</span></span>
<span id="cb7-5"><a href="https://well-typed.com/blog/rss2.xml#cb7-5" tabindex="-1"/><span class="kw">pattern</span> <span class="dt">B</span> <span class="ot">=</span> <span class="dv">1</span></span></code></pre></div>
<p>(Normally an <code>enum</code> results in a <code>newtype</code> around the enum’s underlying type,
and the patterns are for that <code>newtype</code> instead.)</p></li>
<li><p>We now generate bindings for static global variables (such globals are
sometimes used in headers that also contain static function bodies).</p></li>
<li><p>All definitions required by the generated code are now (re-)exported from
<code>hs-bindgen-runtime</code>, so that it becomes the only package dependency that
needs to be declared (no need for <code>ghc-prim</code> or <code>primitive</code> anymore).</p></li>
</ul>
<p>This list is not complete; some other less common edge cases have also been
implemented.</p>
<h2 id="conclusions">Conclusions</h2>
<p>Although we are still working on some finishing touches before we can release
the first official version of <code>hs-bindgen</code>, it is already being put to good use
on various projects. There are only a <a href="https://github.com/well-typed/hs-bindgen/issues?q=is%3Aissue%20state%3Aopen%20label%3Amissing-c-feature">handful of missing C
features</a> left, all of which low priority edge cases (though
if you have a specific use case for any of these, do let us know!). So if you
are interested, please do try it out, and let us know if you find any problems.
There should be no major breaking changes between now and the first official
release.</p>
<section class="footnotes footnotes-end-of-document" id="footnotes">
<hr/>
<ol>
<li id="fn1"><p>This is the version that uses the
<code>--omit-field-prefixes</code> option, which generates code that relies on
<code>DuplicateRecordFields</code> and <code>OverloadedRecordDot</code>.<a class="footnote-back" href="https://well-typed.com/blog/rss2.xml#fnref1">↩︎</a></p></li>
</ol>
</section></div>
    </content>
    <updated>2026-03-27T00:00:00Z</updated>
    <published>2026-03-27T00:00:00Z</published>
    <category term="hs-bindgen"/>
    <category term="open-source"/>
    <category term="foreign function interface"/>
    <author>
      <name>edsko</name>
    </author>
    <source>
      <id>https://well-typed.com/blog/</id>
      <logo>https://well-typed.com/img/wtnlogoplain.svg</logo>
      <link href="https://well-typed.com/blog/rss2.xml" rel="self" type="application/rss+xml"/>
      <link href="https://well-typed.com/blog/" rel="alternate" type="text/html"/>
      <subtitle>Because Well-Typed Programs Don't Go Wrong</subtitle>
      <title>Well-Typed Blog</title>
      <updated>2026-05-28T00:00:00Z</updated>
    </source>
  </entry>

  <entry>
    <id>http://haskell.org/ghc/blog/20260327-ghc-9.12.4-released.html</id>
    <link href="http://haskell.org/ghc/blog/20260327-ghc-9.12.4-released.html" rel="alternate" type="text/html"/>
    <title>GHC 9.12.4 is now available</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><h1>GHC 9.12.4 is now available</h1>
<h4 class="text-muted">wz1000 - 2026-03-27</h4>

<p>The GHC developers are very pleased to announce the release of GHC 9.12.4.
Binary distributions, source distributions, and documentation are available at
<a href="https://downloads.haskell.org/ghc/9.12.4">downloads.haskell.org</a> and via <a href="https://www.haskell.org/ghcup/">GHCup</a>.</p>
<p>GHC 9.12.4 is a bug-fix release fixing many issues of a variety of
severities and scopes, including:</p>
<ul>
<li><p>Fixed a critical code generation regression where sub-word division produced
incorrect results (<a href="https://gitlab.haskell.org/ghc/ghc/issues/26711">#26711</a>, <a href="https://gitlab.haskell.org/ghc/ghc/issues/26668">#26668</a>), similar to the bug fixed in 9.12.2</p></li>
<li><p>Numerous fixes for register allocation bugs, preventing data corruption
when spilling and reloading registers
(<a href="https://gitlab.haskell.org/ghc/ghc/issues/26411">#26411</a>, <a href="https://gitlab.haskell.org/ghc/ghc/issues/26526">#26526</a>, <a href="https://gitlab.haskell.org/ghc/ghc/issues/26537">#26537</a>, <a href="https://gitlab.haskell.org/ghc/ghc/issues/26542">#26542</a>, <a href="https://gitlab.haskell.org/ghc/ghc/issues/26550">#26550</a>)</p></li>
<li><p>Fixes for several compiler crashes, including issues with CSE (<a href="https://gitlab.haskell.org/ghc/ghc/issues/25468">#25468</a>),
and the simplifier(<a href="https://gitlab.haskell.org/ghc/ghc/issues/26681">#26681</a>), implicit parameters (<a href="https://gitlab.haskell.org/ghc/ghc/issues/26451">#26451</a>), and the type-class
specialiser (<a href="https://gitlab.haskell.org/ghc/ghc/issues/26682">#26682</a>)</p></li>
<li><p>Fixed cast worker/wrapper incorrectly firing on INLINE functions (<a href="https://gitlab.haskell.org/ghc/ghc/issues/26903">#26903</a>)</p></li>
<li><p>Fixed LLVM backend miscompilation of bit manipulation operations
(<a href="https://gitlab.haskell.org/ghc/ghc/issues/20645">#20645</a>, <a href="https://gitlab.haskell.org/ghc/ghc/issues/26065">#26065</a>, <a href="https://gitlab.haskell.org/ghc/ghc/issues/26109">#26109</a>)</p></li>
<li><p>Fixed associated type family and data family instance changes not triggering
recompilation (<a href="https://gitlab.haskell.org/ghc/ghc/issues/26183">#26183</a>, <a href="https://gitlab.haskell.org/ghc/ghc/issues/26705">#26705</a>)</p></li>
<li><p>Fixed negative type literals causing the compiler to hang (<a href="https://gitlab.haskell.org/ghc/ghc/issues/26861">#26861</a>)</p></li>
<li><p>Improvements to determinism of compiler output (<a href="https://gitlab.haskell.org/ghc/ghc/issues/26846">#26846</a>, <a href="https://gitlab.haskell.org/ghc/ghc/issues/26858">#26858</a>)</p></li>
<li><p>Fixes for eventlog shutdown deadlocks (<a href="https://gitlab.haskell.org/ghc/ghc/issues/26573">#26573</a>)
and lost wakeups in the RTS (<a href="https://gitlab.haskell.org/ghc/ghc/issues/26324">#26324</a>)</p></li>
<li><p>Fixed split sections support on Windows (<a href="https://gitlab.haskell.org/ghc/ghc/issues/26696">#26696</a>, <a href="https://gitlab.haskell.org/ghc/ghc/issues/26494">#26494</a>) and the LLVM backend (<a href="https://gitlab.haskell.org/ghc/ghc/issues/26770">#26770</a>)</p></li>
<li><p>Fixes for the bytecode compiler, PPC native code generator, and Wasm backend</p></li>
<li><p>The runtime linker now supports COMMON symbols (<a href="https://gitlab.haskell.org/ghc/ghc/issues/6107">#6107</a>)</p></li>
<li><p>Improved backtrace support: backtraces for <code>error</code> exceptions are now
evaluated at throw time</p></li>
<li><p><code>NamedDefaults</code> now correctly requires the class to be standard or have an
in-scope default declaration, and handles poly-kinded classes (<a href="https://gitlab.haskell.org/ghc/ghc/issues/25775">#25775</a>, <a href="https://gitlab.haskell.org/ghc/ghc/issues/25778">#25778</a>, <a href="https://gitlab.haskell.org/ghc/ghc/issues/25882">#25882</a>)</p></li>
<li><p>… and many more</p></li>
</ul>
<p>A full accounting of these fixes can be found in the <a href="https://gitlab.haskell.org/ghc/ghc/-/blob/ghc-9.12/docs/users_guide/9.12.4-notes.rst?ref_type=heads&amp;plain=1">release notes</a>. As
always, GHC’s release status, including planned future releases, can be found on
the GHC Wiki <a href="https://gitlab.haskell.org/ghc/ghc/-/wikis/GHC-status">status</a>.</p>
<p>GHC development is sponsored by:</p>
<ul>
<li><a href="https://juspay.com/">Juspay</a></li>
<li><a href="https://qbaylogic.com/">QBayLogic</a></li>
<li><a href="https://www.channable.com/">Channable</a></li>
<li><a href="https://haskell.foundation/">Haskell Foundation</a></li>
<li><a href="https://serokell.io/">Serokell</a></li>
<li><a href="https://well-typed.com/">Well-Typed</a></li>
<li><a href="https://www.tweag.io/">Tweag</a></li>
<li><a href="https://www.dotcom-monitor.com/">Dotcom-Monitor</a></li>
<li><a href="https://www.loadview-testing.com/">LoadView</a></li>
<li><a href="https://webhostingbuddy.com/">Web Hosting Buddy</a></li>
<li><a href="https://www.findmyelectric.com/">Find My Electric</a></li>
<li><a href="https://www.sc.com">Standard Chartered</a></li>
<li><a href="https://upcloud.com">UpCloud</a></li>
<li><a href="https://mercury.com">Mercury</a></li>
</ul>
<p>We would like to thank these sponsors and other anonymous contributors
whose on-going financial and in-kind support has facilitated GHC maintenance
and release management over the years. Finally, this release would not have
been possible without the hundreds of open-source contributors whose work
comprise this release.</p>
<p>As always, do give this release a try and open a <a href="https://gitlab.haskell.org/ghc/ghc/-/issues/new">ticket</a> if you see
anything amiss.</p></div>
    </summary>
    <updated>2026-03-27T00:00:00Z</updated>
    <published>2026-03-27T00:00:00Z</published>
    <author>
      <name>ghc-devs</name>
    </author>
    <source>
      <id>http://haskell.org/ghc</id>
      <link href="http://haskell.org/ghc" rel="alternate" type="text/html"/>
      <link href="http://haskell.org/ghc/rss.xml" rel="self" type="application/rss+xml"/>
      <title>GHC Developer blog</title>
      <updated>2026-03-27T00:00:00Z</updated>
    </source>
  </entry>

  <entry>
    <id>https://medium.com/p/539cb2f40215</id>
    <link href="https://cdsmithus.medium.com/athena-loses-a-bet-539cb2f40215?source=rss-18bd5acaea78------2" rel="alternate" type="text/html"/>
    <title>Athena Loses a Bet</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*weyULcS-xuFt4Akf6f4vpA.png"/></figure><p>Athena and Ares argue over human nature, and agree to test three great minds of the age.</p><p>First, they approach Aristotle in the Lyceum and propose a bargain. “If you ask it of us, the one you love most in the world will perish, but you will be made rich beyond imagining.” Aristotle barely hesitates. “No,” he says. “To destroy the very purpose of living for the sake of the mere means is the mark of a man who lacks wisdom.”</p><p>Next, they approach Plato, finding him pacing in an olive grove of his Academy. They offer the same proposal. “I decline,” he says. “Love allows us to glimpse the ideal of pure beauty, but wealth is an anchor to the material world.”</p><p>Finally, they approach Socrates, wandering barefoot in the crowded dusty stalls of the Agora. The gods approach him with the same bargain: “If you ask it of us, Xanthippe, whom you love most in the world, will perish — ”</p><p>“I ask it!” he blurts out.</p><p>Athena blinks. “You did not even hear the rest. We were going to say you would be given wealth beyond measure.”</p><p>Socrates shrugs. “Keep it. This was never about money.”</p><p>Millenia later, Athena is still smarting from losing the bet, and she demands a rematch. Searching for another Greek philosopher, they instead find a middle aged woman writing a novel called <em>Atlas Shrugged</em>. She’s a philosopher, and Atlas was Greek, so that’s close enough.</p><p>“If you ask it,” Athena says to her, “we will make you wealthy beyond measure, but then in return, your true love will be taken from you.”</p><p>The woman looks up, bored, and asks “Why give me the money if you’re just going to take it right back?”</p><img alt="" height="1" src="https://medium.com/_/stat?event=post.clientViewed&amp;referrerSource=full_rss&amp;postId=539cb2f40215" width="1"/></div>
    </content>
    <updated>2026-03-25T18:58:04Z</updated>
    <published>2026-03-25T18:58:04Z</published>
    <category term="jokes"/>
    <author>
      <name>Chris Smith</name>
    </author>
    <source>
      <id>https://medium.com/@cdsmithus?source=rss-18bd5acaea78------2</id>
      <logo>https://cdn-images-1.medium.com/fit/c/150/150/1*rU9ddF_bkph8Qg3jip7vfw.jpeg</logo>
      <link href="https://medium.com/@cdsmithus?source=rss-18bd5acaea78------2" rel="alternate" type="text/html"/>
      <link href="https://medium.com/@cdsmithus/feed" rel="self" type="application/rss+xml"/>
      <link href="http://medium.superfeedr.com" rel="hub" type="text/html"/>
      <subtitle>Stories by Chris Smith on Medium</subtitle>
      <title>Stories by Chris Smith on Medium</title>
      <updated>2026-06-13T05:53:38Z</updated>
    </source>
  </entry>

  <entry xml:lang="en-us">
    <id>Buzzsprout-18853260</id>
    <link href="https://www.buzzsprout.com/1817535/episodes/18853260-79-peter-thiemann.mp3" length="47963255" rel="enclosure" type="audio/mpeg"/>
    <title>79: Peter Thiemann</title>
    <summary>Peter is a professor at the University of Freiburg, and he was doing functional programming right when Haskell got started. So naturally we asked him about the early days of Haskell, and how from the start Peter pushed the envelope on what you could do with the type system and specifically with the type classes, from early web programming to program generation to session types. Come with us on a trip down memory lane!</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Peter is a professor at the University of Freiburg, and he was doing functional programming right when Haskell got started. So naturally we asked him about the early days of Haskell, and how from the start Peter pushed the envelope on what you could do with the type system and specifically with the type classes, from early web programming to program generation to session types. Come with us on a trip down memory lane!</p><p><br/></p></div>
    </content>
    <updated>2026-03-22T12:00:00Z</updated>
    <published>2026-03-22T12:00:00Z</published>
    <author>
      <name>Haskell Podcast</name>
    </author>
    <source>
      <id>https://haskell.foundation/podcast/</id>
      <logo>https://storage.buzzsprout.com/tnk1ztokn5vmeiufqmr4kkp37mw2?.jpg</logo>
      <category scheme="http://www.itunes.com/" term="Technology"/>
      <author>
        <name>Haskell Podcast</name>
      </author>
      <link href="https://rss.buzzsprout.com/1817535.rss" rel="self" type="application/rss+xml"/>
      <link href="https://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="https://haskell.foundation/podcast/" rel="alternate" type="text/html"/>
      <rights>Â© 2026 The Haskell Interlude</rights>
      <subtitle>This is the Haskell Interlude, where the five co-hosts (Wouter Swierstra, Andres LÃ¶h, Alejandro Serrano, Niki Vazou, and Joachim Breitner) chat with Haskell guests!</subtitle>
      <title>The Haskell Interlude</title>
      <updated>2026-05-19T12:36:05Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://www.well-typed.com/blog/2026/03/haskell-ecosystem-report-q1-2026</id>
    <link href="https://well-typed.com/blog/2026/03/haskell-ecosystem-report-q1-2026" rel="alternate" type="text/html"/>
    <title>Haskell ecosystem activities report: December 2025â€“February 2026</title>
    <summary>This is the thirtieth edition of our Haskell ecosystem activities report,
which describes the work Well-Typed are doing on GHC, Cabal, HLS and other parts
of the core Haskell toolchain. The current edition covers roughly the months of
December 2025 to February 2026.

You can find the previous editions [...]</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>This is the thirtieth edition of our Haskell ecosystem activities report,
which describes the work Well-Typed are doing on GHC, Cabal, HLS and other parts
of the core Haskell toolchain. The current edition covers roughly the months of
December 2025 to February 2026.</p>
<p>You can find the previous editions collected under the
<a href="https://well-typed.com/blog/tags/haskell-ecosystem-report">haskell-ecosystem-report tag</a>.</p>
<h2 id="sponsorship">Sponsorship</h2>
<p>We offer <a href="https://well-typed.com/ecosystem/">Haskell Ecosystem Support Packages</a> to provide commercial
users with support from Well-Typed’s experts while investing in the Haskell
community and its technical ecosystem including through the work described in
this report. To find out more, read our <a href="https://well-typed.com/blog/2025/06/haskell-ecosystem-support-packages">announcement of these
packages</a> in partnership with
the Haskell Foundation. We need funding to continue this essential maintenance work!</p>
<p>Many thanks to our Haskell Ecosystem Supporters: <a href="https://www.sc.com/">Standard Chartered</a>,
<a href="https://www.channable.com/">Channable</a> and <a href="https://qbaylogic.com/">QBayLogic</a>,
as well as to our other clients who also contribute to making this work possible:
<a href="https://www.anduril.com/">Anduril</a>, <a href="https://juspay.in/">Juspay</a> and <a href="https://mercury.com/">Mercury</a>;
and to the <a href="https://opencollective.com/haskell-language-server">HLS Open Collective</a> for
supporting HLS release management.</p>
<h2 id="team">Team</h2>

<p><a href="https://well-typed.com/people/matthew">Matthew Pickering</a> announced that he will be leaving the company and moving to a non-Haskell
role at the end of March.
Working with Matt has been a joy – more than his deep technical insight
or sharp intuition, it’s the warmth of his vision for how to work together and
his generosity that has made him such a force within the team.
He was also a beacon that could rally the community in difficult times, perhaps
most memorably with his technical and social contributions in consolidating
Haskell IDEs with the creation of the Haskell Language Server.
His dedication to tooling has also been an inspiration, with his work on
<code>ghc-debug</code> and on profiling an invaluable contribution to our understanding
of memory usage of Haskell programs.</p>
<p>The Haskell toolchain team at Well-Typed currently includes:</p>
<ul>
<li><a href="https://well-typed.com/people/andreask">Andreas Klebinger</a></li>
<li><a href="https://well-typed.com/people/hannes">Hannes Siebenhandl</a></li>
<li><a href="https://well-typed.com/people/magnus">Magnus Viernickel</a></li>
<li><a href="https://well-typed.com/people/mikolaj">Mikolaj Konarski</a></li>
<li><a href="https://well-typed.com/people/rodrigo">Rodrigo Mesquita</a></li>
<li><a href="https://well-typed.com/people/sam">Sam Derbyshire</a></li>
<li><a href="https://well-typed.com/people/zubin">Zubin Duggal</a></li>
</ul>
<p>In addition, many others within Well-Typed contribute to GHC, Cabal, HLS
and other open source Haskell libraries and tools.
This report includes contributions from <a href="https://well-typed.com/people/alex">Alex Washburn</a>,
<a href="https://well-typed.com/people/duncan">Duncan Coutts</a>,
<a href="https://well-typed.com/people/wen">Wen Kokke</a> and <a href="https://well-typed.com/people/wolfgang">Wolfgang Jeltsch</a> in
particular.</p>
<p>We are active participants in community efforts for developing the Haskell language and libraries.
Rodrigo joined the <a href="https://github.com/ghc-proposals/ghc-proposals">GHC Steering Committee</a> in December,
alongside <a href="https://well-typed.com/people/adam">Adam Gundry</a>.
Wolfgang joined the <a href="https://github.com/haskell/core-libraries-committee">Core Libraries Committee</a> in February.</p>
<h2 id="highlights">Highlights</h2>
<h3 id="interactive-step-through-debugging">Interactive step-through debugging</h3>
<p>The <a href="https://well-typed.github.io/haskell-debugger/">Haskell Debugger</a> (<code>hdb</code>) has been made more robust and more features were implemented by Rodrigo, Matthew, and Hannes.
Most notably, the debugger now:</p>
<ul>
<li>Displays stack traces for bytecode and compiled code frames (provided the program and dependencies were compiled with <code>-finfo-table-map</code> for the latter)</li>
<li>Displays source locations and callstacks for exception breakpoints</li>
<li>Uses the external interpreter by default</li>
<li>Can be run on GHC itself!</li>
</ul>
<p>To run <code>hdb</code> you need to use GHC 9.14 and to configure the IDE accordingly. Please refer to the <a href="https://well-typed.github.io/haskell-debugger/#installation">installation instructions</a>. Apart from that, if HLS just works on your codebase, so should the debugger!</p>
<h3 id="live-monitoring-using-the-eventlog">Live monitoring using the eventlog</h3>
<p>GHC’s eventlog already lets Haskell programs emit rich runtime telemetry, but
the workflow has historically been to run the program to completion and inspect
the eventlog afterwards. <a href="https://github.com/well-typed/eventlog-live/"><code>eventlog-live</code></a>
allows us instead to monitor the program as it is running. Wen continued work on
this project, taking significant steps towards making it production-ready, including:</p>
<ul>
<li><p>extending <code>eventlog-live</code> with support for the OpenTelemetry protocol
(<a href="https://github.com/well-typed/eventlog-live/pull/119"><span>#119</span></a>),</p></li>
<li><p>bringing the underlying
<a href="https://github.com/well-typed/eventlog-socket/"><code>eventlog-socket</code></a> library
closer to being ready for general use, by
adding a testsuite (<a href="https://github.com/well-typed/eventlog-socket/pull/27"><span>#27</span></a>).
fixing a litany of issues with the C code
(<a href="https://github.com/well-typed/eventlog-socket/pull/38"><span>#38</span></a>), and
finalising the user-facing API (<a href="https://github.com/well-typed/eventlog-socket/pull/43"><span>#43</span></a>),</p></li>
<li><p>adding support for custom commands in
<a href="https://github.com/well-typed/eventlog-socket/"><code>eventlog-socket</code></a>
(<a href="https://github.com/well-typed/eventlog-socket/pull/36"><span>#36</span></a>).</p></li>
</ul>
<h3 id="trees-that-grow">Trees That Grow</h3>
<p>The <code>Language.Haskell.Syntax</code> module hierarchy is intended to be a stable,
public API for the Haskell AST — one that external tools could eventually depend
on without coupling themselves to GHC internals, reducing ecosystem breakage.
Right now, that goal is undermined by lingering dependencies on internal modules
under the <code>GHC</code> hierarchy.</p>
<p>Alex, with help from Rodrigo, has been systematically removing these edges in
the dependency graph:</p>
<ul>
<li><code>Language.Haskell.Syntax.Type</code> no longer depends <code>GHC.Utils.Panic</code>
(<a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15134">!15134</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26626">#26626</a>).</li>
<li><code>Language.Haskell.Syntax.Decls</code> no longer depends on <code>GHC.Unit.Module.Warnings</code>
(<a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15146">!15146</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26636">#26636</a>), nor on <code>GHC.Types.ForeignCall</code> (<a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15477">!15477</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26700">#26700</a>) or
<code>GHC.Types.Basic</code> (<a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15265">!15265</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26699">#26699</a>).</li>
<li><code>Language.Haskell.Syntax.Binds</code> no longer depends on <code>GHC.Types.Basic</code>
(<a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15187">!15187</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26670">#26670</a>).</li>
</ul>
<p>Once this work is done, it will be possible to consider moving the AST into a
separate package, and taking further steps towards increasing modularity of the
compiler.</p>
<h3 id="towards-a-standalone-base-package">Towards a standalone <code>base</code> package</h3>
<p>Historically, the <code>base</code> package was used as both the user-facing standard
library and a repository of GHC-specific internals, with much special treatment
in the compiler. This means GHC and <code>base</code> versions are tightly coupled, and
makes upgrading to new compiler versions unnecessarily difficult.</p>
<p>GHC developers have made significant progress towards making <code>base</code> a normal Haskell
package: <code>ghc-internal</code> has been split out as a separate library, <code>base</code> no
longer has a privileged unit-id in the compiler, and Cabal now allows
reinstalling it.</p>
<p>Matt posted a <a href="https://github.com/haskell/core-libraries-committee/issues/375#issuecomment-3646780735">summary of progress</a>
and outlined possible next steps
to seek community consensus on the direction of travel.
The <a href="https://github.com/well-typed/reinstallable-base">reinstallable-base</a> repository
collects documents and discussion on the effort.</p>
<p>Wolfgang continued various pieces of technical groundwork:</p>
<ul>
<li><p>cleaning up many unused known-key names in the compiler
(<a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15184">!15184</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15190">!15190</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15211">!15211</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15213">!15213</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15217">!15217</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15218">!15218</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15219">!15219</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15215">!15215</a>),</p></li>
<li><p>finishing the process of removing <code>GHC.Desugar</code> from <code>base</code> (<a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15433">!15433</a>),</p></li>
<li><p>refining the import list of <code>System.IO.OS</code> to aid in modularity (<a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15567">!15567</a>).</p></li>
</ul>
<p>Wolfgang improved the public API of <code>base</code> relating to OS handles, to make the
API more stable across platforms and avoid the need for users to depend on
GHC-internal implementation details (<a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/14732">!14732</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/14905">!14905</a>). While in the area, he
fixed a bug in the implementation of <code>hIsReadable</code> and <code>hIsWritable</code> for duplex
handles (<a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26479">#26479</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15227">!15227</a>), and a mistake in the documentation of <code>hIsClosed</code>
(<a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15228">!15228</a>).</p>
<h3 id="incorrect-absence-analysis-in-ghc">Incorrect absence analysis in GHC</h3>
<p>GHC bug <a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26416">#26416</a> has occupied the attention of the team for quite some time.
Initially thought to be an issue with specialisation, a reproducer that Sam and
Magnus created showed that the issue is in fact a bug in absence analysis
— an optimisation that identifies and removes unused function arguments —
in which GHC would erroneously conclude that a used argument was in fact absent.</p>
<p>Andreas helped investigate the root cause, before Zubin finally took the torch
and put up a solution (<a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15238">!15238</a>).</p>
<h3 id="ghc-changelogs">GHC changelogs</h3>
<p>GHC’s changelogs have not always been as complete or reliable as the
community deserves. Keeping changelogs accurate across backports has also been a
major source of frustration for release managers.</p>
<p>This is why, after a discussion initiated by Teo Camarasu in <a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26002">#26002</a>, we have decided
to adopt the <a href="https://codeberg.org/fgaz/changelog-d"><code>changelog.d</code></a> system —
already in use by the Cabal project — in which each change is a separate file
in the changelog directory.
This eliminates the merge conflicts that make backporting painful, and makes it
easier to associate MRs with changelog entries.</p>
<p>Zubin has been spearheading the effort, with the intention to switch to this
new method of changelog generation right after the fork date for GHC 10.0.</p>
<h2 id="ghc">GHC</h2>
<h3 id="ghc-releases">GHC Releases</h3>
<ul>
<li>Zubin worked on 9.12.3, backporting patches and preparing release candidates,
with a final release on the 27th of December.</li>
<li>Magnus and Zubin worked on backports for 9.12.4.</li>
<li>Zubin worked on 9.14.1, putting out the final release on the 19th of December.</li>
</ul>
<h3 id="frontend">Frontend</h3>
<ul>
<li><p>Sam reviewed the implementation of the <code>QualifiedStrings</code>
extension by Brandon Chinn (<a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/14975">!14975</a>).
This allows string literals of the form <code>ModName."foo"</code>
(interpreted as <code>ModName.fromString ("foo" :: String)</code>).</p></li>
<li><p>Sam made several changes to the treatment of <code>Coercible</code> constraints in the
typechecker (<a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/14100">!14100</a>):</p>
<ul>
<li>Defaulting of representational equalities to nominal equalities, functionality
previously added to GHC by Sam, is now more robust (<a href="https://gitlab.haskell.org/ghc/ghc/-/issues/25825">#25825</a>).</li>
<li>Error messages involving unsolved <code>Coercible</code> constraints are greatly
improved, an oft-requested improvement (<a href="https://gitlab.haskell.org/ghc/ghc/-/issues/15850">#15850</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/issues/20289">#20289</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/issues/23731">#23731</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26137">#26137</a>).
Error messages now consistently mention relevant out-of-scope data
constructors, provide import suggestions, and include additional
explanations about roles (when relevant).</li>
</ul></li>
<li><p>Magnus implemented several fixes to the implementation of <code>ExplicitLevelImports</code>:</p>
<ul>
<li>a missing check for types (<a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26098">#26098</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15119">!15119</a>),</li>
<li>a GHC panic in the driver (<a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26568">#26568</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15118">!15118</a>).</li>
</ul></li>
<li><p>Sam improved the reporting of “valid hole fits”, adding support for suggesting
bidirectional pattern synonyms (<a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26339">#26339</a>) and properly dealing with data
constructors with linear arguments (<a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26338">#26338</a>).</p></li>
<li><p>Sam investigated a typechecking regression starting in GHC 9.2 with the
introduction of the <code>Assert</code> type family to improve error messages involving
comparison of type-level literals (<a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26190">#26190</a>), posting <a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26190#note_646511">his analysis</a> to the ticket.
To tackle this, he opened <a href="https://github.com/ghc-proposals/ghc-proposals/pull/735">GHC proposal <span>#735</span></a>, which is still in need of further community feedback.</p></li>
<li><p>Sam minimised a bug with rewrite rules (<a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26682">#26682</a>), which allowed Simon Peyton Jones
to identify and fix the bug (<a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15208">!15208</a>).</p></li>
<li><p>Sam improved how existential variables are displayed in Haddock documentation
(<a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15099">!15099</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26252">#26252</a>).</p></li>
</ul>
<h4 id="determinism">Determinism</h4>
<ul>
<li>Matt identified and fixed several ways in which GHC compilation was not deterministic:
<ul>
<li>an issue with non-deterministic documentation information (<a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26858">#26858</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15482">!15482</a>).</li>
<li>non-determinism of constraint solving impacting generated <code>Typeable</code> evidence (<a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26846">#26846</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15442">!15442</a>).</li>
<li>issues with the Template Haskell machinery of the <code>singletons</code> library producing non-deterministic names
(<a href="https://github.com/goldfirere/singletons/pull/629"><code>singletons</code> <span>#629</span></a>,
<a href="https://github.com/goldfirere/th-desugar/pull/240"><code>th-desugar</code> <span>#240</span></a>).</li>
</ul></li>
</ul>
<h4 id="plugins">Plugins</h4>
<ul>
<li><p>Sam finished up and landed a long-standing MR by Chris Wendt (<a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/10133">!10133</a>) which
fixed a plugin-related issue.</p></li>
<li><p>Sam fixed a regression in <a href="https://hackage.haskell.org/package/ghc-typelits-natnormalise"><code>ghc-typelits-natnormalise</code></a>
in which the plugin would cause GHC to fall into an infinite loop
(<a href="https://github.com/clash-lang/ghc-typelits-natnormalise/issues/116"><code>ghc-typelits-natnormalise</code> <span>#116</span></a>, <a href="https://github.com/clash-lang/ghc-typelits-natnormalise/pull/118"><span>#118</span></a>).</p></li>
</ul>
<h3 id="backend">Backend</h3>
<ul>
<li><p>Rodrigo announced that work described in <a href="https://gitlab.haskell.org/ghc/ghc/-/issues/23218">#23218</a> evolved into the <a href="https://dl.acm.org/doi/10.1145/3776711">POPL 2026
paper “Lazy Linearity for a Core Functional Language”</a>,
which presents a way to type linearity in GHC Core that is robust to almost
all GHC optimisations, together with a GHC plugin validating programs at
each optimisation stage.</p></li>
<li><p>With the oversight of Andreas, Sam carefully reconsidered the treatment of
register formats in the register allocator and liveness analysis. This
culminated in <a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15121">!15121</a>:</p>
<ul>
<li>Keep track of register formats in liveness analysis (<a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26526">#26526</a>).</li>
<li>Use the right format when reloading spilled register (<a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26411">#26411</a>).</li>
<li>Enforce the invariant that writes to a register re-defined the format that
this register is used at for the purposes of liveness analysis, fixing another
bug reported by <code>@aratamizuki</code> on <a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15121#note_647685"><span>!15121</span></a>.</li>
</ul></li>
<li><p>Sam put up a small fix for the mapping of registers to stack slots, fixing
an oversight in the case that registers start off small and are subsequently
written at larger widths (<a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26668">#26668</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15185">!15185</a>).</p></li>
<li><p>Sam reviewed a GHC contribution by <code>@sgillespie</code> adding SIMD primops for
<code>abs</code> and <code>sqrt</code> operations (<a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15236">!15236</a>), suggesting more efficient implementations of
certain operations.</p></li>
<li><p>Andreas investigated potential missed specialisations,
which allowed Simon Peyton Jones to make further progress in
improving the specialiser (<a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26831">#26831</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15441">!15441</a>).</p></li>
<li><p>Sam investigated several bugs to do with the interactions of join points with
ticks (<a href="https://gitlab.haskell.org/ghc/ghc/-/issues/14242">#14242</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26157">#26157</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26642">#26642</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26693">#26693</a>) and casts (<a href="https://gitlab.haskell.org/ghc/ghc/-/issues/14610">#14610</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/issues/21716">#21716</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26422">#26422</a>).
He fixed the main bug (<a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26642">#26642</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15538">!15538</a>), which was due to incorrect
transformations in <code>mergeCaseAlts</code>. He also undertook a general refactor of
the area and, pinning down the overall handling of casts and ticks under
join points in a Note.</p></li>
</ul>
<h3 id="runtime-system-and-linker">Runtime system and linker</h3>
<ul>
<li><p>Matt fixed a decoding failure for <code>stg_dummy_ret</code> by using <code>INFO_TABLE_CONSTR</code>
for its closure (<a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26745">#26745</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15303">!15303</a>).</p></li>
<li><p>Duncan fixed long-standing inconsistencies in eventlog <code>STOP_THREAD</code> status
codes (<a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26867">#26867</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15522">!15522</a>).</p></li>
<li><p>Andreas improved the documentation of the <code>-K</code> RTS flag in <a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15365">!15365</a> (<a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26354">#26354</a>).</p></li>
</ul>
<h3 id="exception-backtraces-stack-annotations-and-stack-decoding">Exception backtraces, stack annotations and stack decoding</h3>
<ul>
<li><p>Matt and Hannes improved the reporting of backtraces when using <code>error</code>
(<a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15306">!15306</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15395">!15395</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26751">#26751</a>). This involved opening two CLC proposals
(<a href="https://github.com/haskell/core-libraries-committee/issues/383">CLC <span>#383</span></a>,
<a href="https://github.com/haskell/core-libraries-committee/issues/387">CLC <span>#387</span></a>).</p></li>
<li><p>Hannes continued working on the implementation of stack annotations and stack
decoding (<a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26218">#26218</a>), including:</p>
<ul>
<li>integrating <a href="https://github.com/well-typed/ghc-stack-profiler"><code>ghc-stack-profiler</code></a>,
a profiler that relies on stack annotations instead of heavier profiling
mechanisms, with the <a href="https://github.com/well-typed/eventlog-socket"><code>eventlog-socket</code></a>
library; and</li>
<li>working on the <a href="https://github.com/well-typed/ghc-stack-annotations"><code>ghc-stack-annotations</code></a>
compatibility library for annotating the stack.</li>
</ul></li>
<li><p>Rodrigo removed an incorrect assertion that fired when decoding a BCO whose
bitmap has no payload (<a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26640">#26640</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15136">!15136</a>).</p></li>
</ul>
<h3 id="build-system-and-packaging">Build system and packaging</h3>
<ul>
<li><p>Zubin fixed a GHC 9.14.1 build issue due to missing <code>.cabal</code> files for
<code>ghc-experimental</code> and <code>ghc-internal</code> in the source tarball (<a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26738">#26738</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15391">!15391</a>).</p></li>
<li><p>Andreas investigated the use of Cabal’s <code>--semaphore</code> feature to speed up GHC builds slightly (<a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26876">#26876</a>, <a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15483">!15483</a>).
There are some issues preventing us from enabling this unconditionally
(<a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26977">#26977</a>, <a href="https://github.com/haskell/cabal/issues/11557"><code>Cabal</code> <span>#11557</span></a>).</p></li>
</ul>
<h3 id="ci-and-testing">CI and testing</h3>
<ul>
<li><p>Magnus ensured the user’s guide can be generated with old versions of Python
to fix CI build failures on some older containers (<a href="https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15127">!15127</a>).</p></li>
<li><p>Magnus updated the Debian images used for CI (<a href="https://gitlab.haskell.org/ghc/ci-images/-/merge_requests/183"><code>ci-images</code> <span>!183</span></a>,
<a href="https://gitlab.haskell.org/ghc/ci-images/-/merge_requests/178"><span>!178</span></a>).</p></li>
<li><p>Sam finished up the work of Sven Tennie on testing floating point expressions
in the <a href="https://gitlab.haskell.org/ghc/test-primops"><code>test-primops</code></a> test
framework for GHC (<a href="https://gitlab.haskell.org/ghc/test-primops/-/merge_requests/19"><code>test-primops</code> <span>!19</span></a>).
This is preparatory work for improving the robustness of GHC’s handling of
floating point (<a href="https://gitlab.haskell.org/ghc/ghc/-/issues/26919">#26919</a>).</p></li>
<li><p>Andreas updated the <code>nofib</code> GHC benchmarking suite to fix issues that Sam ran
into when trying to use it, updating the CI in the process
(<a href="https://gitlab.haskell.org/ghc/nofib/-/merge_requests/81"><code>nofib</code> <span>!81</span></a>, <a href="https://gitlab.haskell.org/ghc/nofib/-/merge_requests/82"><span>!82</span></a>, <a href="https://gitlab.haskell.org/ghc/nofib/-/merge_requests/83"><span>!83</span></a>).</p></li>
</ul>
<h3 id="infrastructure">Infrastructure</h3>
<ul>
<li><p>Magnus worked on the infrastructure for the GitLab instance used for the GHC
project, bringing up new runners for CI and switching to a new verification
system to approve new users which makes it easier for new contributors to
open issues.</p></li>
<li><p>Magnus and Andreas helped the Haskell infrastructure team address Gitlab outages on short notice in order to improve availability of the GHC Gitlab instance.</p></li>
<li><p>Andreas and Magnus organized temporary CI capabilities sponsored by WT during a temporary outage of one of GHC’s CI runners.</p></li>
</ul>
<h2 id="cabal">Cabal</h2>
<ul>
<li><p>Sam added support for setting the logging handle via the library interface of <code>Cabal</code>,
a significant milestone in updating <code>cabal-install</code> to compile packages with
the <code>Cabal</code> library without invoking external processes (<a href="https://github.com/haskell/cabal/pull/11077"><code>Cabal</code> <span>#11077</span></a>).</p></li>
<li><p>Matt helped Matthías Páll Gissurarson to fix a bug in which <code>cabal haddock</code> was looking for
files in the wrong directory (<a href="https://github.com/haskell/cabal/issues/11475"><code>Cabal</code> <span>#11475</span></a>, <a href="https://github.com/haskell/cabal/pull/11476"><span>#11476</span></a>).</p></li>
<li><p>Matt fixed a bug with broken Haddocks locally due to non-expanded <code>${pkgroot}</code>
variable (<a href="https://github.com/haskell/cabal/issues/11217"><code>Cabal</code> <span>#11217</span></a>,
<a href="https://github.com/haskell/cabal/pull/11218"><span>#11218</span></a>).</p></li>
<li><p>Matt fixed some issues with <code>cabal repl</code> silently failing
(<a href="https://github.com/haskell/cabal/issues/11107"><code>Cabal</code> <span>#11107</span></a>,
<a href="https://github.com/haskell/cabal/pull/11237"><span>#11237</span></a>).</p></li>
</ul>
<h2 id="hls">HLS</h2>
<ul>
<li><p>In collaboration with Zubin and Andreas, Hannes investigated the root cause of
<a href="https://github.com/haskell/haskell-language-server/issues/4674">HLS issue <span>#4674</span></a>,
posting his analysis in <a href="https://github.com/haskell/haskell-language-server/issues/4674#issuecomment-3527937881">this comment</a>.
In short, the problem was that the <code>hlint</code> plugin was using an incompatible
version of <code>ghc-lib-parser</code>, and a version mismatch in this library was causing
segfaults due to changes to the <code>GHC.Data.FastString</code> implementation between
the versions.
Hannes disabled the <code>hlint</code> plugin on GHC 9.10 to work around this issue
(<a href="https://github.com/haskell/haskell-language-server/pull/4767">HLS PR <span>#4767</span></a>).</p></li>
<li><p>Hannes reviewed and assisted with <a href="https://github.com/haskell/haskell-language-server/pull/4856">HLS PR <span>#4856</span></a>
by <code>@vidit-od</code>. This PR makes HLS use the stored server-side diagnostics for
code actions, in order to make them more responsive. This fixes <a href="https://github.com/haskell/haskell-language-server/issues/4805">HLS issue <span>#4805</span></a>.</p></li>
<li><p>Hannes helped land long-running <a href="https://github.com/haskell/haskell-language-server/pull/4445">HLS PR <span>#4445</span></a>
by <code>@soulomoon</code>, which allows files to be loaded concurrently in batches in
order to improve responsiveness of HLS.</p></li>
<li><p>Zubin and Hannes worked together to update HLS to work with GHC 9.14 (<a href="https://github.com/haskell/haskell-language-server/pull/4780">HLS PR <span>#4780</span></a>).</p></li>
<li><p>Hannes worked on general maintenance of the HLS project:</p>
<ul>
<li>Prepared release 2.13.0.0 (<a href="https://github.com/haskell/haskell-language-server/pull/4785">HLS PR <span>#4785</span></a>)</li>
<li>Tackled various CI issues (<a href="https://github.com/haskell/haskell-language-server/pull/4863">HLS PR <span>#4863</span></a>,
<a href="https://github.com/haskell/haskell-language-server/pull/4812">HLS PR <span>#4812</span></a>,
<a href="https://github.com/haskell/haskell-language-server/pull/4811">HLS PR <span>#4811</span></a>)</li>
<li>Updated the advertised range of supported GHC versions (<a href="https://github.com/haskell/haskell-language-server/pull/4801">HLS PR <span>#4801</span></a>, <a href="https://github.com/haskell/haskell-language-server/pull/4799">HLS PR <span>#4799</span></a>)</li>
</ul></li>
<li><p>Hannes and Zubin implemented some fixes to Windows CI (<a href="https://github.com/haskell/haskell-language-server/pull/4800">HLS PR <span>#4800</span></a>, <a href="https://github.com/haskell/haskell-language-server/pull/4768">HLS PR <span>#4768</span></a>).</p></li>
<li><p>Hannes merged the <code>hls-module-name-plugin</code> into <code>hls-rename-plugin</code> in
<a href="https://github.com/haskell/haskell-language-server/pull/4847">HLS PR <span>#4847</span></a>.</p></li>
<li><p>Hannes improved the robustness of the <code>hls-call-hierarchy-plugin-tests</code> in
<a href="https://github.com/haskell/haskell-language-server/pull/4834">HLS PR <span>#4834</span></a>
by using <code>VirtualFileTree</code>.</p></li>
<li><p>Hannes also worked on <code>hie-bios</code>:</p>
<ul>
<li>Preparing release 0.18.0.0 (<a href="https://github.com/haskell/hie-bios/pull/496"><code>hie-bios</code> PR <span>#496</span></a>)</li>
<li>Updated the supported GHC versions (<a href="https://github.com/haskell/hie-bios/pull/495"><code>hie-bios</code> PR <span>#495</span></a>)</li>
<li>Adapted to GHC migrating some parts of its codebase to use <code>OsPath</code> (<a href="https://github.com/haskell/hie-bios/pull/493"><code>hie-bios</code> PR <span>#493</span></a>)</li>
</ul></li>
</ul>
<h2 id="haskell-debugger">Haskell Debugger</h2>
<p>Rodrigo continued work on the new <a href="https://github.com/well-typed/haskell-debugger">Haskell Debugger</a>.</p>
<ul>
<li><p>Matt and Rodrigo introduced a DSL for evaluation on the remote process, which
allows the debuggee to be queried from a custom instance, making it possible
to implement visualisations which rely on e.g. evaluatedness of a term
(<a href="https://github.com/well-typed/haskell-debugger/pull/139"><span>#139</span></a>).</p></li>
<li><p>Matt improved support for exceptions: break-on-exception breakpoints now provide
source locations (<a href="https://github.com/well-typed/haskell-debugger/pull/165"><span>#165</span></a>).</p></li>
<li><p>Rodrigo allowed call stacks to be inspected in the debugger (<a href="https://github.com/well-typed/haskell-debugger/pull/158"><span>#158</span></a>).</p></li>
<li><p>Hannes introduced support for stack decoding and viewing custom stack annotations
(<a href="https://github.com/well-typed/haskell-debugger/pull/172"><span>#172</span></a>).</p></li>
<li><p>Rodrigo made the Haskell Debugger use the external interpreter (<a href="https://github.com/well-typed/haskell-debugger/pull/170"><span>#170</span></a>),
which paves the way for multi-threaded debugging (see also <a href="https://github.com/well-typed/haskell-debugger/pull/140"><span>#140</span></a>).
This change also allowed Rodrigo to implement Windows support (<a href="https://github.com/well-typed/haskell-debugger/pull/184"><span>#184</span></a>)
with the help of Hannes.</p></li>
<li><p>Matt fixed a bug in the handling of data constructors with constraints
(<a href="https://github.com/well-typed/haskell-debugger/pull/175"><span>#175</span></a>).</p></li>
<li><p>Hannes improved caching in the CI (<a href="https://github.com/well-typed/haskell-debugger/pull/173"><span>#173</span></a>).</p></li>
</ul>
<h2 id="ghc-debug"><code>ghc-debug</code></h2>
<ul>
<li><p>Matt and Hannes fixed several issues with <code>AP_STACK</code> closures
(<a href="https://gitlab.haskell.org/ghc/ghc-debug/-/merge_requests/79"><span>!79</span></a>,
<a href="https://gitlab.haskell.org/ghc/ghc-debug/-/merge_requests/80"><span>!80</span></a>,
<a href="https://gitlab.haskell.org/ghc/ghc-debug/-/merge_requests/86"><span>!86</span></a>).</p></li>
<li><p>Hannes implemented asynchronous heap traversal in <code>ghc-debug-brick</code>,
making the interface more responsive
(<a href="https://gitlab.haskell.org/ghc/ghc-debug/-/merge_requests/78"><span>!78</span></a>).</p></li>
<li><p>Hannes added history navigation and search caching to the <code>ghc-debug-brick</code>
interface
(<a href="https://gitlab.haskell.org/ghc/ghc-debug/-/merge_requests/83"><span>!83</span></a>).</p></li>
<li><p>Hannes added a summary row to the string counting table view
(<a href="https://gitlab.haskell.org/ghc/ghc-debug/-/merge_requests/81"><span>!81</span></a>), and
fixed the search limit not being honoured during incremental searches
(<a href="https://gitlab.haskell.org/ghc/ghc-debug/-/merge_requests/76"><span>!76</span></a>).</p></li>
</ul></div>
    </content>
    <updated>2026-03-19T00:00:00Z</updated>
    <published>2026-03-19T00:00:00Z</published>
    <category term="well-typed"/>
    <category term="ghc"/>
    <category term="community"/>
    <category term="haskell-ecosystem-report"/>
    <author>
      <name>adam, andreask, hannes, magnus, matthew, mikolaj, rodrigo, sam, zubin</name>
    </author>
    <source>
      <id>https://well-typed.com/blog/</id>
      <logo>https://well-typed.com/img/wtnlogoplain.svg</logo>
      <link href="https://well-typed.com/blog/rss2.xml" rel="self" type="application/rss+xml"/>
      <link href="https://well-typed.com/blog/" rel="alternate" type="text/html"/>
      <subtitle>Because Well-Typed Programs Don't Go Wrong</subtitle>
      <title>Well-Typed Blog</title>
      <updated>2026-05-28T00:00:00Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:,2026:/math/egyptian-fractions-2</id>
    <link href="https://blog.plover.com/math/egyptian-fractions-2.html" rel="alternate" type="text/html"/>
    <title>Did Ahmes find the best expansions for 2/n?</title>
    <content type="xhtml" xml:lang="en"><div xmlns="http://www.w3.org/1999/xhtml"><p>A couple of years back <a href="https://blog.plover.com/math/egyptian-fractions.html">I was discussing the Rhind Mathematical Papyrus</a>
(RMP).  It includes a table expressing <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%24%5cfrac%202n%24"/> as a sum
$$\frac1{a_1}+\frac1{a_2}+\dots+\frac1{a_k} $$ fractions with
numerator 1 (“unit fractions”).  I said:</p>

<blockquote>
  <p>Getting the table of good-quality representations of <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%24%5cfrac%202n%24"/> is not
  trivial, and requires searching, number theory, and some trial and
  error. It's not at all clear that <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%24%5cfrac2%7b105%7d%3d%5cfrac1%7b90%7d%20%2b%0a%3e%20%5cfrac1%7b126%7d%24"/>.</p>
</blockquote>

<p>Today I wondered: <em>did</em> Ahmes (the author) have the best possible
expansions for all the <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%24%5cfrac2n%24"/> values, or were there some
improvements the Egyptians had missed?</p>

<p>It turns out, yes!  Or rather, maybe!</p>

<p>In
<a href="https://www.sciencedirect.com/science/article/pii/S0315086007000274?via%3Dihub">On the Egyptian method of decomposing <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%242%2fn%24"/> into unit fractions</a>
the author, Abdulrahman A. Abdulaziz, points out that for
<img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%24%5cfrac2%7b95%7d%24"/> the Rhind Mathematical Papyrus gives the expansion
$$\frac2{95} = \frac1{60} + \frac1{380} + \frac1{570}$$</p>

<p>but <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%24%5cfrac1%7b380%7d%20%2b%20%5cfrac1%7b570%7d%20%3d%20%5cfrac1%7b228%7d%24"/> so it could have been
written as $$\frac2{95} = \frac1{60}+\frac1{228}.$$</p>

<p>But wait, maybe that <em>wasn't</em> an error.  The Egyptians, like everyone,
often had to multiply by 10.  (In fact, the RMP itself, right after
its <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%24%5cfrac%202n%24"/> table, has a shorter table of expansions of <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%24%5cfrac%0an%7b10%7d%24"/>.)  And <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%24%5cfrac1%7b60%7d%20%2b%20%5cfrac1%7b380%7d%20%2b%20%5cfrac1%7b570%7d%24"/> is trivially
multiplied by 10, whereas <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%24%5cfrac1%7b228%7d%24"/>  isn't.  There is some
indication that Ahmes preferred fractions with even denominators,
because they are easier to double, and the usual Egyptian method of
multiplication required repeated doubling.  But the Egyptians also
sometimes decupled while multiplying, and the <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%24%5cfrac1%7b60%7d%20%2b%0a%5cfrac1%7b380%7d%20%2b%20%5cfrac1%7b570%7d%24"/>  expansion would have made both of those
easy.</p>

<p>The methods by which Ahmes chose the expansions of <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%24%5cfrac%202n%24"/>, and
the criteria by which he preferred one to another, are still unknown;
he doesn't explain them.  So it's tough to say that any item was or
wasn't “best” from Ahmes' point of view.</p></div>
    </content>
    <updated>2026-03-17T13:28:00Z</updated>
    <published>2026-03-17T13:28:00Z</published>
    <category term="/math"/>
    <author>
      <name>Mark Dominus</name>
      <email>mjd@plover.com</email>
      <uri>http://www.plover.com/</uri>
    </author>
    <source>
      <id>tag:,2005:/</id>
      <icon>http://perl.plover.com/favicon.ico</icon>
      <link href="https://blog.plover.com/index.atom" rel="self" type="application/atom+xml"/>
      <link href="https://blog.plover.com" rel="alternate" type="text/html"/>
      <subtitle>The Universe of Discourse (Mark Dominus Blog)</subtitle>
      <title>The Universe of Discourse</title>
    </source>
  </entry>

  <entry xml:lang="en-us">
    <id>https://haskellforall.com/2026/03/a-sufficiently-detailed-spec-is-code</id>
    <link href="https://haskellforall.com/2026/03/a-sufficiently-detailed-spec-is-code" rel="alternate" type="text/html"/>
    <title>A sufficiently detailed spec is code</title>
    <summary>Specifications do not address the limitations of agentic coding</summary>
    <updated>2026-03-17T00:00:00Z</updated>
    <published>2026-03-17T00:00:00Z</published>
    <source>
      <id>https://haskellforall.com</id>
      <author>
        <name>Gabriella Gonzalez</name>
      </author>
      <link href="https://haskellforall.com" rel="alternate" type="text/html"/>
      <link href="https://haskellforall.com/rss.xml" rel="self" type="application/rss+xml"/>
      <subtitle>A blog about Haskell and functional programming.</subtitle>
      <title>Haskell for all</title>
      <updated>2026-06-07T13:45:09Z</updated>
    </source>
  </entry>

  <entry>
    <id>https://medium.com/p/d4811e66120b</id>
    <link href="https://cdsmithus.medium.com/to-flip-or-not-to-flip-d4811e66120b?source=rss-18bd5acaea78------2" rel="alternate" type="text/html"/>
    <title>To Flip Or Not To Flip</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p><em>A fair coin, an unfair offer, and the price of certainty.</em></p><p>I sat down to work out a classic probability problem numerically, and accidentally built a casino.</p><h3>The Problem of Points</h3><p>In 1654, a gambler named Antoine Gombaud posed a question to Blaise Pascal: two players are in a race to win a certain number of points. The game is interrupted. How should they divide the pot?</p><p>Pascal wrote to Fermat, and their correspondence became one of the founding documents of probability theory. The answer is elegant: if you need <em>a</em> more points and your opponent needs <em>b</em> more, you can compute the fair split with a simple recurrence. Let P(a, b) be your probability of winning:</p><ul><li>P(0, b) = 1 — you just won</li><li>P(a, 0) = 0 — your opponent just won</li><li>P(a, b) = ½ · P(a−1, b) + ½ · P(a, b−1)</li></ul><p>Every value in this table is a fraction with a power-of-2 denominator, and the numerators are just Pascal’s triangle. Beautiful math, clean solution, problem solved since the 17th century.</p><p>I built an interactive table to explore it. And then I thought: what if this were a game?</p><h3>The Game</h3><p>You and The House race to a target score. Each round, a fair coin is flipped — heads you score, tails The House scores. First to the target wins a pot of money.</p><p>But before each flip, judges look at the current game state, consult the probability table, and offer you cash to walk away. Accept, and you take the money. Decline, and the coin is flipped.</p><p>The question, every single round, is: <em>to flip or not to flip?</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/796/1*UNqw2J4ROuCLqAwivdI_kQ.png"/></figure><p>You can play at <a href="https://willowdale.online/flip">willowdale.online/flip</a>.</p><h3>How the Judges Set Their Offers</h3><p>The judges know the exact fair value of your position — they have the same formula Pascal and Fermat computed. If you have a 37.5% chance of winning a $10,000 pot, your fair value is $3,750.</p><p>But they don’t offer fair value. They offer the nearest “clean” fraction of the pot that sits strictly <em>below</em> your true odds.</p><p>“Clean” means small denominators whose only prime factors are 2, 3, and 5 — fractions like 1/3, 3/8, 7/20, nothing with a denominator above 20. These produce dollar amounts that look like something a human came up with: $3,333, $3,750, $3,500. Not $3,077 or $3,846, which look like someone ran the numbers to the last penny.</p><p>So if your fair value is $3,770 (193/512 of the pot), the judges offer $3,750 (3/8). Barely below fair, and a beautifully round number. If your fair value is $1,875 (3/16), they offer $1,666 (1/6). An 89% offer — a real discount, but still a clean, human-sounding number.</p><p>This matters psychologically. Round numbers feel like ballpark estimates — casual, generous, not fully analyzed. Precise numbers feel calculated. When the judges offer $7,500, it sounds reasonable. If they offered $7,517, you’d immediately suspect they did the math and it’s in their favor. The irony is that $7,517 is a <em>better</em> deal for you — but I think you’d be less likely to take it. The round number keeps your guard down.</p><p>The algorithm is deterministic — same game state, same offer every time. Just math dressed up in a game show contract.</p><h3>Why People Sign</h3><p>Since the offers are always strictly below fair value, the play that maximizes your expected winnings is to <em>never accept a deal</em>. The coin is fair, the game has zero house edge, and every offer leaves money on the table. A player who always flips would win 50% of their games and, on average, neither gain nor lose.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/809/1*bIC-rVKVQv62gnpV455J3A.png"/></figure><p>And yet.</p><p>When you’re ahead 4–3 in a race to 10, and the contract says $6,000, and you’ve already paid $5,000 to enter this game… you hesitate. That’s a guaranteed profit. The alternative is variance — maybe you win $10,000, but you are not that far ahead. Maybe your luck turns and you lose everything.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/786/1*s4_Dy1tM1WLf2Dbo7DfVVA.png"/></figure><p>You <em>know</em> the offer is below fair. You can peek behind the curtain and see the exact numbers. The judges are shortchanging you by $128. But $128 feels like nothing when the alternative is watching your lead evaporate flip by flip.</p><p>So you sign. And $128 goes into the casino’s pocket.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/802/1*sZAWF6XdrMOb3dWu0Pxxmg.png"/></figure><p>This is what makes the game unusual. In blackjack or roulette, the house edge is baked into the rules — you can’t avoid it no matter how disciplined you are. Here, the game has no edge at all. The coin is fair. The race is symmetric. The <em>only</em> source of profit is human nature. Every dollar the casino makes is expected value that a player voluntarily left on the table.</p><p>Play for a while and you start to notice specific situations where the offer gets harder to refuse.</p><p><strong>Managing risk.</strong> A guaranteed $7,500 is safer than a coin flip worth $7,734. In real life, you might need that money for rent. Variance has a real cost, and paying a premium for certainty can be entirely rational. There is a sophisticated argument for sometimes making decisions that reduce your expected value: bankroll management, survival probability and duration. Here the stakes are fictional, your bankroll buys nothing except more fair coin flips, and going broke is solved by refreshing your web browser, so that case is weaker — but it doesn’t feel weaker when your bankroll is shrinking and the judges are holding out real-looking money.</p><p><strong>Mis-anchoring.</strong> The rational comparison is always between the offer and the expected value of continuing to flip. But that’s rarely the comparison your brain actually makes. If you were staring at a $0 offer last round and now the judges are offering $500, you’re comparing to the $0 — not to the $625 fair value. If your bankroll started at $10,000 and you’re down to $7,000, and the judges offer $3,200, you’re comparing to $10,000 — because taking the deal would put you above where you started. In both cases, the reference point that feels relevant has nothing to do with the expected value of this game.</p><p><strong>Black and white thinking.</strong> When you’re behind in the race, the most likely single outcome is that you lose. If the judges offer $500 and your odds of winning are 6%, it feels like a choice between $500 and nothing. But expected value accounts for the 6% — the rare wins are big enough to compensate for all the losses across many games. You just don’t experience many games at once. You experience this one, where you’ll probably lose, and where the person who took $500 looks smart 94 times out of 100.</p><p><strong>Imaginary momentum.</strong> You lose three flips in a row and it feels like the coin has turned against you — time to take the deal before things get worse. Or you win three in a row and feel like you’re on a streak that shouldn’t be interrupted. The coin has no memory. Each flip is independent. But the human brain is a pattern-recognition machine, and it will find narratives in random sequences whether they’re there or not.</p><h3>The Optimal Judges</h3><p>The judges in this game are clever, but simple — they mechanically pick the nearest clean fraction below fair value, blind to everything except the current expected value.</p><p>But the <em>optimal</em> offer would be very different. The right objective isn’t just the EV gap (fair value minus offer). It’s:</p><p><strong>EV gap × P(acceptance | entire game trajectory)</strong></p><p>A huge gap with low acceptance is worthless — the player just turns it down. A tiny gap with high acceptance is pennies. The sweet spot is a moderate discount the player <em>almost</em> can’t refuse.</p><p>And that acceptance probability depends on far more than just the current score — it depends on everything described above: the bankroll trajectory, the recent streak, what the last offer was, how long the player has been sitting there.</p><p>A perfect judge would think about all of this, and decide exactly what it can get you — tired, frustrated, scared little you — to accept. The clean-fraction heuristic doesn’t. And yet it still works. I still sign those offers.</p><h3>The Lesson</h3><p>The game is a playable demonstration of why casinos stay in business, maybe even why people accept below-market returns for safety, and why insurance companies are profitable.</p><p>The math is always available — right there behind a curtain. If your goal is to maximize expected dollars, the answer is always to flip the coin. And yet, round after round, the judges offer deals, and I sign them.</p><p><em>Play the game at </em><a href="https://willowdale.online/flip"><em>willowdale.online/flip</em></a><em>. It’s free, the coin is fair, and you will almost certainly take a deal you know you shouldn’t.</em></p><img alt="" height="1" src="https://medium.com/_/stat?event=post.clientViewed&amp;referrerSource=full_rss&amp;postId=d4811e66120b" width="1"/></div>
    </content>
    <updated>2026-03-16T12:00:03Z</updated>
    <published>2026-03-14T00:48:43Z</published>
    <category term="finance"/>
    <category term="game-theory"/>
    <category term="mathematics"/>
    <category term="probability"/>
    <author>
      <name>Chris Smith</name>
    </author>
    <source>
      <id>https://medium.com/@cdsmithus?source=rss-18bd5acaea78------2</id>
      <logo>https://cdn-images-1.medium.com/fit/c/150/150/1*rU9ddF_bkph8Qg3jip7vfw.jpeg</logo>
      <link href="https://medium.com/@cdsmithus?source=rss-18bd5acaea78------2" rel="alternate" type="text/html"/>
      <link href="https://medium.com/@cdsmithus/feed" rel="self" type="application/rss+xml"/>
      <link href="http://medium.superfeedr.com" rel="hub" type="text/html"/>
      <subtitle>Stories by Chris Smith on Medium</subtitle>
      <title>Stories by Chris Smith on Medium</title>
      <updated>2026-06-13T05:53:38Z</updated>
    </source>
  </entry>

  <entry>
    <id>http://haskell.org/ghc/blog/20260313-ghc-9.12.4-rc1-released.html</id>
    <link href="http://haskell.org/ghc/blog/20260313-ghc-9.12.4-rc1-released.html" rel="alternate" type="text/html"/>
    <title>GHC 9.12.4-rc1 is now available</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><h1>GHC 9.12.4-rc1 is now available</h1>
<h4 class="text-muted">wz1000 - 2026-03-13</h4>

<p>The GHC developers are very pleased to announce the availability
of the release candidate for GHC 9.12.4. Binary distributions, source
distributions, and documentation are available at <a href="https://downloads.haskell.org/ghc/9.12.4-rc1">downloads.haskell.org</a> and
via <a href="https://www.haskell.org/ghcup/">GHCup</a>.</p>
<p>GHC 9.12.4 is a bug-fix release fixing many issues of a variety of
severities and scopes, including:</p>
<ul>
<li>Fixed a critical code generation regression where sub-word division produced
incorrect results (<a href="https://gitlab.haskell.org/ghc/ghc/issues/26711">#26711</a>, <a href="https://gitlab.haskell.org/ghc/ghc/issues/26668">#26668</a>), similar to the bug fixed in 9.12.2</li>
<li>Numerous fixes for register allocation bugs, preventing data corruption
when spilling and reloading registers
(<a href="https://gitlab.haskell.org/ghc/ghc/issues/26411">#26411</a>, <a href="https://gitlab.haskell.org/ghc/ghc/issues/26526">#26526</a>, <a href="https://gitlab.haskell.org/ghc/ghc/issues/26537">#26537</a>, <a href="https://gitlab.haskell.org/ghc/ghc/issues/26542">#26542</a>, <a href="https://gitlab.haskell.org/ghc/ghc/issues/26550">#26550</a>)</li>
<li>Fixes for several compiler crashes, including issues with
CSE (<a href="https://gitlab.haskell.org/ghc/ghc/issues/25468">#25468</a>), SetLevels (<a href="https://gitlab.haskell.org/ghc/ghc/issues/26681">#26681</a>),
implicit parameters (<a href="https://gitlab.haskell.org/ghc/ghc/issues/26451">#26451</a>), and the type-class specialiser (<a href="https://gitlab.haskell.org/ghc/ghc/issues/26682">#26682</a>)</li>
<li>Fixed cast worker/wrapper incorrectly firing on INLINE functions (<a href="https://gitlab.haskell.org/ghc/ghc/issues/26903">#26903</a>)</li>
<li>Fixed LLVM backend miscompilation of bit manipulation operations
(<a href="https://gitlab.haskell.org/ghc/ghc/issues/20645">#20645</a>, <a href="https://gitlab.haskell.org/ghc/ghc/issues/26065">#26065</a>, <a href="https://gitlab.haskell.org/ghc/ghc/issues/26109">#26109</a>)</li>
<li>Fixed associated type family and data family instance changes not triggering
recompilation (<a href="https://gitlab.haskell.org/ghc/ghc/issues/26183">#26183</a>, <a href="https://gitlab.haskell.org/ghc/ghc/issues/26705">#26705</a>)</li>
<li>Fixed negative type literals causing the compiler to hang (<a href="https://gitlab.haskell.org/ghc/ghc/issues/26861">#26861</a>)</li>
<li>Improvements to determinism of compiler output (<a href="https://gitlab.haskell.org/ghc/ghc/issues/26846">#26846</a>, <a href="https://gitlab.haskell.org/ghc/ghc/issues/26858">#26858</a>)</li>
<li>Fixes for eventlog shutdown deadlocks (<a href="https://gitlab.haskell.org/ghc/ghc/issues/26573">#26573</a>)
and lost wakeups in the RTS (<a href="https://gitlab.haskell.org/ghc/ghc/issues/26324">#26324</a>)</li>
<li>Fixed split sections support on Windows (<a href="https://gitlab.haskell.org/ghc/ghc/issues/26696">#26696</a>, <a href="https://gitlab.haskell.org/ghc/ghc/issues/26494">#26494</a>) and the LLVM backend (<a href="https://gitlab.haskell.org/ghc/ghc/issues/26770">#26770</a>)</li>
<li>Fixes for the bytecode compiler, PPC native code generator, and Wasm backend</li>
<li>The runtime linker now supports COMMON symbols (<a href="https://gitlab.haskell.org/ghc/ghc/issues/6107">#6107</a>)</li>
<li>Improved backtrace support: backtraces for <code>error</code> exceptions are now
evaluated at throw time</li>
<li><code>NamedDefaults</code> now correctly requires the class to be standard or have an
in-scope default declaration, and handles poly-kinded classes (<a href="https://gitlab.haskell.org/ghc/ghc/issues/25775">#25775</a>, <a href="https://gitlab.haskell.org/ghc/ghc/issues/25778">#25778</a>, <a href="https://gitlab.haskell.org/ghc/ghc/issues/25882">#25882</a>)</li>
<li>… and many more</li>
</ul>
<p>A full accounting of these fixes can be found in the</p>
<p><a href="https://gitlab.haskell.org/ghc/ghc/-/blob/ghc-9.12/docs/users_guide/9.12.4-notes.rst?ref_type=heads&amp;plain=1">release notes</a>. As always, GHC’s release status, including planned future
releases, can be found on the GHC Wiki <a href="https://gitlab.haskell.org/ghc/ghc/-/wikis/GHC-status">status</a>.</p>
<p>This release candidate will have a two-week testing period. If all goes well
the final release will be available the week of 26 March 2026.</p>
<p>GHC development is sponsored by:</p>
<ul>
<li><a href="https://juspay.com/">Juspay</a></li>
<li><a href="https://qbaylogic.com/">QBayLogic</a></li>
<li><a href="https://www.channable.com/">Channable</a></li>
<li><a href="https://haskell.foundation/">Haskell Foundation</a></li>
<li><a href="https://serokell.io/">Serokell</a></li>
<li><a href="https://well-typed.com/">Well-Typed</a></li>
<li><a href="https://www.tweag.io/">Tweag</a></li>
<li><a href="https://www.dotcom-monitor.com/">Dotcom-Monitor</a></li>
<li><a href="https://www.loadview-testing.com/">LoadView</a></li>
<li><a href="https://webhostingbuddy.com/">Web Hosting Buddy</a></li>
<li><a href="https://www.findmyelectric.com/">Find My Electric</a></li>
<li><a href="https://www.sc.com">Standard Chartered</a></li>
<li><a href="https://upcloud.com">UpCloud</a></li>
<li><a href="https://mercury.com">Mercury</a></li>
</ul>
<p>We would like to thank these sponsors and other anonymous contributors
whose on-going financial and in-kind support has facilitated GHC maintenance
and release management over the years. Finally, this release would not have
been possible without the hundreds of open-source contributors whose work
comprise this release.</p>
<p>As always, do give this release a try and open a <a href="https://gitlab.haskell.org/ghc/ghc/-/issues/new">ticket</a> if you see
anything amiss.</p></div>
    </summary>
    <updated>2026-03-13T00:00:00Z</updated>
    <published>2026-03-13T00:00:00Z</published>
    <author>
      <name>ghc-devs</name>
    </author>
    <source>
      <id>http://haskell.org/ghc</id>
      <link href="http://haskell.org/ghc" rel="alternate" type="text/html"/>
      <link href="http://haskell.org/ghc/rss.xml" rel="self" type="application/rss+xml"/>
      <title>GHC Developer blog</title>
      <updated>2026-03-27T00:00:00Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-8897180777295067814.post-6620848665537137843</id>
    <link href="http://bokesan.blogspot.com/feeds/6620848665537137843/comments/default" rel="replies" title="Post Comments" type="application/atom+xml"/>
    <link href="http://bokesan.blogspot.com/2026/03/functional-valhalla.html#comment-form" rel="replies" title="1 Comments" type="text/html"/>
    <link href="http://www.blogger.com/feeds/8897180777295067814/posts/default/6620848665537137843" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/8897180777295067814/posts/default/6620848665537137843" rel="self" type="application/atom+xml"/>
    <link href="http://bokesan.blogspot.com/2026/03/functional-valhalla.html" rel="alternate" title="Functional Valhalla?" type="text/html"/>
    <title>Functional Valhalla?</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p><span style="background-color: #fdfdfd; color: #1a1a1a;">Pointer-rich data layouts lead to suboptimal performance on modern hardware. For an excellent introduction to this, see the article</span><span style="background-color: #fdfdfd; color: #1a1a1a;"> </span><a href="https://openjdk.org/projects/valhalla/design-notes/state-of-valhalla/01-background" style="color: #1a1a1a;">The Road to Valhalla</a><span style="background-color: #fdfdfd; color: #1a1a1a;">. While it is specifically about Java, many parts of the article also apply to other languages. To summarize some of the key points of the article:</span></p><ul style="background-color: #fdfdfd; color: #1a1a1a; margin-top: 1em; padding-left: 1.7em;"><li>In 1990, a main memory fetch was about as expensive as an arithmetic operation. Now, it might be a hundred times slower.</li><li>A pointer-rich data layout involving indirections between data at different locations is not ideal for today’s hardware.</li><li>A language should make flat (cache-efficient) and dense (memory-efficient) memory layouts possible without compromising abstraction or type safety.</li></ul><p style="background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;">Consider a vector of records (or tuples, structures, product types - I’ll stay with “record” in this article). A pointer-rich layout has each record allocated separately in the heap, with a vector containing pointers to the records. For example, given a “Point” record of two numbers:</p><p style="background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;"><img alt="pikchr diagram" height="336" width="491"/></p><p style="background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;">The flat and dense layout has the records directly in the array:</p><p style="background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;"><img alt="pikchr diagram" height="88" width="647"/></p><p style="background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;">(Note that there is another flat layout, namely, using one vector per field of the record. This is better suited to instruction-level parallelism or specialized hardware (e.g., GPUs), especially when the record fields have different sizes. But it is less suited for general-purpose computing, as reading a single vector element requires one memory access per field, whereas the “vector of records” layout above requires only one access per record. Such a layout can be easily implemented in any language that has arrays of native types, whether in the language itself or in a library (e.g., OCaml’s Owl library). Thus, in this article, I will only consider the “array of records” layout above.)</p><h2 id="functional-language-considerations" style="background-color: #fdfdfd; color: #1a1a1a; margin-top: 1.4em;">Functional language considerations</h2><p style="background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;">Things should be much easier in functional languages than in Java: we have purity, referential transparency, and everything is a value. So it should be simple enough to store these values in memory in their native representation. But there are reasons that that is often not the case in practice:</p><ul style="background-color: #fdfdfd; color: #1a1a1a; margin-top: 1em; padding-left: 1.7em;"><li>Lazyness: a value can be a computation that produces a value only when needed.</li><li>Layout polymorphism: unless we replicate the code for every type (as, for example, Rust does), we need to be able to store every possible value in the same kind of slot.</li><li>Dynamically typed languages require type information at runtime.</li><li>Functional languages often have automatic memory management, which may require runtime type information.</li><li>Many of our languages are not purely functional, but contain impure features.</li><li>Pure languages often lack traditional vectors or arrays, since making them perform well in immutable code is not easy.</li><li>Historical reasons: Graph reduction was a common implementation technique for lazy languages, and graphs involve pointers.</li><li>Implementation restrictions: not being mainstream, fewer resources are devoted to implementation and optimization.</li></ul><p style="background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;">Many implementations can not even lay out native types flat in records, so a Point record of IEEE 754 double-precision numbers may actually look like this in memory:</p><p style="background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;"><img alt="pikchr diagram" height="232" width="330"/></p><h2 id="the-very-short-list" style="background-color: #fdfdfd; color: #1a1a1a; margin-top: 1.4em;">The (very short) List</h2><p style="background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;">So, given a record type, which functional languages allow a collection of values of that type to have a flat, linear memory layout? The number of programming languages that claim to be “functional” is huge, so the ones listed here are just a selection based on my preferences - mainly languages that allow that layout, and some I have some experience with and can speculate on how easy or hard it would be to add that as a library or extension.</p><p style="background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;">Since the Point record can be misleading in its simplicity when it comes to the question of whether the functionality could be implemented as a library, I’ll point out that there are records where the layout is a bit more interesting:</p><ul style="background-color: #fdfdfd; color: #1a1a1a; margin-top: 1em; padding-left: 1.7em;"><li>Records containing different types with different storage sizes, for example, one 64-bit float and one 32-bit integer. On most architectures, this will require 4 bytes of padding between elements.</li><li>Records containing native values along with something that has to be represented as a pointer, for example, a reference-type or a lazy value. In a flat layout, this means that every nth element will be a pointer, requiring special support from the memory management system, either by providing layout information or by using a conservative GC that treats everything as a potential pointer.</li></ul><h3 id="pure-languages" style="background-color: #fdfdfd; color: #1a1a1a; margin-top: 1.4em;">Pure languages:</h3><h4 id="clean" style="background-color: #fdfdfd; color: #1a1a1a; margin-top: 1.4em;">Clean</h4><p style="background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;">Yes: Clean has unboxed arrays of records in the base language.</p><p style="background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;">Caveat: it does not have integer types of specific sizes and only one floating-point type, making it harder to reduce memory usage by using the smallest type just large enough to support the required value range. It seems possible to implement such types in a library (the <a href="http://bokesan.blogspot.de/feeds/posts/default/-/gitlab.com/mtask/" style="color: #1a1a1a;">mTask system</a> does that).</p><h4 id="futhark" style="background-color: #fdfdfd; color: #1a1a1a; margin-top: 1.4em;">Futhark</h4><p style="background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;">No. Futhark does not intend to be a general-purpose language, so this is not surprising.</p><p style="background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;">I mention it here because it <em>does have arrays of records,</em> but, since it targets GPUs and related hardware, it uses the “record of arrays” layout mentioned above.</p><h4 id="haskell" style="background-color: #fdfdfd; color: #1a1a1a; margin-top: 1.4em;">Haskell</h4><p style="background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;">Yes. Not in the base language, but there is library support via <a href="https://hackage-content.haskell.org/package/vector-0.13.2.0/docs/Data-Vector-Unboxed.html" style="color: #1a1a1a;">Data.Vector.Unboxed</a>. Types that implement the <code>Unbox</code> type class can be used in these vectors. Many basic types and tuples have an <code>Unbox</code> instance. However, when you care about efficiency, you probably do not want to use tuples but rather a data type with strict fields, i.e., not:</p><div class="sourceCode" id="cb1" style="background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px; overflow: auto;"><pre class="sourceCode haskell" style="background-color: transparent; margin: 0px; overflow: visible;"><code class="sourceCode haskell"><span id="cb1-1" style="color: inherit; display: inline-block; line-height: 1.25; text-decoration: inherit;"><a href="http://bokesan.blogspot.de/feeds/posts/default/-/Haskell#cb1-1" style="color: #1a1a1a;" tabindex="-1"/><span class="kw" style="color: #007020; font-weight: bold;">type</span> <span class="dt" style="color: #902000;">Point</span> <span class="ot" style="color: #007020;">=</span> (<span class="dt" style="color: #902000;">Double</span>, <span class="dt" style="color: #902000;">Double</span>)</span></code></pre></div><p style="background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;">but:</p><div class="sourceCode" id="cb2" style="background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px; overflow: auto;"><pre class="sourceCode haskell" style="background-color: transparent; margin: 0px; overflow: visible;"><code class="sourceCode haskell"><span id="cb2-1" style="color: inherit; display: inline-block; line-height: 1.25; text-decoration: inherit;"><a href="http://bokesan.blogspot.de/feeds/posts/default/-/Haskell#cb2-1" style="color: #1a1a1a;" tabindex="-1"/><span class="kw" style="color: #007020; font-weight: bold;">data</span> <span class="dt" style="color: #902000;">Point</span> <span class="ot" style="color: #007020;">=</span> <span class="dt" style="color: #902000;">Point</span> <span class="op" style="color: #666666;">!</span><span class="dt" style="color: #902000;">Double</span> <span class="op" style="color: #666666;">!</span><span class="dt" style="color: #902000;">Double</span></span></code></pre></div><p style="background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;">Writing an <code>Unbox</code> instance for such a type is not trivial. The <a href="https://hackage.haskell.org/package/vector-th-unbox-0.2.2/docs/Data-Vector-Unboxed-Deriving.html" style="color: #1a1a1a;">vector-th-unbox library</a> makes it easier, but requires Template Haskell. Unboxed vectors are implemented by marshalling the values to byte arrays, so records with pointer fields are not supported.</p><h3 id="impure-languages" style="background-color: #fdfdfd; color: #1a1a1a; margin-top: 1.4em;">Impure Languages</h3><h4 id="f" style="background-color: #fdfdfd; color: #1a1a1a; margin-top: 1.4em;">F#</h4><p style="background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;">Yes, even records with pointer fields. Records have structural equality, and you can use structs or the <code>[&lt;Struct&gt;]</code> attribute to get a flat layout.</p><hr style="background-color: #fdfdfd; border-bottom: none; border-left: none; border-right: none; border-top-color: rgb(26, 26, 26); border-top-style: solid; height: 1px; margin: 1em 0px;"/><p style="background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;">And that’s all I could find. Unless I follow <a href="https://en.wikipedia.org/wiki/List_of_programming_languages_by_type#Functional_languages" style="color: #1a1a1a;">Wikipedia's list of functional programming languages</a>, which contains languages such as C++, C#, Rust, or Swift, that allow the flat layout, but don’t really fit my idea of a functional language. But SML, OCaml, Erlang (Elixir, Gleam), Scala? Not that I could see (but please correct me if I’m wrong).</p><h3 id="rolling-your-own" style="background-color: #fdfdfd; color: #1a1a1a; margin-top: 1.4em;">Rolling your own</h3><p style="background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;">Since there is a library implementation for Haskell, maybe that’s a possibility for other languages?</p><p style="background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;">You should be able to implement flat layouts in any language that supports byte vectors. More interesting is how well such a library fits into the language, and whether a user of the library has to write code or annotations for user-defined record types, or whether the library can handle part or all of that automagically.</p><p style="background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;">I’ll only mention my beloved Lisp/Scheme here. Lisp’s uniform syntax and macro system are a bonus here, but the lack of static typing makes things harder.</p><p style="background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;">In Scheme, R6RS (and R7RS with the help of some SRFIs) has byte-vectors and marshalling to/from them in the standard library. But Scheme does not have type annotations, so you either need to offer a macro to define records with typed fields or to define how to marshal the fields of a regular (sealed) record. Since you can shadow standard procedures in a library, you can write code that looks like regular Scheme code, but, perhaps surprisingly, loses identity when storing/retrieving values from records:</p><div class="sourceCode" id="cb3" style="background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px; overflow: auto;"><pre class="sourceCode scheme" style="background-color: transparent; margin: 0px; overflow: visible;"><code class="sourceCode scheme"><span id="cb3-1" style="color: inherit; display: inline-block; line-height: 1.25; text-decoration: inherit;"><a href="http://bokesan.blogspot.de/feeds/posts/default/-/Haskell#cb3-1" style="color: #1a1a1a;" tabindex="-1"/>(<span class="kw" style="color: #007020; font-weight: bold;">let</span> ((vec (make-typed-vector 'point <span class="dv" style="color: #40a070;">1000</span>))</span>
<span id="cb3-2" style="color: inherit; display: inline-block; line-height: 1.25; text-decoration: inherit;"><a href="http://bokesan.blogspot.de/feeds/posts/default/-/Haskell#cb3-2" style="color: #1a1a1a;" tabindex="-1"/>      (pt (make-point x y)))</span>
<span id="cb3-3" style="color: inherit; display: inline-block; line-height: 1.25; text-decoration: inherit;"><a href="http://bokesan.blogspot.de/feeds/posts/default/-/Haskell#cb3-3" style="color: #1a1a1a;" tabindex="-1"/>  (<span class="kw" style="color: #007020; font-weight: bold;">vector-set!</span> vec <span class="dv" style="color: #40a070;">0</span> pt)</span>
<span id="cb3-4" style="color: inherit; display: inline-block; line-height: 1.25; text-decoration: inherit;"><a href="http://bokesan.blogspot.de/feeds/posts/default/-/Haskell#cb3-4" style="color: #1a1a1a;" tabindex="-1"/>  (<span class="kw" style="color: #007020; font-weight: bold;">eq?</span> (<span class="kw" style="color: #007020; font-weight: bold;">vector-ref</span> vec <span class="dv" style="color: #40a070;">0</span>) pt))</span>
<span id="cb3-5" style="color: inherit; display: inline-block; line-height: 1.25; text-decoration: inherit;"><a href="http://bokesan.blogspot.de/feeds/posts/default/-/Haskell#cb3-5" style="color: #1a1a1a;" tabindex="-1"/> ⇒ <span class="dv" style="color: #40a070;">#f</span></span></code></pre></div><p style="background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;">(But then, you probably shouldn’t be using <code>eq?</code> when doing functional programming in Scheme).</p><p style="background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;">The same approach is possible in Common Lisp. In contrast to Scheme, it does have optional type annotations, and, together with a helper library for accessing the innards of floats and either the meta-object protocol to get type information or (probably better) a macro to define typed records, an implementation should be reasonably straightforward. Making it play nice with inheritance and the dynamic nature of Common Lisp (e.g., adding slots to classes or even changing an object's class at runtime) would be a much harder undertaking.</p><h2 id="conclusion" style="background-color: #fdfdfd; color: #1a1a1a; margin-top: 1.4em;">Conclusion</h2><p style="background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;">Of the functional languages I looked at, only F# fully supports flat and dense memory layouts. Among the pure languages, Haskell and Clean come close.</p><p style="background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;">The question is how important this really is. There’s a good argument to be made for turning to more specialized languages like Futhark if you mainly care about performance. On the other hand, having a uniform codebase in one language also has advantages.</p><p style="background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;">Then, the performance story has changed, too. While the points Project Valhalla raises remain true in principle, processor designers are aware of this as well. They are doing their best to hide memory latency with techniques such as out-of-order execution or humongous caches. Thus, on a modern CPU, the effects of a pointer-rich layout are often only observable with large working set sizes.</p><p style="background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;">Still, given the plethora of imperative language that can get you to Valhalla, support for this in the functional landscape seems lacking. In the future, I hope to see more languages or libraries that will make this possible.</p></div>
    </content>
    <updated>2026-03-12T11:17:02Z</updated>
    <published>2026-03-12T11:17:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="Haskell"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="Lisp"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="Performance"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="programming"/>
    <author>
      <name>bokesan</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/09457977231270485255</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-8897180777295067814</id>
      <category term="programming"/>
      <category term="Photography"/>
      <category term="Haskell"/>
      <category term="Nikon"/>
      <category term="Scala"/>
      <category term="Benchmark"/>
      <category term="Hasselblad"/>
      <category term="Nikkor"/>
      <category term="Performance"/>
      <category term="Sony"/>
      <category term="ICFPC"/>
      <category term="Java"/>
      <category term="Lenses"/>
      <category term="Lisp"/>
      <category term="Sony Alpha"/>
      <category term="Focus shift"/>
      <category term="Lens test"/>
      <category term="LoCA"/>
      <category term="Adapter"/>
      <category term="Android"/>
      <category term="CMOS"/>
      <category term="Catalyst"/>
      <category term="Closures"/>
      <category term="CoffeeScript"/>
      <category term="D600"/>
      <category term="Extension"/>
      <category term="Hannover"/>
      <category term="JavaScript"/>
      <category term="Kaveri"/>
      <category term="Leaf Shutter"/>
      <category term="Lens"/>
      <category term="Linux"/>
      <category term="Loongson"/>
      <category term="MTF"/>
      <category term="Macro"/>
      <category term="MapExplorer"/>
      <category term="Megapixels"/>
      <category term="Mirrorless"/>
      <category term="Olympus"/>
      <category term="Oracle"/>
      <category term="PSF"/>
      <category term="Samsung"/>
      <category term="Sensor"/>
      <category term="Steamroller"/>
      <category term="Tripod"/>
      <category term="Tubes"/>
      <category term="Windows"/>
      <category term="bokeh"/>
      <category term="bugs"/>
      <category term="chromatic aberration"/>
      <category term="cooling"/>
      <category term="field curvature"/>
      <category term="mainboard"/>
      <category term="mini-itx"/>
      <category term="multithreaded"/>
      <category term="testing"/>
      <author>
        <name>bokesan</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/09457977231270485255</uri>
      </author>
      <link href="http://bokesan.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/8897180777295067814/posts/default/-/Haskell" rel="self" type="application/atom+xml"/>
      <link href="http://bokesan.blogspot.com/search/label/Haskell" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <subtitle>Thoughts about programming, photography, and sometimes life</subtitle>
      <title>about:random</title>
      <updated>2026-04-16T11:33:45Z</updated>
    </source>
  </entry>

  <entry>
    <id>https://www.parsonsmatt.org/2026/03/10/teaching_claude_to_be_lazy.html</id>
    <link href="https://www.parsonsmatt.org/2026/03/10/teaching_claude_to_be_lazy.html" rel="alternate" type="text/html"/>
    <title>Teaching Claude to Be Lazy</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>I’ve been watching AI development for a long time.
I found LessWrong around 2012-2013, and managed to get myself worked up about the oncoming singularity.
I managed to chill out about it, but interest and excitement for AI remained.
The initial Deep Dream image generation, Alpha Go, etc, were all so exciting.
And then GPT-2 came out.</p>

<p>Over the last five years, people have been making wild claims about the utility of <em>present</em> AI.
Not “the AI that you’ll have <em>soon</em>,” but the current generation stuff.
And the results, frankly, had been garbage.
A sea of garbage coating the internet.
I’d try using the tools, and when checking them against my own expertise or knowledge, they always fell short.</p>

<p>I heard the noise on Twitter after Opus 4.5 was released in November of 2025.
Seemed like a step change- people were much more impressed with it than prior versions.
In December, I decided to give it a try.
Opus 4.5, with significant guidance, properly diagnosed and fixed some Template Haskell code generation issues.
It knew how to <code class="language-plaintext highlighter-rouge">-ddump-splices</code>, it knew how to read those splices and diagnose the issue.
Given a small, highly mechanical problem, plenty of examples, and a ton of tests, it took about 6 hours to do what I felt would have taken me 3 or 4 hours.</p>

<p>This is pretty incredible, because my productivity has always been limited by two things:</p>

<ol>
  <li>Effort. Literally whacking my keyboard and staring at computer and waiting on a compile/test loop to tell me what to do next.</li>
  <li>Attention. Where I’m focusing my effort. My editor? Slack? Meetings? A bike ride? Cello? Which OSS project?</li>
</ol>

<p>Now, with Opus 4.5, I can set a robot going and do <em>something else</em> with my effort.
While Claude Code was spinning on the Template Haskell code, I was doing another project in a different repository.
Sure, Claude took 6 hours instead of my 3, but I was able to fill those 6 hours with <em>effort</em> and attention placed elsewhere - not a full 6, as Claude required supervision and input, but call it 5.
This is a positive investment, and my personal “break even” moment.</p>

<h1 id="using-claude-code-effectively">Using Claude Code Effectively</h1>

<p>In mid February, I got access to an API token and unlimited usage.
I’ve been trying to figure out how to leverage this tool to improve my productivity, and the results have been pretty strongly positive.</p>

<p>The brief tl;dr:</p>

<blockquote>
  <p>It’s the same shit that makes humans good at software development</p>
</blockquote>

<h2 id="haskell-is-awesome-for-llms">Haskell is Awesome for LLMs</h2>

<p>This was true with Opus 4.5 and is much more true with Opus 4.6.
Prior versions of LLM coding agents produced utter garbage with Haskell, most likely due to the relatively low quantity of examples.
It <em>seems</em> like the AI labs have figured out how to do higher quality training with less data, and the relatively high average quality of Haskell code helps the LLMs generate relatively high quality Haskell.</p>

<p>Haskell’s type safety, purity, and library design opportunities make it a fantastic choice for LLM generated code.
The human developer can easily specify a solution and let Claude fill in a <em>surprising</em> amount of the boring details.</p>

<p>Haskell’s terse nature benefits LLMs - you can simply fit more tokens into the context window when the tokens are more semantically dense.</p>

<p>Funny enough, all of Haskell’s benefits “for LLMs” are also benefits of Haskell for humans.
I do earnestly believe that if all devs knew Haskell, we would consider switching to other languages only very rarely.
And Claude <em>knows Haskell</em>.</p>

<h2 id="software-engineering-matters">Software Engineering Matters</h2>

<p>Claude Code works <em>really well</em> with tightly scoped issues, lots of tests and examples, and good safety guardrails.
I asked it to make <code class="language-plaintext highlighter-rouge">cabal</code> faster, and taught it how to run <code class="language-plaintext highlighter-rouge">cabal</code> with debug logs, timings, and then to build a profiled version of it.
Then it looped for a bit, collected timing information on our codebase, and figured out the critical path and hot spot - the solver.
Then it <a href="https://github.com/haskell/cabal/pull/11566">made several fixes to optimize the solver</a>.
These changes resulted in a 30% improvement in solver times, which shaved 2 seconds off every <code class="language-plaintext highlighter-rouge">cabal repl</code> invocation- a pretty nice benefit, since that happens virtually anytime you want to do anything in our codebase.</p>

<p>But this only worked because the <code class="language-plaintext highlighter-rouge">cabal</code> library had timing logs, and I gave it a quick feedback loop and target.
I’ve had Claude Code totally fall over when trying to do bigger or more undirected work.</p>

<p>Fortunately, Claude can do this pretty well.
I’ve had Claude do some exploratory research (generally pretty highly supervised), then generate some plans for improvement (then edited and clarified), and it can then do a good job of writing up a ticket- certainly better than almost all human written tickets I’ve seen.</p>

<h2 id="build-workflows-iteratively">Build Workflows Iteratively</h2>

<p>LLMs can do anything.
But they are expensive, slow, and non-deterministic (and often incorrect).
So get the LLM to help with <em>replacing themselves</em> - build a tool or skill to do the thing faster and deterministically.</p>

<p>My Claude sessions generally progress from “highly supervised, exploratory work” to “mostly unsupervised, automated work.”
Early sessions in a project often involve having Claude build tools - CLI scripts, libraries, interfaces - that it can use in later work to make the job easier.
A surprisingly effective prompt here is “What tools would help you do this job better next time?”
At the end of a session, I’ll also have Claude review and update its skill documentation with everything I told it to do differently.</p>

<p>So each work session with Claude produces:</p>

<ol>
  <li>An artifact (the work itself)</li>
  <li>Often, updates to the skill to improve efficiency on further work</li>
  <li>Sometimes, a tool to deterministically do some chunk of the work.</li>
</ol>

<p>This process ends up reducing the highly non-deterministic LLM tool with a much more deterministic tool.</p>

<h2 id="mock-reviews-and-refactoring">Mock Reviews and Refactoring</h2>

<p>You can ask Claude to review code, and that works OK.
But Claude works <em>much better</em> if you ask it to assume someone else’s perspective.
I’ve asked it to mimic myself and it did Alright.
I asked it to mimic Edward Kmett, Alexis King, and Michael Snoyman, and it did Alright - it noticed different things with each perspective and suggested improvements in line with those perspectives.</p>

<p>I’ve generally found that the initial output is of poor to middling quality.
But you can get decently far with “now make it more legible/faster/more correct” or “apply ‘Parse, Don’t Validate’ here” etc.
After several rounds of refactoring, it makes stuff that I’m reasonably happy with putting my name on.</p>

<h1 id="what-doesnt-work-well">What Doesn’t Work Well</h1>

<p>Claude isn’t a replacement for human engineering (“yet” i guess).
It lacks qualities like taste, judgement, and vision, that are generally required in subjective work like software and product design.
So when I let Claude run totally loose on something, it <em>produces</em>, but it produces poor quality code and poorly thought out features.</p>

<p>I haven’t had great luck with getting Claude to iterate on this itself.
When given the very large picture, it sort of flounders.
It can do some analysis and subdivision, but the divisions are often somewhat unnatural and don’t feel right to me.</p>

<h2 id="defined-by-our-vice">Defined by our Vice</h2>

<p>If the above complaint is about Claude’s lack of virtue, let me also complain about Claude’s lack of vice.
Claude is infinitely patient and willing to work very hard.
However, “infinitely patient” means that Claude has no problem at all waiting an hour for a build to finish.
You have to teach it to use faster tools and feedback loops.</p>

<p>Likewise, “hardworking” is a virtue when you’re paying a human by the month and trusting in their laziness to be efficient, but when you’re paying per unit of thought, “more work” means “more cost” and often not “more output.”
You have to tell Claude to <em>stop doing stuff</em> or to do stuff more efficiently.</p>

<p>Fortunately, Claude is relatively teachable - but Claude very often will start a skill and then do a lot of “research and understanding” before running the one-shot script to generate the compile-errors to track down and fix.</p>

<p>Humans are impatient and lazy, so we build fast and efficient systems.
Without pain to guide us, we make little progress in <em>reducing</em> that pain.</p>

<h1 id="am-i-still-a-skeptic">Am I still a skeptic?</h1>

<p>I’ve been using AI to write 95% of my code for the last month.
And yet, I still feel like I’m more on the skeptic side of things.
AI is clearly a <em>useful</em> tool - my own productivity has doubled or more while maintaining my personal quality bar.
But it’s not a do-it-all miracle - yet?</p>

<p>AI-first companies are experiencing massive reliability issues.
Vibe coding projects start, enjoy some success, and then go down in flames.</p>

<p>Humans are clearly still necessary at key points in the software lifecycle.
The bottlenecks have shifted, though, and the easiest parts of my job have been mostly automated.
What’s coming next?</p>

<p>I’m excited to wait and find out.</p></div>
    </summary>
    <updated>2026-03-10T00:00:00Z</updated>
    <published>2026-03-10T00:00:00Z</published>
    <source>
      <id>https://www.parsonsmatt.org</id>
      <author>
        <name>Matt Parsons</name>
      </author>
      <link href="https://www.parsonsmatt.org" rel="alternate" type="text/html"/>
      <link href="https://www.parsonsmatt.org/feed.xml" rel="self" type="application/rss+xml"/>
      <title>parsonsmatt.org</title>
      <updated>2026-03-10T19:05:50Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:,2026:/tech/gpt/documentation-wins-2</id>
    <link href="https://blog.plover.com/tech/gpt/documentation-wins-2.html" rel="alternate" type="text/html"/>
    <title>Programmers will document for Claude, but not for each other</title>
    <content type="xhtml" xml:lang="en"><div xmlns="http://www.w3.org/1999/xhtml"><p><a href="https://blog.plover.com/tech/gpt/documentation-wins.html">A couple of days ago I recounted a common complaint</a>:</p>

<blockquote>
  <p>I keep seeing programmers say how angry it makes them that people
  are willing to write detailed <code>CLAUDE.md</code> and <code>PROJECT.md</code> files for
  Claude to use, but they weren't willing to write them for their
  coworkers.</p>
</blockquote>

<p>For larger projects, I've taken to having Claude maintain a handoff
document that I can have the next Claude read, saying what we planned
to do, what has been done, and other pertinent information.  Then when
I shut down one Claude I can have the next one read the file to get up
to speed.  Then I have the Claude <img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%24n%2b1%24"/> update it for Claude
<img src="https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;cht=tx&amp;chl=%24n%2b2%24"/>.</p>

<p>After seeing the common complaint enough times I had a happy
inspiration.  I'd been throwing away Claude's handoff documents at the
end of each project.  Why do that?  It's no trouble to copy the file
into the repository and commit it.  Someone in the future, wondering
what was going on, might luckily find the right document with <code>git
grep</code> and learn something useful.</p>

<p>I'm a little slow so it took me until this week to think of a better
version of this: at the end of the project I now ask Claude to write
up from scratch a detailed but high-level explanation of what problem
we were solving and what changes we made, and I commit <em>that</em>.  Not
just running notes, but a structured overview of the whole thing.</p>

<p>I review these overviews carefully and make edits as necessary before
I check them in. It's my signature on the commit, and my bank account
receiving the paycheck, so nothing goes into the repository that I
haven't read carefully and understood, same as if Claude were a human
programmer under my supervision.</p>

<p>But Claude's explanations haven't required much editing.  Claude's
most recent project summary was around as good as what I could have
written myself, maybe a little worse and maybe a little better.  But
it took ten seconds to write instead of an hour, and it didn't take
anything like an hour to review.</p>

<p>The serious thing I had to fix the last time around was that Claude
had used a previous, related report as a model, and the previous
report had had a paragraph I had added at the end that said:</p>

<blockquote>
  <p># Approved-by</p>
  
  <p>Claude abstracted these notes from our discussions of the issue. Mark
  Dominus has read, reviewed, edited, and approved these notes.</p>
</blockquote>

<p>Claude's new document had an identical section at the end.  Oops!
Fortunately, by the time I saw it, it was true, so I didn't have to
delete it.  I had Claude add a sentence to <code>CLAUDE.md</code> to tell it not
to do this again.</p>

<p>My advice for the day:</p>

<ol>
<li><p>If you have Claude write down notes, check them into the repo when
you're done.  It probably can't hurt and it might help.</p></li>
<li><p>Have Claude write a project summary, and then check it into the repo.</p></li>
</ol>

<p>Maybe this is obvious?  But it wasn't obvious to me.  I'm still
getting used to this new world.</p></div>
    </content>
    <updated>2026-03-09T08:04:00Z</updated>
    <published>2026-03-09T07:40:00Z</published>
    <category term="/tech/gpt"/>
    <author>
      <name>Mark Dominus</name>
      <email>mjd@plover.com</email>
      <uri>http://www.plover.com/</uri>
    </author>
    <source>
      <id>tag:,2005:/</id>
      <icon>http://perl.plover.com/favicon.ico</icon>
      <link href="https://blog.plover.com/index.atom" rel="self" type="application/atom+xml"/>
      <link href="https://blog.plover.com" rel="alternate" type="text/html"/>
      <subtitle>The Universe of Discourse (Mark Dominus Blog)</subtitle>
      <title>The Universe of Discourse</title>
    </source>
  </entry>

  <entry xml:lang="en-us">
    <id>Buzzsprout-18809011</id>
    <link href="https://www.buzzsprout.com/1817535/episodes/18809011-78-jamie-willis.mp3" length="31284259" rel="enclosure" type="audio/mpeg"/>
    <title>78: Jamie Willis</title>
    <summary>In this episode, we focus on a particular part of Haskell: teaching it. To help us, we are joined by Jamie Willis who is a Teaching Fellow at Imperial College London. The episode explores the benefits of live coding, and why Haskell is the best language for teaching programming.</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p><b>In this episode, we focus on a particular part of Haskell: teaching it. To help us, we are joined by Jamie Willis who is a Teaching Fellow at Imperial College London. The episode explores the benefits of live coding, and why Haskell is the best language for teaching programming.</b></p><p><br/></p></div>
    </content>
    <updated>2026-03-08T11:00:00Z</updated>
    <published>2026-03-08T11:00:00Z</published>
    <author>
      <name>Haskell Podcast</name>
    </author>
    <source>
      <id>https://haskell.foundation/podcast/</id>
      <logo>https://storage.buzzsprout.com/tnk1ztokn5vmeiufqmr4kkp37mw2?.jpg</logo>
      <category scheme="http://www.itunes.com/" term="Technology"/>
      <author>
        <name>Haskell Podcast</name>
      </author>
      <link href="https://rss.buzzsprout.com/1817535.rss" rel="self" type="application/rss+xml"/>
      <link href="https://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="https://haskell.foundation/podcast/" rel="alternate" type="text/html"/>
      <rights>Â© 2026 The Haskell Interlude</rights>
      <subtitle>This is the Haskell Interlude, where the five co-hosts (Wouter Swierstra, Andres LÃ¶h, Alejandro Serrano, Niki Vazou, and Joachim Breitner) chat with Haskell guests!</subtitle>
      <title>The Haskell Interlude</title>
      <updated>2026-05-19T12:36:05Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:,2026:/movie/john_waters</id>
    <link href="https://blog.plover.com/movie/john_waters.html" rel="alternate" type="text/html"/>
    <title>How are John Waters movies like James Bond movies?</title>
    <content type="xhtml" xml:lang="en"><div xmlns="http://www.w3.org/1999/xhtml"><p>A number of years ago I wondered how many movies I had seen. The only
way I could think of finding out was just to make a list.  This I did
as best I could.  (It turned out to be around 700.)</p>

<p>I found, though, that I could not include all the James Bond movies I
had seen, because I couldn't tell them apart from the descriptions.
I'd read a plot summary for a James Bond movie, and ask myself “Did I
see that?  I don't know, it sounds like every other James Bond movie.”</p>

<p>Today I discovered that John Waters movies are like that also.  I was
trying to remember if I had seen <em>A Dirty Shame</em>:</p>

<blockquote>
  <p>The people of Harford Road are firmly divided into two camps: the
  neuters, the puritanical residents who despise anything even
  remotely carnal; and the perverts, a group of sex addicts whose
  unique fetishes have all been brought to the fore by accidental
  concussions. Repressed Sylvia Stickles finds herself firmly
  entrenched in the former camp.</p>
</blockquote>

<p>You'd think that would be something I would remember decisively, or
not.  But I'm really not sure. All I can do is shrug and say “I don't
know, it sounds like a John Waters movie I have seen, but maybe it
wasn't that one.”</p>

<p>Looking into it further I discovered that I also wasn't sure if I had
seen <em>Multiple Maniacs</em>.  In it, Divine's character is raped by a
giant lobster.  On the one hand, that seems like the sort of thing I
would remember.  And I think maybe I do?  But again I'm not sure I'm
not just imagining what it would be like!</p></div>
    </content>
    <updated>2026-03-08T09:50:00Z</updated>
    <published>2026-03-08T09:50:00Z</published>
    <category term="/movie"/>
    <author>
      <name>Mark Dominus</name>
      <email>mjd@plover.com</email>
      <uri>http://www.plover.com/</uri>
    </author>
    <source>
      <id>tag:,2005:/</id>
      <icon>http://perl.plover.com/favicon.ico</icon>
      <link href="https://blog.plover.com/index.atom" rel="self" type="application/atom+xml"/>
      <link href="https://blog.plover.com" rel="alternate" type="text/html"/>
      <subtitle>The Universe of Discourse (Mark Dominus Blog)</subtitle>
      <title>The Universe of Discourse</title>
    </source>
  </entry>

  <entry>
    <id>tag:,2026:/tech/gpt/documentation-wins</id>
    <link href="https://blog.plover.com/tech/gpt/documentation-wins.html" rel="alternate" type="text/html"/>
    <title>Documentation is a message in a bottle</title>
    <content type="xhtml" xml:lang="en"><div xmlns="http://www.w3.org/1999/xhtml"><p>Our company is
going to a convention later this month, and they will have a booth with
big TV screens showing statistics that update in real time.  My job is
to write the backend server that delivers the statistics.</p>

<p>I read over the documents that the product people had written up about
what was wanted, asked questions, got answers, and then turned the
original two-line ticket into a three-page ticket that said what
should be done and how.  I intended to do the ticket myself, but it's
good practice to write all this stuff down, for many reasons:</p>

<ul>
<li><p>Writing things down forces me to think them through carefully and
realize what doesn't make sense or what I still don't understand.</p></li>
<li><p>I forget things easily and this will keep the plan where I can find it.</p></li>
<li><p>I might get sick, and if someone else has to pick up the project
this might help them understand what I was doing.</p></li>
<li><p>If my boss gets worried that all I do is post on 4chan all day, this
is tangible work product that proves I did something else that might
have enhanced shareholder value.</p></li>
<li><p>If I'm tempted to spend the day posting on 4chan, and then to later
<em>claim</em> I spent the time planning the project, I might fool my boss.
But without that tangible work product, I won't be able to fool
<em>myself</em>, and that's more important.</p></li>
<li><p>Conversely if I later think back and ask “What was I doing the week
of March 2?” I might be tempted to imagine that all I did was post
on 4chan.  But the three pages of ticket description will prove to
me that I am not just a lazy slacker.  <a href="https://blog.plover.com/misc/evaluation.html">This is a real problem for
me</a>.</p></li>
<li><p>In principle, a future person going back to extend the work might
find this helpful documentation of what was done and why.  Does this
ever really happen?  I don't know, but it might.</p></li>
<li><p>I like writing because writing is fun.</p></li>
</ul>

<p>A few days after I wrote the ticket, something unexpected happened.
It transpired that person who was to build the front-end consumer of
my statistics would not be a professional programmer.  It would be the
company's Head of Product, a very smart woman named Amanda. The actual
code would be written by Claude, under her supervision.</p>

<p>I have never done anything like this before, and I would not have
wanted to try it on a short deadline, but there is some slack in the
schedule and it seemed a worthwhile and exciting experiment.</p>

<p>Amanda shared some screencaps of her chats with Claude about the
project, and I suggested:</p>

<blockquote>
  <p>When you get a chance, please ask Claude to write out a Markdown
  file memorializing all this.  Tell it that you're going to give it
  to the backend programmer for discussion, so more detail is better.
  When it's ready, send it over.</p>
</blockquote>

<p>Claude immediately produced a nine-page, 14-part memo and a half-page
overview.  I spent a couple of hours reviewing it and marking it up.</p>

<p>It became immediately clear that Claude and I had very similar ideas
about how the project should go and how the front and back ends would
hook up.  So similar that I asked Angela:</p>

<blockquote>
  <p>It looks like maybe you started it off by feeding it my ticket
  description.  Is that right? </p>
</blockquote>

<p>She said yes, she had.  She had also fed it the original product
documents I had read.</p>

<p>I was delighted.  I had had many reasons for writing detailed ticket
descriptions before, but the most plausible ones were aimed back at
myself.</p>

<p>The external consumers of the documentation all seemed somewhat
unlikely.  The person who would extend the project in the future
probably didn't exist, and if they did they probably wouldn't have
thought to look at my notes.  Same for the hypothetical person who
would take over when I got sick.  My boss probably isn't checking up
on me by looking at my ticketing history.  Still, I like to document
these things for my own benefit, and also just in case.</p>

<p>But now, because I had written the project plan, it was available for
consumption when an unexpected consumer turned up!  Claude and I were
able to rapidly converge on the design of the system, because Amanda
had found my notes and cleverly handed them to Claude.  Suddenly one
of those unlikely-seeming external reasons materialized!</p>

<p>On Mastodon I keep seeing programmers say how angry it makes
them that people are willing to write detailed <code>CLAUDE.md</code> and
<code>PROJECT.md</code> files for Claude to use, but they weren't willing to
write them for their coworkers.  (They complain about this as if this
is somehow the fault of the AI, rather than of the people who failed
in the past to write documentation for their coworkers.)</p>

<p>The obvious answer to the question of why people are willing to write
documentation for Claude but not for their coworkers is that the
author can count on Claude to <em>read</em> the documentation, whereas it's a
rare coworker who will look at it attentively.</p>

<p>Rik Signes points out there's a less obvious but more likely answer:
your coworkers will remember things if you just tell them, but Claude
forgets everything every time.  If you want Claude to remember
something, you have to write it down.  So people using Claude do write
things down, because otherwise they have to say them over and over.</p>

<p>And there's a happy converse to the complaint that most programmers
don't bother to write documentation.  It means that people like me,
professionals who <em>have</em> always written meticulous documentation, are
now reaping new benefits from that always valuable practice.</p>

<p>Not everything is going to get worse.  Some things will get better.</p>

<h3>Addendum 20260208</h3>

<p><a href="https://blog.plover.com/tech/gpt/documentation-wins-2.html">A corollary</a>: You don't
have to write the rocumentation yourself.  You can have Claude write a
detailed summary based on your ongoing chats about the work, and then
you can edit it and check it in.</p>

<p>If you're good at editing, anyway.  I wonder if part of the reason
Claude is working so well for me is that I'm really good at editing
and at code review?</p></div>
    </content>
    <updated>2026-03-05T16:07:00Z</updated>
    <published>2026-03-05T16:07:00Z</published>
    <category term="/tech/gpt"/>
    <author>
      <name>Mark Dominus</name>
      <email>mjd@plover.com</email>
      <uri>http://www.plover.com/</uri>
    </author>
    <source>
      <id>tag:,2005:/</id>
      <icon>http://perl.plover.com/favicon.ico</icon>
      <link href="https://blog.plover.com/index.atom" rel="self" type="application/atom+xml"/>
      <link href="https://blog.plover.com" rel="alternate" type="text/html"/>
      <subtitle>The Universe of Discourse (Mark Dominus Blog)</subtitle>
      <title>The Universe of Discourse</title>
    </source>
  </entry>

  <entry>
    <id>https://doisinkidney.com/posts/2026-03-03-monus-heaps.html</id>
    <link href="https://doisinkidney.com/posts/2026-03-03-monus-heaps.html" rel="alternate" type="text/html"/>
    <title>Monuses and Heaps</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><div class="info">
    Posted on March  3, 2026
</div>
<div class="info">
    
</div>
<div class="info">
    
        Tags: <a href="https://doisinkidney.com/tags/Haskell.html" rel="tag" title="All pages tagged 'Haskell'.">Haskell</a>
    
</div>

<p>This post is about a simple algebraic structure that I have found
useful for algorithms that involve searching or sorting based on some
ordered weight. I used it a bit in a pair of papers on graph search
<span class="citation">(<a href="https://doisinkidney.com/rss.xml#ref-kidney_algebras_2021">2021</a>; <a href="https://doisinkidney.com/rss.xml#ref-kidney_formalising_2025">2025</a>)</span>, and more recently I used it to
implement a version of the <code class="sourceCode haskell"><span class="dt">Phases</span></code> type
<span class="citation">(<a href="https://doisinkidney.com/rss.xml#ref-easterly_functions_2019">Easterly
2019</a>)</span> that supported arbitrary keys, inspired by some work by
BlÃ¶ndal <span class="citation">(<a href="https://doisinkidney.com/rss.xml#ref-blondal_generalized_2025">2025a</a>; <a href="https://doisinkidney.com/rss.xml#ref-blondal_phases_2025">2025b</a>)</span>
and <span class="citation">Visscher
(<a href="https://doisinkidney.com/rss.xml#ref-visscher_phases_2025">2025</a>)</span>.</p>
<p>The algebraic structure in question is a <em>monus</em>, which is a
kind of monoid that supports a partial subtraction operation (that
subtraction operation, denoted by the symbol âˆ¸, is itself often called a
â€œmonusâ€�). However, before giving the full definition of the structure,
let me first try to motivate its use. The context here is heap-based
algorithms. For the purposes of this post, a heap is a tree that obeys
the â€œheap propertyâ€�; i.e.Â every node in the tree has some â€œweightâ€�
attached to it, and every parent node has a weight less than or equal to
the weight of each of its children. So, for a tree like the
following:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="https://doisinkidney.com/rss.xml#cb1-1" tabindex="-1"/>   â”Œd</span>
<span id="cb1-2"><a href="https://doisinkidney.com/rss.xml#cb1-2" tabindex="-1"/> â”Œbâ”¤</span>
<span id="cb1-3"><a href="https://doisinkidney.com/rss.xml#cb1-3" tabindex="-1"/>aâ”¤ â””e</span>
<span id="cb1-4"><a href="https://doisinkidney.com/rss.xml#cb1-4" tabindex="-1"/> â””c</span></code></pre></div>
<p>The heap property is satisfied when
<math display="inline">&lt;semantics&gt;<mrow><mi>a</mi><mo>â‰¤</mo><mi>b</mi></mrow>&lt;annotation encoding="application/x-tex"&gt;a \leq b&lt;/annotation&gt;&lt;/semantics&gt;</math>,
<math display="inline">&lt;semantics&gt;<mrow><mi>a</mi><mo>â‰¤</mo><mi>c</mi></mrow>&lt;annotation encoding="application/x-tex"&gt;a \leq c&lt;/annotation&gt;&lt;/semantics&gt;</math>,
<math display="inline">&lt;semantics&gt;<mrow><mi>b</mi><mo>â‰¤</mo><mi>d</mi></mrow>&lt;annotation encoding="application/x-tex"&gt;b \leq d&lt;/annotation&gt;&lt;/semantics&gt;</math>,
and
<math display="inline">&lt;semantics&gt;<mrow><mi>b</mi><mo>â‰¤</mo><mi>e</mi></mrow>&lt;annotation encoding="application/x-tex"&gt;b \leq e&lt;/annotation&gt;&lt;/semantics&gt;</math>.</p>
<p>Usually, we also want our heap structure to have an operation like
<code class="sourceCode haskell"><span class="ot">popMin ::</span> <span class="dt">Heap</span> k v <span class="ot">-&gt;</span> <span class="dt">Maybe</span> (v, <span class="dt">Heap</span> k v)</code>
that returns the least-weight value in the heap paired with the rest of
the heap. If this operation is efficient, we can use the heap to
efficiently implement sorting algorithms, graph search, etc. In fact,
let me give the whole basic interface for a heap here:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb2-1"><a href="https://doisinkidney.com/rss.xml#cb2-1" tabindex="-1"/><span class="ot">popMin ::</span> <span class="dt">Heap</span> k v <span class="ot">-&gt;</span> <span class="dt">Maybe</span> (v, <span class="dt">Heap</span> k v)</span>
<span id="cb2-2"><a href="https://doisinkidney.com/rss.xml#cb2-2" tabindex="-1"/><span class="ot">insert ::</span> k <span class="ot">-&gt;</span> v <span class="ot">-&gt;</span> <span class="dt">Heap</span> k v <span class="ot">-&gt;</span> <span class="dt">Heap</span> k v</span>
<span id="cb2-3"><a href="https://doisinkidney.com/rss.xml#cb2-3" tabindex="-1"/><span class="ot">empty  ::</span> <span class="dt">Heap</span> k v</span></code></pre></div>
<p>Using these functions itâ€™s not hard to see how we can implement a
sorting algorithm:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb3-1"><a href="https://doisinkidney.com/rss.xml#cb3-1" tabindex="-1"/><span class="ot">sortOn ::</span> (a <span class="ot">-&gt;</span> k) <span class="ot">-&gt;</span> [a] <span class="ot">-&gt;</span> [a]</span>
<span id="cb3-2"><a href="https://doisinkidney.com/rss.xml#cb3-2" tabindex="-1"/>sortOn k <span class="ot">=</span> unfoldr popMin <span class="op">.</span> <span class="fu">foldr</span> (\x <span class="ot">-&gt;</span> insert (k x) x) empty</span></code></pre></div>
<p>The monus becomes relevant when the weight involved is some kind of
<em>monoid</em>. This is quite a common situation: if we were using the
heap for graph search (least-cost paths or something), we would expect
the weight to correspond to path costs, and we would expect that we can
add the costs of paths in a kind of monoidal way. Furthermore, we would
probably expect the monoidal operations to relate to the order in some
coherent way. A monus <span class="citation">(<a href="https://doisinkidney.com/rss.xml#ref-amer_equationally_1984">Amer
1984</a>)</span> is an ordered monoid where the order itself can be
defined <em>in terms</em> of the monoidal operations<a class="footnote-ref" href="https://doisinkidney.com/rss.xml#fn1" id="fnref1"><sup>1</sup></a>:</p>
<p><math display="block">&lt;semantics&gt;<mrow><mi>x</mi><mo>â‰¤</mo><mi>y</mi><mo>â‡”</mo><mo>âˆƒ</mo><mi>z</mi><mi>.</mi><mspace width="0.278em"/><mi>y</mi><mo>=</mo><mi>x</mi><mo>â€¢</mo><mi>z</mi></mrow>&lt;annotation encoding="application/x-tex"&gt; x \leq y \iff \exists z. \; y = x \bullet z &lt;/annotation&gt;&lt;/semantics&gt;</math></p>
<p>I read this definition as saying
â€œ<math display="inline">&lt;semantics&gt;<mi>x</mi>&lt;annotation encoding="application/x-tex"&gt;x&lt;/annotation&gt;&lt;/semantics&gt;</math>
is less than
<math display="inline">&lt;semantics&gt;<mi>y</mi>&lt;annotation encoding="application/x-tex"&gt;y&lt;/annotation&gt;&lt;/semantics&gt;</math>
iff there is some
<math display="inline">&lt;semantics&gt;<mi>z</mi>&lt;annotation encoding="application/x-tex"&gt;z&lt;/annotation&gt;&lt;/semantics&gt;</math>
that <em>fits between</em>
<math display="inline">&lt;semantics&gt;<mi>x</mi>&lt;annotation encoding="application/x-tex"&gt;x&lt;/annotation&gt;&lt;/semantics&gt;</math>
and
<math display="inline">&lt;semantics&gt;<mi>y</mi>&lt;annotation encoding="application/x-tex"&gt;y&lt;/annotation&gt;&lt;/semantics&gt;</math>â€�.
In other words, the <em>gap</em> between
<math display="inline">&lt;semantics&gt;<mi>x</mi>&lt;annotation encoding="application/x-tex"&gt;x&lt;/annotation&gt;&lt;/semantics&gt;</math>
and
<math display="inline">&lt;semantics&gt;<mi>y</mi>&lt;annotation encoding="application/x-tex"&gt;y&lt;/annotation&gt;&lt;/semantics&gt;</math>
has to exist, and it is equal to
<math display="inline">&lt;semantics&gt;<mi>z</mi>&lt;annotation encoding="application/x-tex"&gt;z&lt;/annotation&gt;&lt;/semantics&gt;</math>.</p>
<p>Notice that this order definition wonâ€™t work for groups like
<math display="inline">&lt;semantics&gt;<mrow><mo form="prefix" stretchy="false">(</mo><mi>â„¤</mi><mo>,</mo><mi>+</mi><mo>,</mo><mn>0</mn><mo form="postfix" stretchy="false">)</mo></mrow>&lt;annotation encoding="application/x-tex"&gt;(\mathbb{Z},+,0)&lt;/annotation&gt;&lt;/semantics&gt;</math>.
For a group, we can <em>always</em> find some
<math display="inline">&lt;semantics&gt;<mi>z</mi>&lt;annotation encoding="application/x-tex"&gt;z&lt;/annotation&gt;&lt;/semantics&gt;</math>
that will fit the existential (specifically,
<math display="inline">&lt;semantics&gt;<mrow><mi>z</mi><mo>=</mo><mo form="prefix" stretchy="false">(</mo><mi>âˆ’</mi><mi>x</mi><mo form="postfix" stretchy="false">)</mo><mo>â€¢</mo><mi>y</mi></mrow>&lt;annotation encoding="application/x-tex"&gt;z = (- x) \bullet y&lt;/annotation&gt;&lt;/semantics&gt;</math>).
Monuses, then, tend to be positive monoids: in fact, many monuses are
the positive cones of some group
(<math display="inline">&lt;semantics&gt;<mrow><mo form="prefix" stretchy="false">(</mo><mi>â„•</mi><mo>,</mo><mi>+</mi><mo>,</mo><mn>0</mn><mo form="postfix" stretchy="false">)</mo></mrow>&lt;annotation encoding="application/x-tex"&gt;(\mathbb{N},+,0)&lt;/annotation&gt;&lt;/semantics&gt;</math>
is the positive cone of
<math display="inline">&lt;semantics&gt;<mrow><mo form="prefix" stretchy="false">(</mo><mi>â„¤</mi><mo>,</mo><mi>+</mi><mo>,</mo><mn>0</mn><mo form="postfix" stretchy="false">)</mo></mrow>&lt;annotation encoding="application/x-tex"&gt;(\mathbb{Z},+,0)&lt;/annotation&gt;&lt;/semantics&gt;</math>).</p>
<p>We can derive a lot of useful properties from this basic structure.
For example, if the order above is total, then we can derive the binary
subtraction operator mentioned above:</p>
<p><math display="block">&lt;semantics&gt;<mrow><mi>x</mi><mo>âˆ¸</mo><mi>y</mi><mo>=</mo><mrow><mo form="prefix" stretchy="true">{</mo><mtable><mtr><mtd columnalign="left" style="text-align: left;"><mi>z</mi><mo>,</mo></mtd><mtd columnalign="left" style="text-align: left;"><mrow><mtext mathvariant="normal">if </mtext><mspace width="0.333em"/></mrow><mi>y</mi><mo>â‰¤</mo><mi>x</mi><mrow><mspace width="0.333em"/><mtext mathvariant="normal"> and </mtext><mspace width="0.333em"/></mrow><mi>x</mi><mo>=</mo><mi>y</mi><mo>â€¢</mo><mi>z</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left;"><mn>0</mn><mo>,</mo></mtd><mtd columnalign="left" style="text-align: left;"><mtext mathvariant="normal">otherwise.</mtext></mtd></mtr></mtable></mrow></mrow>&lt;annotation encoding="application/x-tex"&gt; x âˆ¸ y =
\begin{cases}
z, &amp; \text{if } y \leq x \text{ and } x = y \bullet z  \\
0, &amp; \text{otherwise.}
\end{cases}
&lt;/annotation&gt;&lt;/semantics&gt;</math></p>
<p>If we require the underlying monoid to be commutative, and we further
require the derived order to be total and antisymmetric, we get the
particular flavour of monus I worked with in a pair of papers on graph
search <span class="citation">(<a href="https://doisinkidney.com/rss.xml#ref-kidney_algebras_2021">2021</a>; <a href="https://doisinkidney.com/rss.xml#ref-kidney_formalising_2025">2025</a>)</span>. In this post I will actually be
working with a weakened form of the algebra that I will define
shortly.</p>
<p>Getting back to our heap from above, with this new order defined, we
can see that the heap property actually tells us something about the
makeup of the weights in the tree. Instead of every child just having a
weight equal to some arbitrary quantity, the heap property tells us that
each child weight has to be made up of the combination of its parentâ€™s
weight and some difference.</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb4-1"><a href="https://doisinkidney.com/rss.xml#cb4-1" tabindex="-1"/>   â”Œd              â”Œbâ€¢(dâˆ¸b)</span>
<span id="cb4-2"><a href="https://doisinkidney.com/rss.xml#cb4-2" tabindex="-1"/> â”Œbâ”¤       â”Œaâ€¢(bâˆ¸a)â”¤</span>
<span id="cb4-3"><a href="https://doisinkidney.com/rss.xml#cb4-3" tabindex="-1"/>aâ”¤ â””e  <span class="ot">=</span>  aâ”¤       â””bâ€¢(eâˆ¸b)</span>
<span id="cb4-4"><a href="https://doisinkidney.com/rss.xml#cb4-4" tabindex="-1"/> â””c        â””aâ€¢(câˆ¸a)</span></code></pre></div>
<p>This observation gives us an opportunity for a different
representation: instead of storing the full weight at each node, we
could instead just store the difference.</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb5-1"><a href="https://doisinkidney.com/rss.xml#cb5-1" tabindex="-1"/>     â”Œdâˆ¸b</span>
<span id="cb5-2"><a href="https://doisinkidney.com/rss.xml#cb5-2" tabindex="-1"/> â”Œbâˆ¸aâ”¤</span>
<span id="cb5-3"><a href="https://doisinkidney.com/rss.xml#cb5-3" tabindex="-1"/>aâ”¤   â””eâˆ¸b</span>
<span id="cb5-4"><a href="https://doisinkidney.com/rss.xml#cb5-4" tabindex="-1"/> â””câˆ¸a</span></code></pre></div>
<p>Just in terms of data structure design, I prefer this version: if we
wanted to write down a type of heaps using the previous design, we would
first define the type of trees, and then separately write a predicate
corresponding to the heap property. With this design, it is impossible
to write down a tree that <em>doesnâ€™t</em> satisfy the heap
property.</p>
<p>More practically, though, using this algebraic structure when working
with heaps enables some optimisations that might be difficult to
implement otherwise. The strength of this representation is that it
allows for efficient relative and global computation: now, if we wanted
to add some quantity to every weight in the tree, we can do it just by
adding the weight to the root node.</p>
<h1 id="monuses-in-haskell">Monuses in Haskell</h1>
<p>To see some examples of how to use this pattern, letâ€™s first write a
class for Haskell monuses:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb6-1"><a href="https://doisinkidney.com/rss.xml#cb6-1" tabindex="-1"/><span class="kw">class</span> (<span class="dt">Semigroup</span> a, <span class="dt">Ord</span> a) <span class="ot">=&gt;</span> <span class="dt">Monus</span> a <span class="kw">where</span></span>
<span id="cb6-2"><a href="https://doisinkidney.com/rss.xml#cb6-2" tabindex="-1"/>  (âˆ¸)<span class="ot"> ::</span> a <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> a</span></code></pre></div>
<p>Youâ€™ll notice that weâ€™re requiring semigroup here, not monoid. Thatâ€™s
because one of the nice uses of this pattern actually works with a
weakening of the usual monus algebra; this weakening only requires
semigroup, and the following two laws.</p>
<p><math display="block">&lt;semantics&gt;<mrow><mi>x</mi><mo>â‰¤</mo><mi>y</mi><mo>âŸ¹</mo><mi>x</mi><mo>â€¢</mo><mo form="prefix" stretchy="false">(</mo><mi>y</mi><mo>âˆ¸</mo><mi>x</mi><mo form="postfix" stretchy="false">)</mo><mo>=</mo><mi>y</mi><mspace width="1.0em"/><mspace width="1.0em"/><mspace width="1.0em"/><mspace width="1.0em"/><mspace width="1.0em"/><mi>x</mi><mo>â‰¤</mo><mi>y</mi><mo>âŸ¹</mo><mi>z</mi><mo>â€¢</mo><mi>x</mi><mo>â‰¤</mo><mi>z</mi><mo>â€¢</mo><mi>y</mi></mrow>&lt;annotation encoding="application/x-tex"&gt; x \leq y \implies x \bullet (y âˆ¸ x) = y
\quad \quad \quad \quad \quad
x \leq y \implies z \bullet x \leq z \bullet y &lt;/annotation&gt;&lt;/semantics&gt;</math></p>
<p>A straightforward monus instance is the following:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb7-1"><a href="https://doisinkidney.com/rss.xml#cb7-1" tabindex="-1"/><span class="kw">instance</span> (<span class="dt">Num</span> a, <span class="dt">Ord</span> a) <span class="ot">=&gt;</span> <span class="dt">Monus</span> (<span class="dt">Sum</span> a) <span class="kw">where</span></span>
<span id="cb7-2"><a href="https://doisinkidney.com/rss.xml#cb7-2" tabindex="-1"/>  (âˆ¸) <span class="ot">=</span> (<span class="op">-</span>)</span></code></pre></div>
<h1 id="pairing-heaps-in-haskell">Pairing Heaps in Haskell</h1>
<p>Next, letâ€™s look at a simple heap implementation. I will always go
for pairing heaps <span class="citation">(<a href="https://doisinkidney.com/rss.xml#ref-fredman_pairing_1986">Fredman et al. 1986</a>)</span> in Haskell; they
are extremely simple to implement, and (as long as you donâ€™t have
significant persistence requirements) their performance seems to be the
best of the available pointer-based heaps <span class="citation">(<a href="https://doisinkidney.com/rss.xml#ref-larkin_backtobasics_2013">Larkin, Sen,
and Tarjan 2013</a>)</span>. Here is the type definition:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb8-1"><a href="https://doisinkidney.com/rss.xml#cb8-1" tabindex="-1"/><span class="kw">data</span> <span class="dt">Root</span> k v <span class="ot">=</span> <span class="dt">Root</span> <span class="op">!</span>k v [<span class="dt">Root</span> k v]</span>
<span id="cb8-2"><a href="https://doisinkidney.com/rss.xml#cb8-2" tabindex="-1"/><span class="kw">type</span> <span class="dt">Heap</span> k v <span class="ot">=</span> <span class="dt">Maybe</span> (<span class="dt">Root</span> k v)</span></code></pre></div>
<p>A <code class="sourceCode haskell"><span class="dt">Root</span></code> is a
non-empty pairing heap; the <code class="sourceCode haskell"><span class="dt">Heap</span></code> type
represents possibly-empty heaps. The key function to implement is the
merging of two heaps; we can accomplish this as an implementation of the
semigroup <code class="sourceCode haskell"><span class="op">&lt;&gt;</span></code>.</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb9-1"><a href="https://doisinkidney.com/rss.xml#cb9-1" tabindex="-1"/><span class="kw">instance</span> <span class="dt">Monus</span> k <span class="ot">=&gt;</span> <span class="dt">Semigroup</span> (<span class="dt">Root</span> k v) <span class="kw">where</span></span>
<span id="cb9-2"><a href="https://doisinkidney.com/rss.xml#cb9-2" tabindex="-1"/>  <span class="dt">Root</span> xk xv xs <span class="op">&lt;&gt;</span> <span class="dt">Root</span> yk yv ys</span>
<span id="cb9-3"><a href="https://doisinkidney.com/rss.xml#cb9-3" tabindex="-1"/>    <span class="op">|</span> xk <span class="op">&lt;=</span> yk  <span class="ot">=</span> <span class="dt">Root</span> xk xv (<span class="dt">Root</span> (yk âˆ¸ xk) yv ys <span class="op">:</span> xs)</span>
<span id="cb9-4"><a href="https://doisinkidney.com/rss.xml#cb9-4" tabindex="-1"/>    <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="dt">Root</span> yk yv (<span class="dt">Root</span> (xk âˆ¸ yk) xv xs <span class="op">:</span> ys)</span></code></pre></div>
<p>The only difference between this and a normal pairing heap merge is
the use of <code class="sourceCode haskell">âˆ¸</code> in the key of the
child node (<code class="sourceCode haskell">yk âˆ¸ xk</code> and <code class="sourceCode haskell">xk âˆ¸ yk</code>). This difference ensures that
each child only holds the difference of the weight between itself and
its parent.</p>
<p>Itâ€™s worth working out why the weakened monus laws above are all we
need in order to maintain the heap property on this structure.</p>
<p>The rest of the methods are implemented the same as their
implementations on a normal pairing heap. First, we have the pairing
merge of a list of heaps, here given as an implementation of the
semigroup method <code class="sourceCode haskell">sconcat</code>:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb10-1"><a href="https://doisinkidney.com/rss.xml#cb10-1" tabindex="-1"/>  sconcat (x1 <span class="op">:|</span> []) <span class="ot">=</span> x1</span>
<span id="cb10-2"><a href="https://doisinkidney.com/rss.xml#cb10-2" tabindex="-1"/>  sconcat (x1 <span class="op">:|</span> [x2]) <span class="ot">=</span> x1 <span class="op">&lt;&gt;</span> x2</span>
<span id="cb10-3"><a href="https://doisinkidney.com/rss.xml#cb10-3" tabindex="-1"/>  sconcat (x1 <span class="op">:|</span> x2 <span class="op">:</span> x3 <span class="op">:</span> xs) <span class="ot">=</span> (x1 <span class="op">&lt;&gt;</span> x2) <span class="op">&lt;&gt;</span> sconcat (x3 <span class="op">:|</span> xs)</span>
<span id="cb10-4"><a href="https://doisinkidney.com/rss.xml#cb10-4" tabindex="-1"/></span>
<span id="cb10-5"><a href="https://doisinkidney.com/rss.xml#cb10-5" tabindex="-1"/><span class="ot">merges ::</span> <span class="dt">Monus</span> k <span class="ot">=&gt;</span> [<span class="dt">Root</span> k v] <span class="ot">-&gt;</span> <span class="dt">Heap</span> k v</span>
<span id="cb10-6"><a href="https://doisinkidney.com/rss.xml#cb10-6" tabindex="-1"/>merges <span class="ot">=</span> <span class="fu">fmap</span> sconcat <span class="op">.</span> nonEmpty</span></code></pre></div>
<p>The pattern of this two-level merge is what gives the pairing heap
its excellent performance.</p>
<p>The <code class="sourceCode haskell"><span class="dt">Heap</span></code> type
derives its monoid instance from the monoid instance on <code class="sourceCode haskell"><span class="dt">Maybe</span></code> (<code class="sourceCode haskell"><span class="kw">instance</span> <span class="dt">Semigroup</span> a <span class="ot">=&gt;</span> <span class="dt">Monoid</span> (<span class="dt">Maybe</span> a)</code>),
so we can implement <code class="sourceCode haskell">insert</code> like
so:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb11-1"><a href="https://doisinkidney.com/rss.xml#cb11-1" tabindex="-1"/><span class="ot">insert ::</span> <span class="dt">Monus</span> k <span class="ot">=&gt;</span> k <span class="ot">-&gt;</span> v <span class="ot">-&gt;</span> <span class="dt">Heap</span> k v <span class="ot">-&gt;</span> <span class="dt">Heap</span> k v</span>
<span id="cb11-2"><a href="https://doisinkidney.com/rss.xml#cb11-2" tabindex="-1"/>insert k v hp <span class="ot">=</span> <span class="dt">Just</span> (<span class="dt">Root</span> k v []) <span class="op">&lt;&gt;</span> hp</span></code></pre></div>
<p>And <code class="sourceCode haskell">popMin</code> is also relatively
simple:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb12-1"><a href="https://doisinkidney.com/rss.xml#cb12-1" tabindex="-1"/><span class="ot">delay ::</span> <span class="dt">Semigroup</span> k <span class="ot">=&gt;</span> k <span class="ot">-&gt;</span> <span class="dt">Heap</span> k v <span class="ot">-&gt;</span> <span class="dt">Heap</span> k v</span>
<span id="cb12-2"><a href="https://doisinkidney.com/rss.xml#cb12-2" tabindex="-1"/>delay by <span class="ot">=</span> <span class="fu">fmap</span> (\(<span class="dt">Root</span> k v xs) <span class="ot">-&gt;</span> <span class="dt">Root</span> (by <span class="op">&lt;&gt;</span> k) v xs)</span>
<span id="cb12-3"><a href="https://doisinkidney.com/rss.xml#cb12-3" tabindex="-1"/></span>
<span id="cb12-4"><a href="https://doisinkidney.com/rss.xml#cb12-4" tabindex="-1"/><span class="ot">popMin ::</span> <span class="dt">Monus</span> k <span class="ot">=&gt;</span> <span class="dt">Heap</span> k v <span class="ot">-&gt;</span> <span class="dt">Maybe</span> (v,<span class="dt">Heap</span> k v)</span>
<span id="cb12-5"><a href="https://doisinkidney.com/rss.xml#cb12-5" tabindex="-1"/>popMin <span class="ot">=</span> <span class="fu">fmap</span> (\(<span class="dt">Root</span> k v xs) <span class="ot">-&gt;</span> (v, k <span class="ot">`delay`</span> merges xs))</span></code></pre></div>
<p>Notice that we <code class="sourceCode haskell">delay</code> the rest
of the heap, because all of its entries need to be offset by the weight
of the previous root node. Thankfully, because weâ€™re only storing the
differences, we can â€œmodifyâ€� every weight by just increasing the weight
of the root, making this an
<math display="inline">&lt;semantics&gt;<mrow><mi>ğ�’ª</mi><mo form="prefix" stretchy="false">(</mo><mn>1</mn><mo form="postfix" stretchy="false">)</mo></mrow>&lt;annotation encoding="application/x-tex"&gt;\mathcal{O}(1)&lt;/annotation&gt;&lt;/semantics&gt;</math>
operation.</p>
<p>Finally, we can implement heap sort like so:</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb13-1"><a href="https://doisinkidney.com/rss.xml#cb13-1" tabindex="-1"/><span class="ot">sortOn ::</span> <span class="dt">Monus</span> k <span class="ot">=&gt;</span> (a <span class="ot">-&gt;</span> k) <span class="ot">-&gt;</span> [a] <span class="ot">-&gt;</span> [a]</span>
<span id="cb13-2"><a href="https://doisinkidney.com/rss.xml#cb13-2" tabindex="-1"/>sortOn k <span class="ot">=</span> unfoldr popMin <span class="op">.</span> foldl' (\xs x <span class="ot">-&gt;</span> insert (k x) x xs) <span class="dt">Nothing</span></span></code></pre></div>
<p>And it does indeed work:</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb14-1"><a href="https://doisinkidney.com/rss.xml#cb14-1" tabindex="-1"/><span class="op">&gt;&gt;&gt;</span> sortOn <span class="dt">Sum</span> [<span class="dv">3</span>,<span class="dv">4</span>,<span class="dv">2</span>,<span class="dv">5</span>,<span class="dv">1</span>]</span>
<span id="cb14-2"><a href="https://doisinkidney.com/rss.xml#cb14-2" tabindex="-1"/>[<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></code></pre></div>
<p>Here is a trace of the output:</p>
<details>

Trace

<pre class="text"><code>Input           Heap:
list:

[3,4,2,5,1]


[4,2,5,1]       3


[2,5,1]         3â”€1


[5,1]           2â”€1â”€1


[1]              â”Œ3
                2â”¤
                 â””1â”€1


[]                 â”Œ3
                1â”€1â”¤
                   â””1â”€1


Output          Heap:
list:

[]                 â”Œ3
                1â”€1â”¤
                   â””1â”€1


[1]              â”Œ3
                2â”¤
                 â””1â”€1


[1,2]            â”Œ2
                3â”¤
                 â””1


[1,2,3]         4â”€1


[1,2,3,4]       5


[1,2,3,4,5]</code></pre>
</details>
<p>While the heap implementation presented here is pretty efficient,
note that we could significantly improve its performance with a few
optimisations: first, we could unpack all of the constructors, using a
custom list definition in <code class="sourceCode haskell"><span class="dt">Root</span></code> instead
of Haskellâ€™s built-in lists; second, in <code class="sourceCode haskell">foldl'</code> we could avoid the <code class="sourceCode haskell"><span class="dt">Maybe</span></code> wrapper
by building a non-empty heap. There are probably more small
optimisations available as well.</p>
<h1 id="retrieving-a-normal-heap">Retrieving a Normal Heap</h1>
<p>A problem with the definition of <code class="sourceCode haskell">sortOn</code> above is that it requires a
<code class="sourceCode haskell"><span class="dt">Monus</span></code>
instance on the keys, but it only really needs <code class="sourceCode haskell"><span class="dt">Ord</span></code>. It seems
that by switching to the <code class="sourceCode haskell"><span class="dt">Monus</span></code>-powered
heap we have lost some generality.</p>
<p>Luckily, there are two monuses we can use to solve this problem:</p>
<div class="sourceCode" id="cb16"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb16-1"><a href="https://doisinkidney.com/rss.xml#cb16-1" tabindex="-1"/><span class="kw">instance</span> <span class="dt">Ord</span> a <span class="ot">=&gt;</span> <span class="dt">Monus</span> (<span class="dt">Max</span> a) <span class="kw">where</span></span>
<span id="cb16-2"><a href="https://doisinkidney.com/rss.xml#cb16-2" tabindex="-1"/>  x âˆ¸ y <span class="ot">=</span> x</span>
<span id="cb16-3"><a href="https://doisinkidney.com/rss.xml#cb16-3" tabindex="-1"/></span>
<span id="cb16-4"><a href="https://doisinkidney.com/rss.xml#cb16-4" tabindex="-1"/><span class="kw">instance</span> <span class="dt">Ord</span> a <span class="ot">=&gt;</span> <span class="dt">Monus</span> (<span class="dt">Last</span> a) <span class="kw">where</span></span>
<span id="cb16-5"><a href="https://doisinkidney.com/rss.xml#cb16-5" tabindex="-1"/>  x âˆ¸ y <span class="ot">=</span> x</span></code></pre></div>
<p>The <code class="sourceCode haskell"><span class="dt">Max</span></code> semigroup
uses the <code class="sourceCode haskell"><span class="fu">max</span></code> operation,
and the <code class="sourceCode haskell"><span class="dt">Last</span></code> semigroup
returns its second operand.</p>
<div class="sourceCode" id="cb17"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb17-1"><a href="https://doisinkidney.com/rss.xml#cb17-1" tabindex="-1"/><span class="kw">instance</span> <span class="dt">Ord</span> a <span class="ot">=&gt;</span> <span class="dt">Semigroup</span> (<span class="dt">Max</span> a) <span class="kw">where</span></span>
<span id="cb17-2"><a href="https://doisinkidney.com/rss.xml#cb17-2" tabindex="-1"/>  <span class="dt">Max</span> x <span class="op">&lt;&gt;</span> <span class="dt">Max</span> y <span class="ot">=</span> <span class="dt">Max</span> (<span class="fu">max</span> x y)</span>
<span id="cb17-3"><a href="https://doisinkidney.com/rss.xml#cb17-3" tabindex="-1"/></span>
<span id="cb17-4"><a href="https://doisinkidney.com/rss.xml#cb17-4" tabindex="-1"/><span class="kw">instance</span> <span class="dt">Semigroup</span> (<span class="dt">Last</span> a) <span class="kw">where</span></span>
<span id="cb17-5"><a href="https://doisinkidney.com/rss.xml#cb17-5" tabindex="-1"/>  x <span class="op">&lt;&gt;</span> y <span class="ot">=</span> y</span></code></pre></div>
<p>While the <code class="sourceCode haskell"><span class="dt">Monus</span></code>
instances here might seem degenerate, they do actually satisfy the <code class="sourceCode haskell"><span class="dt">Monus</span></code> laws as
given above.</p>
<details>

<code class="sourceCode haskell"><span class="dt">Max</span></code> and
<code class="sourceCode haskell"><span class="dt">Last</span></code>
Monus laws

<p>Max:</p>
<div class="sourceCode" id="cb18"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb18-1"><a href="https://doisinkidney.com/rss.xml#cb18-1" tabindex="-1"/>x <span class="op">&lt;=</span> y <span class="op">==&gt;</span> x <span class="op">&lt;&gt;</span> (y âˆ¸ x) <span class="ot">=</span> y</span>
<span id="cb18-2"><a href="https://doisinkidney.com/rss.xml#cb18-2" tabindex="-1"/><span class="dt">Max</span> x <span class="op">&lt;=</span> <span class="dt">Max</span> y <span class="op">==&gt;</span> <span class="dt">Max</span> x <span class="op">&lt;&gt;</span> (<span class="dt">Max</span> y âˆ¸ <span class="dt">Max</span> x) <span class="ot">=</span> <span class="dt">Max</span> y</span>
<span id="cb18-3"><a href="https://doisinkidney.com/rss.xml#cb18-3" tabindex="-1"/><span class="dt">Max</span> x <span class="op">&lt;=</span> <span class="dt">Max</span> y <span class="op">==&gt;</span> <span class="dt">Max</span> x <span class="op">&lt;&gt;</span> <span class="dt">Max</span> y <span class="ot">=</span> <span class="dt">Max</span> y</span>
<span id="cb18-4"><a href="https://doisinkidney.com/rss.xml#cb18-4" tabindex="-1"/><span class="dt">Max</span> x <span class="op">&lt;=</span> <span class="dt">Max</span> y <span class="op">==&gt;</span> <span class="dt">Max</span> (<span class="fu">max</span> x y) <span class="ot">=</span> <span class="dt">Max</span> y</span>
<span id="cb18-5"><a href="https://doisinkidney.com/rss.xml#cb18-5" tabindex="-1"/>x <span class="op">&lt;=</span> y <span class="op">==&gt;</span> <span class="fu">max</span> x y <span class="ot">=</span> y</span>
<span id="cb18-6"><a href="https://doisinkidney.com/rss.xml#cb18-6" tabindex="-1"/></span>
<span id="cb18-7"><a href="https://doisinkidney.com/rss.xml#cb18-7" tabindex="-1"/>x <span class="op">&lt;=</span> y <span class="op">==&gt;</span> z <span class="op">&lt;&gt;</span> x <span class="op">&lt;=</span> z <span class="op">&lt;&gt;</span> y</span>
<span id="cb18-8"><a href="https://doisinkidney.com/rss.xml#cb18-8" tabindex="-1"/><span class="dt">Max</span> x <span class="op">&lt;=</span> <span class="dt">Max</span> y <span class="op">==&gt;</span> <span class="dt">Max</span> z <span class="op">&lt;&gt;</span> <span class="dt">Max</span> x <span class="op">&lt;=</span> <span class="dt">Max</span> z <span class="op">&lt;&gt;</span> <span class="dt">Max</span> y</span>
<span id="cb18-9"><a href="https://doisinkidney.com/rss.xml#cb18-9" tabindex="-1"/><span class="dt">Max</span> x <span class="op">&lt;=</span> <span class="dt">Max</span> y <span class="op">==&gt;</span> <span class="dt">Max</span> (<span class="fu">max</span> z x) <span class="op">&lt;=</span> <span class="dt">Max</span> (<span class="fu">max</span> z y)</span>
<span id="cb18-10"><a href="https://doisinkidney.com/rss.xml#cb18-10" tabindex="-1"/>x <span class="op">&lt;=</span> y <span class="op">==&gt;</span> <span class="fu">max</span> z x <span class="op">&lt;=</span> <span class="fu">max</span> z y</span></code></pre></div>
<p>Last:</p>
<div class="sourceCode" id="cb19"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb19-1"><a href="https://doisinkidney.com/rss.xml#cb19-1" tabindex="-1"/>x <span class="op">&lt;=</span> y <span class="op">==&gt;</span> x <span class="op">&lt;&gt;</span> (y âˆ¸ x) <span class="ot">=</span> y</span>
<span id="cb19-2"><a href="https://doisinkidney.com/rss.xml#cb19-2" tabindex="-1"/><span class="dt">Last</span> x <span class="op">&lt;=</span> <span class="dt">Last</span> y <span class="op">==&gt;</span> <span class="dt">Last</span> x <span class="op">&lt;&gt;</span> (<span class="dt">Last</span> y âˆ¸ <span class="dt">Last</span> x) <span class="ot">=</span> <span class="dt">Last</span> y</span>
<span id="cb19-3"><a href="https://doisinkidney.com/rss.xml#cb19-3" tabindex="-1"/><span class="dt">Last</span> x <span class="op">&lt;=</span> <span class="dt">Last</span> y <span class="op">==&gt;</span> <span class="dt">Last</span> x <span class="op">&lt;&gt;</span> <span class="dt">Last</span> y <span class="ot">=</span> <span class="dt">Last</span> y</span>
<span id="cb19-4"><a href="https://doisinkidney.com/rss.xml#cb19-4" tabindex="-1"/><span class="dt">Last</span> x <span class="op">&lt;=</span> <span class="dt">Last</span> y <span class="op">==&gt;</span> <span class="dt">Last</span> y <span class="ot">=</span> <span class="dt">Last</span> y</span>
<span id="cb19-5"><a href="https://doisinkidney.com/rss.xml#cb19-5" tabindex="-1"/></span>
<span id="cb19-6"><a href="https://doisinkidney.com/rss.xml#cb19-6" tabindex="-1"/>x <span class="op">&lt;=</span> y <span class="op">==&gt;</span> z <span class="op">&lt;&gt;</span> x <span class="op">&lt;=</span> z <span class="op">&lt;&gt;</span> y</span>
<span id="cb19-7"><a href="https://doisinkidney.com/rss.xml#cb19-7" tabindex="-1"/><span class="dt">Last</span> x <span class="op">&lt;=</span> <span class="dt">Last</span> y <span class="op">==&gt;</span> <span class="dt">Last</span> z <span class="op">&lt;&gt;</span> <span class="dt">Last</span> x <span class="op">&lt;=</span> <span class="dt">Last</span> z <span class="op">&lt;&gt;</span> <span class="dt">Last</span> y</span>
<span id="cb19-8"><a href="https://doisinkidney.com/rss.xml#cb19-8" tabindex="-1"/><span class="dt">Last</span> x <span class="op">&lt;=</span> <span class="dt">Last</span> y <span class="op">==&gt;</span> <span class="dt">Last</span> x <span class="op">&lt;=</span> <span class="dt">Last</span> y</span></code></pre></div>
</details>
<p>Either <code class="sourceCode haskell"><span class="dt">Max</span></code> or <code class="sourceCode haskell"><span class="dt">Last</span></code> will
work; semantically, thereâ€™s no real difference. <code class="sourceCode haskell"><span class="dt">Last</span></code> avoids
some comparisons, so we can use that:</p>
<div class="sourceCode" id="cb20"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb20-1"><a href="https://doisinkidney.com/rss.xml#cb20-1" tabindex="-1"/><span class="ot">sortOn' ::</span> <span class="dt">Ord</span> k <span class="ot">=&gt;</span> (a <span class="ot">-&gt;</span> k) <span class="ot">-&gt;</span> [a] <span class="ot">-&gt;</span> [a]</span>
<span id="cb20-2"><a href="https://doisinkidney.com/rss.xml#cb20-2" tabindex="-1"/>sortOn' k <span class="ot">=</span> sortOn (<span class="dt">Last</span> <span class="op">.</span> k)</span></code></pre></div>
<h1 id="phases-as-a-pairing-heap">Phases as a Pairing Heap</h1>
<p>The <code class="sourceCode haskell"><span class="dt">Phases</span></code>
applicative <span class="citation">(<a href="https://doisinkidney.com/rss.xml#ref-easterly_functions_2019">Easterly
2019</a>)</span> is an <code class="sourceCode haskell"><span class="dt">Applicative</span></code>
transformer that allows reordering of <code class="sourceCode haskell"><span class="dt">Applicative</span></code>
effects in an easy-to-use, high-level way. The interface looks like
this:</p>
<div class="sourceCode" id="cb21"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb21-1"><a href="https://doisinkidney.com/rss.xml#cb21-1" tabindex="-1"/><span class="ot">phase     ::</span> <span class="dt">Natural</span> <span class="ot">-&gt;</span> f a <span class="ot">-&gt;</span> <span class="dt">Phases</span> f a</span>
<span id="cb21-2"><a href="https://doisinkidney.com/rss.xml#cb21-2" tabindex="-1"/><span class="ot">runPhases ::</span> <span class="dt">Applicative</span> f <span class="ot">=&gt;</span> <span class="dt">Phases</span> f a <span class="ot">-&gt;</span> f a</span>
<span id="cb21-3"><a href="https://doisinkidney.com/rss.xml#cb21-3" tabindex="-1"/></span>
<span id="cb21-4"><a href="https://doisinkidney.com/rss.xml#cb21-4" tabindex="-1"/><span class="kw">instance</span> <span class="dt">Applicative</span> f <span class="ot">=&gt;</span> <span class="dt">Applicative</span> (<span class="dt">Phases</span> f)</span></code></pre></div>
<p>And we can use it like this:</p>
<div class="sourceCode" id="cb22"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb22-1"><a href="https://doisinkidney.com/rss.xml#cb22-1" tabindex="-1"/><span class="ot">phased ::</span> <span class="dt">IO</span> <span class="dt">String</span></span>
<span id="cb22-2"><a href="https://doisinkidney.com/rss.xml#cb22-2" tabindex="-1"/>phased <span class="ot">=</span> runPhases <span class="op">$</span> <span class="fu">sequenceA</span></span>
<span id="cb22-3"><a href="https://doisinkidney.com/rss.xml#cb22-3" tabindex="-1"/>  [ phase <span class="dv">3</span> <span class="op">$</span> emit <span class="ch">'a'</span></span>
<span id="cb22-4"><a href="https://doisinkidney.com/rss.xml#cb22-4" tabindex="-1"/>  , phase <span class="dv">2</span> <span class="op">$</span> emit <span class="ch">'b'</span></span>
<span id="cb22-5"><a href="https://doisinkidney.com/rss.xml#cb22-5" tabindex="-1"/>  , phase <span class="dv">1</span> <span class="op">$</span> emit <span class="ch">'c'</span></span>
<span id="cb22-6"><a href="https://doisinkidney.com/rss.xml#cb22-6" tabindex="-1"/>  , phase <span class="dv">2</span> <span class="op">$</span> emit <span class="ch">'d'</span></span>
<span id="cb22-7"><a href="https://doisinkidney.com/rss.xml#cb22-7" tabindex="-1"/>  , phase <span class="dv">3</span> <span class="op">$</span> emit <span class="ch">'e'</span> ]</span>
<span id="cb22-8"><a href="https://doisinkidney.com/rss.xml#cb22-8" tabindex="-1"/>  <span class="kw">where</span> emit c <span class="ot">=</span> <span class="fu">putChar</span> c <span class="op">&gt;&gt;</span> <span class="fu">return</span> c</span>
<span id="cb22-9"><a href="https://doisinkidney.com/rss.xml#cb22-9" tabindex="-1"/></span>
<span id="cb22-10"><a href="https://doisinkidney.com/rss.xml#cb22-10" tabindex="-1"/><span class="op">&gt;&gt;&gt;</span> phased</span>
<span id="cb22-11"><a href="https://doisinkidney.com/rss.xml#cb22-11" tabindex="-1"/>cbdae</span>
<span id="cb22-12"><a href="https://doisinkidney.com/rss.xml#cb22-12" tabindex="-1"/><span class="st">"abcde"</span></span></code></pre></div>
<p>The above computation performs the <em>effects</em> in the order
dictated by their phases (this is why the characters are printed out in
the order <code class="sourceCode haskell">cbdae</code>), but the pure
value (the returned string) has its order unaffected.</p>
<p>I have written about this type <a href="https://doisinkidney.com/posts/2019-05-28-linear-phases.html">before</a>, and in a handful
of papers <span class="citation">(<a href="https://doisinkidney.com/rss.xml#ref-kidney_algebras_2021">2021</a>; <a href="https://doisinkidney.com/rss.xml#ref-gibbons_breadthfirst_2022">Gibbons et
al. 2022</a>; <a href="https://doisinkidney.com/rss.xml#ref-gibbons_phases_2023">Gibbons et al. 2023</a>)</span>, but more recently
<span class="citation">BlÃ¶ndal (<a href="https://doisinkidney.com/rss.xml#ref-blondal_generalized_2025">2025a</a>)</span> started looking into trying to
use the <code class="sourceCode haskell"><span class="dt">Phases</span></code> pattern
with arbitrary ordered keys <span class="citation">(<a href="https://doisinkidney.com/rss.xml#ref-visscher_phases_2025">Visscher 2025</a>;
<a href="https://doisinkidney.com/rss.xml#ref-blondal_phases_2025">BlÃ¶ndal
2025b</a>)</span>. There are a lot of different directions you can go
from the <code class="sourceCode haskell"><span class="dt">Phases</span></code> type;
what interested me most immediately was the idea of implementing the
type efficiently using standard data-structure representations. If our
core goal here is to order some values according to a key, then that is
clearly a problem that a heap should solve: enter the free applicative
pairing heap.</p>
<p>Here is the typeâ€™s definition:</p>
<div class="sourceCode" id="cb23"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb23-1"><a href="https://doisinkidney.com/rss.xml#cb23-1" tabindex="-1"/><span class="kw">data</span> <span class="dt">Heap</span> k f a <span class="kw">where</span></span>
<span id="cb23-2"><a href="https://doisinkidney.com/rss.xml#cb23-2" tabindex="-1"/>  <span class="dt">Pure</span><span class="ot"> ::</span> a <span class="ot">-&gt;</span> <span class="dt">Heap</span> k f a</span>
<span id="cb23-3"><a href="https://doisinkidney.com/rss.xml#cb23-3" tabindex="-1"/>  <span class="dt">Root</span><span class="ot"> ::</span> <span class="op">!</span>k <span class="ot">-&gt;</span> (x <span class="ot">-&gt;</span> y <span class="ot">-&gt;</span> a) <span class="ot">-&gt;</span> f x <span class="ot">-&gt;</span> <span class="dt">Heaps</span> k f y <span class="ot">-&gt;</span> <span class="dt">Heap</span> k f a</span>
<span id="cb23-4"><a href="https://doisinkidney.com/rss.xml#cb23-4" tabindex="-1"/></span>
<span id="cb23-5"><a href="https://doisinkidney.com/rss.xml#cb23-5" tabindex="-1"/><span class="kw">data</span> <span class="dt">Heaps</span> k f a <span class="kw">where</span></span>
<span id="cb23-6"><a href="https://doisinkidney.com/rss.xml#cb23-6" tabindex="-1"/>  <span class="dt">Nil</span><span class="ot"> ::</span> <span class="dt">Heaps</span> k f ()</span>
<span id="cb23-7"><a href="https://doisinkidney.com/rss.xml#cb23-7" tabindex="-1"/>  <span class="dt">App</span><span class="ot"> ::</span> <span class="op">!</span>k <span class="ot">-&gt;</span> f x <span class="ot">-&gt;</span> <span class="dt">Heaps</span> k f y <span class="ot">-&gt;</span> <span class="dt">Heaps</span> k f z <span class="ot">-&gt;</span> <span class="dt">Heaps</span> k f (x,y,z)</span></code></pre></div>
<p>We have had to change a few aspects of the original pairing heap, but
the overall structure remains. The entries in this heap are now
effectful computations: the <code class="sourceCode haskell">f</code>s.
The data structure also contains some scaffolding to reconstruct the
pure values â€œinsideâ€� each effect when we actually run the heap.</p>
<p>The root-level structure is the <code class="sourceCode haskell"><span class="dt">Heap</span></code>: this can
either be <code class="sourceCode haskell"><span class="dt">Pure</span></code>
(corresponding to an empty heap: notice that, though this constructor
has some contents (the <code class="sourceCode haskell">a</code>), it is
still regarded as â€œemptyâ€� because it contains no effects (<code class="sourceCode haskell">f</code>)); or a <code class="sourceCode haskell"><span class="dt">Root</span></code>, which is
a singleton value, paired with the list of sub-heaps represented by the
<code class="sourceCode haskell"><span class="dt">Heaps</span></code>
type. Weâ€™re using the usual Yoneda-ish trick here to allow the top-level
data type to be parametric and a <code class="sourceCode haskell"><span class="dt">Functor</span></code>, by
storing the function <code class="sourceCode haskell">x <span class="ot">-&gt;</span> y <span class="ot">-&gt;</span> a</code>.</p>
<p>The <code class="sourceCode haskell"><span class="dt">Heaps</span></code> type
then plays the role of <code class="sourceCode haskell">[<span class="dt">Root</span> k v]</code> in
the previous pairing heap implementation; here, we have inlined all of
the constructors so that we can get all of the types to line up.
Remember, this is a heap of <em>effects</em>, not of pure values: the
pure values need to be able to be reconstructed to one single top-level
<code class="sourceCode haskell">a</code> when we run the heap at the
end.</p>
<p>Merging two heaps happens in the <code class="sourceCode haskell"><span class="dt">Applicative</span></code>
instance itself:</p>
<div class="sourceCode" id="cb24"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb24-1"><a href="https://doisinkidney.com/rss.xml#cb24-1" tabindex="-1"/><span class="kw">instance</span> <span class="dt">Functor</span> (<span class="dt">Heap</span> k f) <span class="kw">where</span></span>
<span id="cb24-2"><a href="https://doisinkidney.com/rss.xml#cb24-2" tabindex="-1"/>  <span class="fu">fmap</span> f (<span class="dt">Pure</span> x) <span class="ot">=</span> <span class="dt">Pure</span> (f x)</span>
<span id="cb24-3"><a href="https://doisinkidney.com/rss.xml#cb24-3" tabindex="-1"/>  <span class="fu">fmap</span> f (<span class="dt">Root</span> k c x xs) <span class="ot">=</span> <span class="dt">Root</span> k (\a b <span class="ot">-&gt;</span> f (c a b)) x xs</span>
<span id="cb24-4"><a href="https://doisinkidney.com/rss.xml#cb24-4" tabindex="-1"/></span>
<span id="cb24-5"><a href="https://doisinkidney.com/rss.xml#cb24-5" tabindex="-1"/><span class="kw">instance</span> <span class="dt">Monus</span> k <span class="ot">=&gt;</span> <span class="dt">Applicative</span> (<span class="dt">Heap</span> k f) <span class="kw">where</span></span>
<span id="cb24-6"><a href="https://doisinkidney.com/rss.xml#cb24-6" tabindex="-1"/>  <span class="fu">pure</span> <span class="ot">=</span> <span class="dt">Pure</span></span>
<span id="cb24-7"><a href="https://doisinkidney.com/rss.xml#cb24-7" tabindex="-1"/>  <span class="dt">Pure</span> f <span class="op">&lt;*&gt;</span> xs <span class="ot">=</span> <span class="fu">fmap</span> f xs</span>
<span id="cb24-8"><a href="https://doisinkidney.com/rss.xml#cb24-8" tabindex="-1"/>  xs <span class="op">&lt;*&gt;</span> <span class="dt">Pure</span> f <span class="ot">=</span> <span class="fu">fmap</span> (<span class="op">$</span> f) xs</span>
<span id="cb24-9"><a href="https://doisinkidney.com/rss.xml#cb24-9" tabindex="-1"/></span>
<span id="cb24-10"><a href="https://doisinkidney.com/rss.xml#cb24-10" tabindex="-1"/>  <span class="dt">Root</span> xk xc xs xss <span class="op">&lt;*&gt;</span> <span class="dt">Root</span> yk yc ys yss</span>
<span id="cb24-11"><a href="https://doisinkidney.com/rss.xml#cb24-11" tabindex="-1"/>    <span class="op">|</span> xk <span class="op">&lt;=</span> yk  <span class="ot">=</span> <span class="dt">Root</span> xk (\a (b,c,d) <span class="ot">-&gt;</span> xc a d (yc b c)) xs (<span class="dt">App</span> (yk âˆ¸ xk) ys yss xss)</span>
<span id="cb24-12"><a href="https://doisinkidney.com/rss.xml#cb24-12" tabindex="-1"/>    <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="dt">Root</span> yk (\a (b,c,d) <span class="ot">-&gt;</span> xc b c (yc a d)) ys (<span class="dt">App</span> (xk âˆ¸ yk) xs xss yss)</span></code></pre></div>
<p>To actually run the heap we will use the following two functions:</p>
<div class="sourceCode" id="cb25"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb25-1"><a href="https://doisinkidney.com/rss.xml#cb25-1" tabindex="-1"/><span class="ot">merges ::</span> (<span class="dt">Monus</span> k, <span class="dt">Applicative</span> f) <span class="ot">=&gt;</span> <span class="dt">Heaps</span> k f a <span class="ot">-&gt;</span> <span class="dt">Heap</span> k f a</span>
<span id="cb25-2"><a href="https://doisinkidney.com/rss.xml#cb25-2" tabindex="-1"/>merges <span class="dt">Nil</span> <span class="ot">=</span> <span class="dt">Pure</span> ()</span>
<span id="cb25-3"><a href="https://doisinkidney.com/rss.xml#cb25-3" tabindex="-1"/>merges (<span class="dt">App</span> k1 e1 t1 <span class="dt">Nil</span>) <span class="ot">=</span> <span class="dt">Root</span> k1 (,,()) e1 t1</span>
<span id="cb25-4"><a href="https://doisinkidney.com/rss.xml#cb25-4" tabindex="-1"/>merges (<span class="dt">App</span> k1 e1 t1 (<span class="dt">App</span> k2 e2 t2 xs)) <span class="ot">=</span></span>
<span id="cb25-5"><a href="https://doisinkidney.com/rss.xml#cb25-5" tabindex="-1"/>   (<span class="dt">Root</span> k1 (\a b cd es <span class="ot">-&gt;</span> (a,b, cd es)) e1 t1 <span class="op">&lt;*&gt;</span> <span class="dt">Root</span> k2 (,,) e2 t2) <span class="op">&lt;*&gt;</span> merges xs</span>
<span id="cb25-6"><a href="https://doisinkidney.com/rss.xml#cb25-6" tabindex="-1"/></span>
<span id="cb25-7"><a href="https://doisinkidney.com/rss.xml#cb25-7" tabindex="-1"/><span class="ot">runHeap ::</span> (<span class="dt">Monus</span> k, <span class="dt">Applicative</span> f) <span class="ot">=&gt;</span> <span class="dt">Heap</span> k f a <span class="ot">-&gt;</span> f a</span>
<span id="cb25-8"><a href="https://doisinkidney.com/rss.xml#cb25-8" tabindex="-1"/>runHeap (<span class="dt">Pure</span> x) <span class="ot">=</span> <span class="fu">pure</span> x</span>
<span id="cb25-9"><a href="https://doisinkidney.com/rss.xml#cb25-9" tabindex="-1"/>runHeap (<span class="dt">Root</span> _ c x xs) <span class="ot">=</span> liftA2 c x (runHeap (merges xs))</span></code></pre></div>
<p>And we can lift a computation into <code class="sourceCode haskell"><span class="dt">Phases</span></code> like
so:</p>
<div class="sourceCode" id="cb26"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb26-1"><a href="https://doisinkidney.com/rss.xml#cb26-1" tabindex="-1"/><span class="ot">phase ::</span> k <span class="ot">-&gt;</span> f a <span class="ot">-&gt;</span> <span class="dt">Heap</span> k f a</span>
<span id="cb26-2"><a href="https://doisinkidney.com/rss.xml#cb26-2" tabindex="-1"/>phase k xs <span class="ot">=</span> <span class="dt">Root</span> k <span class="fu">const</span> xs <span class="dt">Nil</span></span></code></pre></div>
<h1 id="stabilising-phases">Stabilising Phases</h1>
<p>Thereâ€™s a problem. A heap sort based on a pairing heap isnâ€™t
<em>stable</em>. That means that the order of effects here can vary for
two effects in the same phase. If we look back to the example with the
strings we saw above, that means that outputs like <code class="sourceCode haskell">cdbea</code> would be possible (in actual
fact, we donâ€™t get any reordering in this particular example, but thatâ€™s
just an accident of the way the applicative operators are associated
under the hood).</p>
<p>This is problematic because we would expect effects in the same phase
to behave as if they were normal applicative effects, sequenced
according to their syntactic order. It also means that the applicative
transformer breaks the applicative laws, because effects might be
reordered according to the association of the applicative operators,
which should lawfully be associative.</p>
<p>To make the sort stable, we could layer the heap effect with some
state effect that would tag each effect with its order. However, that
would hurt efficiency and composability: it would force us to linearise
the whole heap sort procedure, where currently different branches of the
tree can compute completely independently of each other. The solution
comes in the form of another monus: the key monus.</p>
<div class="sourceCode" id="cb27"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb27-1"><a href="https://doisinkidney.com/rss.xml#cb27-1" tabindex="-1"/><span class="kw">data</span> <span class="dt">Key</span> k <span class="ot">=</span> <span class="op">!</span>k <span class="op">:*</span> <span class="ot">{-# UNPACK #-}</span> <span class="op">!</span><span class="dt">Int</span> <span class="kw">deriving</span> (<span class="dt">Eq</span>, <span class="dt">Ord</span>)</span></code></pre></div>
<p>A <code class="sourceCode haskell"><span class="dt">Key</span> k</code> is some
ordered key <code class="sourceCode haskell">k</code> coupled with an
<code class="sourceCode haskell"><span class="dt">Int</span></code> that
represents the offset between the original position and the current
position of the key. In this way, when two keys compare as equal, we can
cascade on to compare their original positions, thereby maintaining
their original order when there is ambiguity caused by a key collision.
However, in contrast to the approach of walking over the data once and
tagging it all with positions, this approach keeps the location
information completely local: we never need to know that some key is in
the
<math display="inline">&lt;semantics&gt;<mi>n</mi>&lt;annotation encoding="application/x-tex"&gt;n&lt;/annotation&gt;&lt;/semantics&gt;</math>th
position in the original sequence, only that it has moved
<math display="inline">&lt;semantics&gt;<mi>n</mi>&lt;annotation encoding="application/x-tex"&gt;n&lt;/annotation&gt;&lt;/semantics&gt;</math>
steps from its original position.</p>
<p>The instances are as follows:</p>
<div class="sourceCode" id="cb28"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb28-1"><a href="https://doisinkidney.com/rss.xml#cb28-1" tabindex="-1"/><span class="kw">instance</span> <span class="dt">Semigroup</span> (<span class="dt">Key</span> k) <span class="kw">where</span></span>
<span id="cb28-2"><a href="https://doisinkidney.com/rss.xml#cb28-2" tabindex="-1"/>  (xk <span class="op">:*</span> xi) <span class="op">&lt;&gt;</span> (yk <span class="op">:*</span> yi) <span class="ot">=</span> yk <span class="op">:*</span> (xi <span class="op">+</span> yi)</span>
<span id="cb28-3"><a href="https://doisinkidney.com/rss.xml#cb28-3" tabindex="-1"/></span>
<span id="cb28-4"><a href="https://doisinkidney.com/rss.xml#cb28-4" tabindex="-1"/><span class="kw">instance</span> <span class="dt">Ord</span> k <span class="ot">=&gt;</span> <span class="dt">Monus</span> (<span class="dt">Key</span> k) <span class="kw">where</span></span>
<span id="cb28-5"><a href="https://doisinkidney.com/rss.xml#cb28-5" tabindex="-1"/>  (xk <span class="op">:*</span> xi) âˆ¸ (yk <span class="op">:*</span> yi) <span class="ot">=</span> xk <span class="op">:*</span> (xi <span class="op">-</span> yi)</span></code></pre></div>
<p>This instance is basically a combination of the <code class="sourceCode haskell"><span class="dt">Last</span></code> semigroup
and the
<math display="inline">&lt;semantics&gt;<mrow><mo form="prefix" stretchy="false">(</mo><mi>â„¤</mi><mo>,</mo><mi>+</mi><mo>,</mo><mn>0</mn><mo form="postfix" stretchy="false">)</mo></mrow>&lt;annotation encoding="application/x-tex"&gt;(\mathbb{Z}, +, 0)&lt;/annotation&gt;&lt;/semantics&gt;</math>
group. We could make a slightly more generalised version of <code class="sourceCode haskell"><span class="dt">Key</span></code> that is
the combination of any monus and
<math display="inline">&lt;semantics&gt;<mi>â„¤</mi>&lt;annotation encoding="application/x-tex"&gt;\mathbb{Z}&lt;/annotation&gt;&lt;/semantics&gt;</math>,
but since Iâ€™m only going to be using this type for simple sorting-like
algorithms I will leave that generalisation for another time.</p>
<p>The stable heap type is as follows:</p>
<div class="sourceCode" id="cb29"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb29-1"><a href="https://doisinkidney.com/rss.xml#cb29-1" tabindex="-1"/><span class="kw">data</span> <span class="dt">Stable</span> k f a</span>
<span id="cb29-2"><a href="https://doisinkidney.com/rss.xml#cb29-2" tabindex="-1"/>  <span class="ot">=</span> <span class="dt">Stable</span> {<span class="ot"> size ::</span> <span class="ot">{-# UNPACK #-}</span> <span class="op">!</span><span class="dt">Int</span></span>
<span id="cb29-3"><a href="https://doisinkidney.com/rss.xml#cb29-3" tabindex="-1"/>           ,<span class="ot"> heap ::</span> <span class="op">!</span>(<span class="dt">Heap</span> (<span class="dt">Key</span> k) f a) }</span></code></pre></div>
<p>We need to track the size of the heap so that we can supply the
right-hand operand with their offsets. Because weâ€™re storing
differences, we can add an offset to every entry in a heap in
<math display="inline">&lt;semantics&gt;<mrow><mi>ğ�’ª</mi><mo form="prefix" stretchy="false">(</mo><mn>1</mn><mo form="postfix" stretchy="false">)</mo></mrow>&lt;annotation encoding="application/x-tex"&gt;\mathcal{O}(1)&lt;/annotation&gt;&lt;/semantics&gt;</math>
time by simply adding to the root:</p>
<div class="sourceCode" id="cb30"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb30-1"><a href="https://doisinkidney.com/rss.xml#cb30-1" tabindex="-1"/><span class="ot">delayKey ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Heap</span> (<span class="dt">Key</span> k) f a <span class="ot">-&gt;</span> <span class="dt">Heap</span> (<span class="dt">Key</span> k) f a</span>
<span id="cb30-2"><a href="https://doisinkidney.com/rss.xml#cb30-2" tabindex="-1"/>delayKey _ hp<span class="op">@</span>(<span class="dt">Pure</span> _) <span class="ot">=</span> hp</span>
<span id="cb30-3"><a href="https://doisinkidney.com/rss.xml#cb30-3" tabindex="-1"/>delayKey n (<span class="dt">Root</span> (k <span class="op">:*</span> m) c x xs) <span class="ot">=</span> <span class="dt">Root</span> (k <span class="op">:*</span> (n <span class="op">+</span> m)) c x xs</span></code></pre></div>
<p>Finally, using this we can implement the <code class="sourceCode haskell"><span class="dt">Applicative</span></code>
instance and the rest of the interface:</p>
<div class="sourceCode" id="cb31"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb31-1"><a href="https://doisinkidney.com/rss.xml#cb31-1" tabindex="-1"/><span class="kw">instance</span> <span class="dt">Ord</span> k <span class="ot">=&gt;</span> <span class="dt">Applicative</span> (<span class="dt">Stable</span> k f) <span class="kw">where</span></span>
<span id="cb31-2"><a href="https://doisinkidney.com/rss.xml#cb31-2" tabindex="-1"/>  <span class="fu">pure</span> <span class="ot">=</span> <span class="dt">Stable</span> <span class="dv">0</span> <span class="op">.</span> <span class="fu">pure</span></span>
<span id="cb31-3"><a href="https://doisinkidney.com/rss.xml#cb31-3" tabindex="-1"/>  <span class="dt">Stable</span> n xs <span class="op">&lt;*&gt;</span> <span class="dt">Stable</span> m ys <span class="ot">=</span> <span class="dt">Stable</span> (n<span class="op">+</span>m) (xs <span class="op">&lt;*&gt;</span> delayKey n ys)</span>
<span id="cb31-4"><a href="https://doisinkidney.com/rss.xml#cb31-4" tabindex="-1"/></span>
<span id="cb31-5"><a href="https://doisinkidney.com/rss.xml#cb31-5" tabindex="-1"/><span class="ot">runStable ::</span> (<span class="dt">Applicative</span> f, <span class="dt">Ord</span> k) <span class="ot">=&gt;</span> <span class="dt">Stable</span> k f a <span class="ot">-&gt;</span> f a</span>
<span id="cb31-6"><a href="https://doisinkidney.com/rss.xml#cb31-6" tabindex="-1"/>runStable <span class="ot">=</span> runHeap <span class="op">.</span> heap</span>
<span id="cb31-7"><a href="https://doisinkidney.com/rss.xml#cb31-7" tabindex="-1"/></span>
<span id="cb31-8"><a href="https://doisinkidney.com/rss.xml#cb31-8" tabindex="-1"/><span class="ot">stable ::</span> <span class="dt">Ord</span> k <span class="ot">=&gt;</span> k <span class="ot">-&gt;</span> f a <span class="ot">-&gt;</span> <span class="dt">Stable</span> k f a</span>
<span id="cb31-9"><a href="https://doisinkidney.com/rss.xml#cb31-9" tabindex="-1"/>stable k fa <span class="ot">=</span> <span class="dt">Stable</span> <span class="dv">1</span> (phase (k <span class="op">:*</span> <span class="dv">0</span>) fa)</span></code></pre></div>
<p>This is a pure, optimally efficient implementation of <code class="sourceCode haskell"><span class="dt">Phases</span></code> ordered
by an arbitrary total-ordered key.</p>
<h1 id="local-computation-in-a-monadic-heap">Local Computation in a
Monadic Heap</h1>
<p>In <span class="citation">(<a href="https://doisinkidney.com/rss.xml#ref-kidney_algebras_2021">2021</a>)</span>,
I developed a monadic heap based on the free monad transformer.</p>
<div class="sourceCode" id="cb32"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb32-1"><a href="https://doisinkidney.com/rss.xml#cb32-1" tabindex="-1"/><span class="kw">newtype</span> <span class="dt">Search</span> k a <span class="ot">=</span> <span class="dt">Search</span> {<span class="ot"> runSearch ::</span> [<span class="dt">Either</span> a (k, <span class="dt">Search</span> k a)] }</span></code></pre></div>
<p>This type is equivalent to the <a href="https://hackage.haskell.org/package/free-5.2/docs/Control-Monad-Trans-Free.html#t:FreeT">free
monad transformer</a> over the list monad and <code class="sourceCode haskell">(,) k</code> functor (i.e.Â the writer
monad).</p>
<div class="sourceCode" id="cb33"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb33-1"><a href="https://doisinkidney.com/rss.xml#cb33-1" tabindex="-1"/><span class="dt">Search</span> k a â‰… <span class="dt">FreeT</span> ((,) k) [] a</span></code></pre></div>
<p>In the paper <span class="citation">(<a href="https://doisinkidney.com/rss.xml#ref-kidney_algebras_2021">2021</a>)</span> we extended the type to become a
full monad transformer, replacing lists with <code class="sourceCode haskell"><span class="dt">ListT</span></code>. This
let us order the effects according to the weight <code class="sourceCode haskell">k</code>; however, for this example we only
need the simplified type, which lets us order the values according to
<code class="sourceCode haskell">k</code>.</p>
<p>This <code class="sourceCode haskell"><span class="dt">Search</span></code> type
follows the structure of a pairing heap (although not as closely as the
version above). However, this type is interesting because
<em>semantically</em> it needs the weights to be stored as differences,
rather than absolute weights. As a free monad transformer, the <code class="sourceCode haskell"><span class="dt">Search</span></code> type
layers effects on top of each other; we can later interpret those layers
by collapsing them together using the monadic <code class="sourceCode haskell">join</code>. In the case of <code class="sourceCode haskell"><span class="dt">Search</span></code>, those
layers are drawn from the list monad and the <code class="sourceCode haskell">(,) k</code> functor (writer monad). That
means that if we have some heap representing the tree from above:</p>
<div class="sourceCode" id="cb34"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb34-1"><a href="https://doisinkidney.com/rss.xml#cb34-1" tabindex="-1"/><span class="dt">Search</span> [ <span class="dt">Right</span> (a, <span class="dt">Search</span> [ <span class="dt">Right</span> (b, <span class="dt">Search</span> [ <span class="dt">Right</span> (d, <span class="dt">Search</span> [<span class="dt">Left</span> x])</span>
<span id="cb34-2"><a href="https://doisinkidney.com/rss.xml#cb34-2" tabindex="-1"/>                                             , <span class="dt">Right</span> (e, <span class="dt">Search</span> [<span class="dt">Left</span> y])])</span>
<span id="cb34-3"><a href="https://doisinkidney.com/rss.xml#cb34-3" tabindex="-1"/>                          , <span class="dt">Right</span> (c, <span class="dt">Search</span> [<span class="dt">Left</span> z])])]</span></code></pre></div>
<p>When we collapse this computation down to the leaves, the weights we
will get are the following:</p>
<div class="sourceCode" id="cb35"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb35-1"><a href="https://doisinkidney.com/rss.xml#cb35-1" tabindex="-1"/>[(a <span class="op">&lt;&gt;</span> b <span class="op">&lt;&gt;</span> d, x), (a <span class="op">&lt;&gt;</span> b <span class="op">&lt;&gt;</span> e, y), (a <span class="op">&lt;&gt;</span> c, z)]</span></code></pre></div>
<p>So, if we want the weights to line up properly, we need to store the
differences.</p>
<div class="sourceCode" id="cb36"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb36-1"><a href="https://doisinkidney.com/rss.xml#cb36-1" tabindex="-1"/><span class="ot">mergeS ::</span> <span class="dt">Monus</span> k <span class="ot">=&gt;</span> [(k, <span class="dt">Search</span> k a)] <span class="ot">-&gt;</span> <span class="dt">Maybe</span> (k, <span class="dt">Search</span> k a)</span>
<span id="cb36-2"><a href="https://doisinkidney.com/rss.xml#cb36-2" tabindex="-1"/>mergeS [] <span class="ot">=</span> <span class="dt">Nothing</span></span>
<span id="cb36-3"><a href="https://doisinkidney.com/rss.xml#cb36-3" tabindex="-1"/>mergeS (x<span class="op">:</span>xs) <span class="ot">=</span> <span class="dt">Just</span> (mergeS' x xs)</span>
<span id="cb36-4"><a href="https://doisinkidney.com/rss.xml#cb36-4" tabindex="-1"/>  <span class="kw">where</span></span>
<span id="cb36-5"><a href="https://doisinkidney.com/rss.xml#cb36-5" tabindex="-1"/>    mergeS' x1 [] <span class="ot">=</span> x1</span>
<span id="cb36-6"><a href="https://doisinkidney.com/rss.xml#cb36-6" tabindex="-1"/>    mergeS' x1 [x2] <span class="ot">=</span> x1 <span class="op">&lt;+&gt;</span> x2</span>
<span id="cb36-7"><a href="https://doisinkidney.com/rss.xml#cb36-7" tabindex="-1"/>    mergeS' x1 (x2<span class="op">:</span>x3<span class="op">:</span>xs) <span class="ot">=</span> (x1 <span class="op">&lt;+&gt;</span> x2) <span class="op">&lt;+&gt;</span> mergeS' x3 xs</span>
<span id="cb36-8"><a href="https://doisinkidney.com/rss.xml#cb36-8" tabindex="-1"/></span>
<span id="cb36-9"><a href="https://doisinkidney.com/rss.xml#cb36-9" tabindex="-1"/>    (xw, <span class="dt">Search</span> xs) <span class="op">&lt;+&gt;</span> (yw, <span class="dt">Search</span> ys)</span>
<span id="cb36-10"><a href="https://doisinkidney.com/rss.xml#cb36-10" tabindex="-1"/>      <span class="op">|</span> xw <span class="op">&lt;=</span> yw  <span class="ot">=</span> (xw, <span class="dt">Search</span> (<span class="dt">Right</span> (yw âˆ¸ xw, <span class="dt">Search</span> ys) <span class="op">:</span> xs))</span>
<span id="cb36-11"><a href="https://doisinkidney.com/rss.xml#cb36-11" tabindex="-1"/>      <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> (yw, <span class="dt">Search</span> (<span class="dt">Right</span> (xw âˆ¸ yw, <span class="dt">Search</span> xs) <span class="op">:</span> ys))</span>
<span id="cb36-12"><a href="https://doisinkidney.com/rss.xml#cb36-12" tabindex="-1"/></span>
<span id="cb36-13"><a href="https://doisinkidney.com/rss.xml#cb36-13" tabindex="-1"/><span class="ot">popMins ::</span> <span class="dt">Monus</span> k <span class="ot">=&gt;</span> <span class="dt">Search</span> k a <span class="ot">-&gt;</span> ([a], <span class="dt">Maybe</span> (k, <span class="dt">Search</span> k a))</span>
<span id="cb36-14"><a href="https://doisinkidney.com/rss.xml#cb36-14" tabindex="-1"/>popMins <span class="ot">=</span> <span class="fu">fmap</span> mergeS <span class="op">.</span> partitionEithers <span class="op">.</span> runSearch</span></code></pre></div>
<h1 id="conclusion">Conclusion</h1>
<p>The technique of â€œdonâ€™t store the absolute value, store the
differenceâ€� seems to be generally quite useful; I think that monuses are
a handy algebra to keep in mind whenever that technique looks like it
might be needed. The <code class="sourceCode haskell"><span class="dt">Key</span></code> monus
above is closely related to the factorial numbers, and the trick I used
in <a href="https://doisinkidney.com/posts/2019-03-24-permutations-by-sorting.html">this</a>
post.</p>
<hr/>
<h2 class="unnumbered" id="references">References</h2>
<div class="references csl-bib-body hanging-indent" id="refs">
<div class="csl-entry" id="ref-amer_equationally_1984">
Amer, K. 1984. <span>â€œEquationally complete classes of commutative
monoids with monus.â€�</span> <em>algebra universalis</em> 18 (1)
(February): 129â€“131. doi:<a href="https://doi.org/10.1007/BF01182254">10.1007/BF01182254</a>.
</div>
<div class="csl-entry" id="ref-blondal_generalized_2025">
BlÃ¶ndal, Baldur. 2025a. <span>â€œGeneralized multi-phase
compiler/concurrency.â€�</span> <em>reddit</em>. <a href="https://www.reddit.com/r/haskell/comments/1m25fw8/generalized_multiphase_compilerconcurrency/">https://www.reddit.com/r/haskell/comments/1m25fw8/generalized_multiphase_compilerconcurrency/</a>.
</div>
<div class="csl-entry" id="ref-blondal_phases_2025">
â€”â€”â€”. 2025b. <span>â€œPhases using <span>Vault</span>.â€�</span>
<em>reddit</em>. <a href="https://www.reddit.com/r/haskell/comments/1msvwzd/phases_using_vault/">https://www.reddit.com/r/haskell/comments/1msvwzd/phases_using_vault/</a>.
</div>
<div class="csl-entry" id="ref-easterly_functions_2019">
Easterly, Noah. 2019. <span>â€œFunctions and newtype wrappers for
traversing <span>Trees</span>: Rampion/tree-traversals.â€�</span> <a href="https://github.com/rampion/tree-traversals">https://github.com/rampion/tree-traversals</a>.
</div>
<div class="csl-entry" id="ref-fredman_pairing_1986">
Fredman, Michael L., Robert Sedgewick, Daniel D. Sleator, and Robert E.
Tarjan. 1986. <span>â€œThe pairing heap: <span>A</span> new form of
self-adjusting heap.â€�</span> <em>Algorithmica</em> 1 (1-4) (January):
111â€“129. doi:<a href="https://doi.org/10.1007/BF01840439">10.1007/BF01840439</a>.
</div>
<div class="csl-entry" id="ref-gibbons_breadthfirst_2022">
Gibbons, Jeremy, Donnacha OisÃ­n Kidney, Tom Schrijvers, and Nicolas Wu.
2022. <span>â€œBreadth-<span>First Traversal</span>
viaÂ <span>Staging</span>.â€�</span> In <em>Mathematics of <span>Program
Construction</span></em>, ed by. Ekaterina Komendantskaya, 1â€“33. Cham:
Springer International Publishing. doi:<a href="https://doi.org/10.1007/978-3-031-16912-0_1">10.1007/978-3-031-16912-0_1</a>.
</div>
<div class="csl-entry" id="ref-gibbons_phases_2023">
â€”â€”â€”. 2023. <span>â€œPhases in <span>Software Architecture</span>.â€�</span>
In <em>Proceedings of the 1st <span>ACM SIGPLAN International
Workshop</span> on <span>Functional Software Architecture</span></em>,
29â€“33. <span>FUNARCH</span> 2023. New York, NY, USA: Association for
Computing Machinery. doi:<a href="https://doi.org/10.1145/3609025.3609479">10.1145/3609025.3609479</a>.
</div>
<div class="csl-entry" id="ref-kidney_algebras_2021">
Kidney, Donnacha OisÃ­n, and Nicolas Wu. 2021. <span>â€œAlgebras for
weighted search.â€�</span> <em>Proceedings of the ACM on Programming
Languages</em> 5 (ICFP) (August): 72:1â€“72:30. doi:<a href="https://doi.org/10.1145/3473577">10.1145/3473577</a>.
</div>
<div class="csl-entry" id="ref-kidney_formalising_2025">
â€”â€”â€”. 2025. <span>â€œFormalising <span>Graph Algorithms</span> with
<span>Coinduction</span>.â€�</span> <em>Proc. ACM Program. Lang.</em> 9
(POPL) (January): 56:1657â€“56:1686. doi:<a href="https://doi.org/10.1145/3704892">10.1145/3704892</a>.
</div>
<div class="csl-entry" id="ref-larkin_backtobasics_2013">
Larkin, Daniel H., Siddhartha Sen, and Robert E. Tarjan. 2013. <span>â€œA
<span class="nocase">Back-to-Basics Empirical Study</span> of
<span>Priority Queues</span>.â€�</span> In <em>2014
<span>Proceedings</span> of the <span>Meeting</span> on <span>Algorithm
Engineering</span> and <span>Experiments</span>
(<span>ALENEX</span>)</em>, 61â€“72. Proceedings. <span>Society for
Industrial and Applied Mathematics</span>. doi:<a href="https://doi.org/10.1137/1.9781611973198.7">10.1137/1.9781611973198.7</a>.
</div>
<div class="csl-entry" id="ref-visscher_phases_2025">
Visscher, Sjoerd. 2025. <span>â€œPhases with any <span>Ord</span> key
type.â€�</span> <a href="https://gist.github.com/sjoerdvisscher/bf282a050f0681e2f737908e254c4061">https://gist.github.com/sjoerdvisscher/bf282a050f0681e2f737908e254c4061</a>.
</div>
</div>
<section class="footnotes footnotes-end-of-document" id="footnotes">
<hr/>
<ol>
<li id="fn1"><p>Note that there are many related structures that all
fall under the umbrella notion of â€œmonusâ€�; the structure that I am
defining here is the same structure I worked with in <span class="citation">(<a href="https://doisinkidney.com/rss.xml#ref-kidney_algebras_2021">2021</a>)</span>
and <span class="citation">(<a href="https://doisinkidney.com/rss.xml#ref-kidney_formalising_2025">2025</a>)</span>.<a class="footnote-back" href="https://doisinkidney.com/rss.xml#fnref1">â†©ï¸�</a></p></li>
</ol>
</section></div>
    </summary>
    <updated>2026-03-03T00:00:00Z</updated>
    <published>2026-03-03T00:00:00Z</published>
    <author>
      <name>Donnacha Oisín Kidney</name>
    </author>
    <source>
      <id>https://doisinkidney.com</id>
      <link href="https://doisinkidney.com" rel="alternate" type="text/html"/>
      <link href="https://doisinkidney.com/rss.xml" rel="self" type="application/rss+xml"/>
      <subtitle>Mainly writing about programming</subtitle>
      <title>Donnacha Oisín Kidney's Blog</title>
      <updated>2026-04-28T00:00:00Z</updated>
    </source>
  </entry>

  <entry>
    <id>https://www.joachim-breitner.de/blog/819-Vibe-coding_a_debugger_for_a_DSL</id>
    <link href="https://www.joachim-breitner.de/blog/819-Vibe-coding_a_debugger_for_a_DSL" rel="alternate" type="text/html"/>
    <title>Vibe-coding a debugger for a DSL</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Earlier this week a colleague of mine, Emilio Jesús Gallego Arias, shared a demo of something he built as an experiment, and I felt the desire to share this and add a bit of reflection. (Not keen on watching a 5 min video? Read on below.)</p>


<h3 id="what-was-that">What was that?</h3>
<p>So what did you just see (or skipped watching)? You could see Emilio’s screen, running VSCode and editing a Lean file. He designed a small programming language that he embedded into Lean, including an evaluator. So far, so standard, but a few things stick out already:</p>
<ul>
<li>Using Lean’s very extensible syntax this embedding is rather elegant and pretty.</li>
<li>Furthermore, he can run this DSL code right there, in the source code, using commands like <a href="https://lean-lang.org/doc/reference/latest/find/?domain=Verso.Genre.Manual.section&amp;name=hash-eval"><code>#eval</code></a>. This is a bit like the interpreter found in Haskell or Python, but without needing a separate process, or like using a Jupyter notebook, but without the stateful cell management.</li>
</ul>
<p>This is already a nice demonstration of Lean’s abilities and strength, as we know them. But what blew my mind the first time was what happened next: He had a visual debugger that allowed him to <em>debug his DSL program</em>. It appeared on the right, in Lean’s “Info View”, where various Lean tools can hook into, show information and allow the user to interact.</p>
<p>But it did not stop there, and my mind was blown a second time: Emilio opened VSCode’s „Debugger“ pane on the left, and was able to properly use VSCode’s full-fledged debugger frontend for his own little embedded programming language! Complete with highlighting the executed line, with the ability to set breakpoints there, and showing the state of local variables in the debugger.</p>
<p>Having a good debugger is not to be taken for granted even for serious, practical programming languages. Having it for a small embedded language that you just built yourself? I wouldn’t have even considered that.</p>
<h3 id="did-it-take-long">Did it take long?</h3>
<p>If I were Emilio’s manager I would applaud the demo and then would have to ask how many weeks he spent on that. Coming up with the language, getting the syntax extension right, writing the evaluator and especially learning how the debugger integration into VSCode (using the <a href="https://microsoft.github.io/debug-adapter-protocol/">DAP protocol</a>) works, and then instrumenting his evaluator to speak that protocol – that is a sizeable project!</p>
<p>It turns out the answer isn’t measured in weeks: it took just one day of coding together with GPT-Codex 5.3. My mind was blown a third time.</p>
<h3 id="why-does-lean-make-a-difference">Why does Lean make a difference?</h3>
<p>I am sure this post is just one of many stories you have read in recent weeks about how new models like Claude Opus 4.6 and GPT-Codex 5.3 built impressive things in hours that would have taken days or more before. But have you seen something like this? Agentic coding is powerful, but limited by what the underlying platform exposes. I claim that Lean is a particularly well-suited platform to unleash the agents’ versatility.</p>
<p>Here we are using Lean as a programming language, not as a theorem prover (which brings other immediate benefits when using agents, e.g. the produced code can be verified rather than merely plausible, but that’s a story to be told elsewhere.)</p>
<p>But arguably because Lean is <em>also</em> a theorem prover, and because of the requirements that stem from that, its architecture is different from that of a conventional programming language implementation:</p>
<ul>
<li>As a theorem prover, it needs extensible syntax to allow formalizing mathematics in an ergonomic way, but it can also be used for embedding syntax.</li>
<li>As a theorem prover, it needs the ability to run “tactics” written by the user, hence the ability to evaluate the code right there in the editor.</li>
<li>As a theorem prover, it needs to give access to information such as tactic state, and such introspection abilities unlock many other features – such as a debugger for an embedded language.</li>
<li>As a theorem prover, it has to allow tools to present information like the tactic state, so it has the concept of <a href="https://lean-lang.org/examples/1900-1-1-widgets/">interactive “Widgets”</a>.</li>
</ul>
<p>So Lean’s design has always made such a feat <em>possible</em>. But it was no easy feat. The Lean API is large, and documentation never ceases to be improvable. In the past, it would take an expert (or someone willing to become one) to pull off that stunt. These days, coding assistants have no issue digesting, understanding and using the API, as Emilio’s demo shows.</p>
<p>The combination of Lean’s extensibility and the ability of coding agents to make use of that is a game changer to how we can develop software, with rich, deep, flexible and bespoke ways to interact with our code, created on demand.</p>
<h3 id="where-does-that-lead-us">Where does that lead us?</h3>
<p>Emilio actually shared more such demos (<a href="https://github.com/ejgallego/imp-lab">Github repository</a>). A visual explorer for the compiler output (<a href="https://www.joachim-breitner.de/various/lean-compiler-explorer.png">have a look at the screenshot</a>. A browser-devtool-like inspection tool for Lean’s “InfoTree”. Any of these provide a significant productivity boost. Any of these would have been a sizeable project half a year ago. Now it’s just a few hours of chatting with the agent.</p>
<p>So allow me to try and extrapolate into a future where coding agents have continued to advance at the current pace, and are used ubiquitously. Is there then even a point in polishing these tools, shipping them to our users, documenting them? Why build a compiler explorer for our users, if our users can just ask their agent to build one for them, right then when they need it, tailored to precisely the use case they have, with no unnecessary or confusing feature. The code would be single use, as the next time the user needs something like that the agent can just re-create it, maybe slightly different because every use case is different.</p>
<p>If that comes to pass then Lean may no longer get praise for its nice out-of-the-box user experience, but instead because it is such a powerful framework for ad-hoc UX improvements.</p>
<p>And Emilio wouldn’t post demos about his debugger. He’d just use it.</p></div>
    </summary>
    <updated>2026-02-25T10:53:30Z</updated>
    <published>2026-02-25T10:53:30Z</published>
    <author>
      <name>Joachim Breitner</name>
      <email>mail@joachim-breitner.de</email>
    </author>
    <source>
      <id>https://www.joachim-breitner.de/blog</id>
      <logo>https://joachim-breitner.de/avatars/avatar_128.png</logo>
      <link href="https://www.joachim-breitner.de/blog" rel="alternate" type="text/html"/>
      <link href="https://www.joachim-breitner.de/blog_feed.rss" rel="self" type="application/rss+xml"/>
      <subtitle>Joachim Breitners Denkblogade</subtitle>
      <title>nomeataâ€™s mind shares</title>
      <updated>2026-05-16T01:02:11Z</updated>
    </source>
  </entry>

  <entry>
    <id>https://tweag.io/blog/2026-02-19-nickel-since-1-0/</id>
    <link href="https://tweag.io/blog/2026-02-19-nickel-since-1-0/" rel="alternate" type="text/html"/>
    <title>Nickel since 1.0</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>We released Nickel 1.0 in May 2023. Since then, we’ve been working so hard
on new features, bug fixes, and performance improvements that we haven’t had
the opportunity to write about them as much as we would’ve liked. This post
rounds up some of the big changes that we’ve landed over the past few years.</p>
<h2 id="new-language-features"><a class="anchor before" href="https://www.tweag.io/rss.xml#new-language-features"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>New language features</h2>
<h3 id="algebraic-data-types"><a class="anchor before" href="https://www.tweag.io/rss.xml#algebraic-data-types"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>Algebraic data types</h3>
<p>The biggest new language feature is one that we have actually <a href="https://www.tweag.io/blog/2024-09-05-algebraic-data-types-nickel/">written
about</a>
before: algebraic data types — or <em>enum variants</em> in Nickel terminology —
first landed in <a href="https://github.com/tweag/nickel/releases/tag/1.5.0">Nickel 1.5</a>. Nickel has supported plain enums
for a long time: <code class="language-text">[| 'Carnitas, 'Fish |]</code> is the type of something that
can take two possible values: <code class="language-text">'Carnitas</code> or <code class="language-text">'Fish</code>. Enum variants extend
these by allowing the enum types to specify payloads, like
<code class="language-text">[| 'Carnitas { pineapple : Number }, 'Fish { avocado : Number, cheese : Number } |]</code>.
Types like this are supported by many modern programming languages, as
they are useful for encoding important invariants like the fact that carnitas
tacos can be topped with pineapple but not avocado. For more on the design
and motivation for algebraic data types in Nickel, see
<a href="https://www.tweag.io/blog/2024-09-05-algebraic-data-types-nickel/">our other post</a>.</p>
<h3 id="pattern-matching"><a class="anchor before" href="https://www.tweag.io/rss.xml#pattern-matching"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>Pattern matching</h3>
<p>Nickel has had a <code class="language-text">match</code> statement for a while, but it used to be quite limited.
<a href="https://github.com/tweag/nickel/releases/tag/1.5.0">Nickel 1.5</a> and
<a href="https://github.com/tweag/nickel/releases/tag/1.7.0">Nickel 1.7</a> extended it significantly: not only can you now match
the enum variants we mentioned above, you can also match arrays, records, and constants.
You can also match the “or” of two patterns, and you can guard matches with predicates.</p>
<div class="gatsby-highlight"><pre class="language-nickel"><code class="language-nickel"><span class="token keyword">match</span><span class="token operator"> </span><span class="token operator">{</span>
<span class="token operator"> </span><span class="token operator"> </span><span class="token operator">'</span><span class="token operator">C</span><span class="token operator">a</span><span class="token operator">r</span><span class="token operator">n</span><span class="token operator">i</span><span class="token operator">t</span><span class="token operator">a</span><span class="token operator">s</span><span class="token operator"> </span><span class="token operator">{</span><span class="token operator"> </span><span class="token operator">p</span><span class="token operator">i</span><span class="token operator">n</span><span class="token operator">e</span><span class="token operator">a</span><span class="token operator">p</span><span class="token operator">p</span><span class="token operator">l</span><span class="token operator">e</span><span class="token operator"> </span><span class="token operator">}</span><span class="token operator"> </span><span class="token keyword">if</span><span class="token operator"> </span><span class="token operator">p</span><span class="token operator">i</span><span class="token operator">n</span><span class="token operator">e</span><span class="token operator">a</span><span class="token operator">p</span><span class="token operator">p</span><span class="token operator">l</span><span class="token operator">e</span><span class="token operator"> </span><span class="token operator">&gt;</span><span class="token operator">=</span><span class="token operator"> </span><span class="token number">5</span><span class="token operator"> </span><span class="token operator">=</span><span class="token operator">&gt;</span><span class="token operator"> </span><span class="token operator">s</span><span class="token operator">t</span><span class="token operator">d</span><span class="token operator">.</span><span class="token operator">f</span><span class="token operator">a</span><span class="token operator">i</span><span class="token operator">l</span><span class="token operator">_</span><span class="token operator">w</span><span class="token operator">i</span><span class="token operator">t</span><span class="token operator">h</span><span class="token operator"> </span><span class="token string">"too much pineapple"</span><span class="token operator">,</span>

<span class="token operator"> </span><span class="token operator"> </span><span class="token operator">[</span><span class="token operator"> </span><span class="token operator">'</span><span class="token operator">C</span><span class="token operator">a</span><span class="token operator">r</span><span class="token operator">n</span><span class="token operator">i</span><span class="token operator">t</span><span class="token operator">a</span><span class="token operator">s</span><span class="token operator"> </span><span class="token operator">{</span><span class="token operator"> </span><span class="token operator">.</span><span class="token operator">.</span><span class="token operator"> </span><span class="token operator">}</span><span class="token operator">,</span><span class="token operator"> </span><span class="token operator">'</span><span class="token operator">F</span><span class="token operator">i</span><span class="token operator">s</span><span class="token operator">h</span><span class="token operator"> </span><span class="token operator">{</span><span class="token operator"> </span><span class="token operator">.</span><span class="token operator">.</span><span class="token operator"> </span><span class="token operator">}</span><span class="token operator"> </span><span class="token operator">]</span>
<span class="token operator"> </span><span class="token operator"> </span><span class="token operator">o</span><span class="token operator">r</span><span class="token operator"> </span><span class="token operator">[</span><span class="token operator"> </span><span class="token operator">'</span><span class="token operator">F</span><span class="token operator">i</span><span class="token operator">s</span><span class="token operator">h</span><span class="token operator"> </span><span class="token operator">{</span><span class="token operator"> </span><span class="token operator">.</span><span class="token operator">.</span><span class="token operator"> </span><span class="token operator">}</span><span class="token operator">,</span><span class="token operator"> </span><span class="token operator">'</span><span class="token operator">C</span><span class="token operator">a</span><span class="token operator">r</span><span class="token operator">n</span><span class="token operator">i</span><span class="token operator">t</span><span class="token operator">a</span><span class="token operator">s</span><span class="token operator"> </span><span class="token operator">{</span><span class="token operator"> </span><span class="token operator">.</span><span class="token operator">.</span><span class="token operator"> </span><span class="token operator">}</span><span class="token operator"> </span><span class="token operator">]</span><span class="token operator"> </span><span class="token operator">=</span><span class="token operator">&gt;</span><span class="token operator"> </span><span class="token string">"one of each"</span><span class="token operator">,</span>
<span class="token operator">}</span></code></pre></div>
<p>Basically, if you’ve used pattern matching in another language then
Nickel’s match blocks probably have the features you’re used to.
And they’re adapted to Nickel’s gradual typing: the example match block
above will work in dynamically typed code, but in a statically typed block
it will fail to typecheck, because there’s no static type that can be
either an enum or an array.</p>
<h3 id="field-punning"><a class="anchor before" href="https://www.tweag.io/rss.xml#field-punning"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>Field punning</h3>
<p>Records in Nickel are recursive by default, meaning that in the record</p>
<div class="gatsby-highlight"><pre class="language-nickel"><code class="language-nickel"><span class="token operator">{</span>
<span class="token operator"> </span><span class="token operator"> </span><span class="token property">tacos</span><span class="token operator"> </span><span class="token operator">=</span><span class="token operator"> </span><span class="token operator">[</span><span class="token operator">'</span><span class="token operator">C</span><span class="token operator">a</span><span class="token operator">r</span><span class="token operator">n</span><span class="token operator">i</span><span class="token operator">t</span><span class="token operator">a</span><span class="token operator">s</span><span class="token operator"> </span><span class="token operator">{</span><span class="token operator"> </span><span class="token property">pineapple</span><span class="token operator"> </span><span class="token operator">=</span><span class="token operator"> </span><span class="token number">2</span><span class="token operator"> </span><span class="token operator">}</span><span class="token operator">]</span><span class="token operator">,</span>
<span class="token operator"> </span><span class="token operator"> </span><span class="token property">price</span><span class="token operator"> </span><span class="token operator">=</span><span class="token operator"> </span><span class="token operator">p</span><span class="token operator">r</span><span class="token operator">i</span><span class="token operator">c</span><span class="token operator">e</span><span class="token operator">_</span><span class="token operator">p</span><span class="token operator">e</span><span class="token operator">r</span><span class="token operator">_</span><span class="token operator">t</span><span class="token operator">a</span><span class="token operator">c</span><span class="token operator">o</span><span class="token operator"> </span><span class="token operator">*</span><span class="token operator"> </span><span class="token operator">s</span><span class="token operator">t</span><span class="token operator">d</span><span class="token operator">.</span><span class="token operator">a</span><span class="token operator">r</span><span class="token operator">r</span><span class="token operator">a</span><span class="token operator">y</span><span class="token operator">.</span><span class="token operator">l</span><span class="token operator">e</span><span class="token operator">n</span><span class="token operator">g</span><span class="token operator">t</span><span class="token operator">h</span><span class="token operator"> </span><span class="token operator">t</span><span class="token operator">a</span><span class="token operator">c</span><span class="token operator">o</span><span class="token operator">s</span><span class="token operator">,</span>
<span class="token operator"> </span><span class="token operator"> </span><span class="token property">price_per_taco</span><span class="token operator"> </span><span class="token operator">=</span><span class="token operator"> </span><span class="token number">5</span><span class="token operator">,</span>
<span class="token operator">}</span></code></pre></div>
<p>the name <code class="language-text">price_per_taco</code> in the definition of <code class="language-text">price</code> refers to the field
<code class="language-text">price_per_taco</code> defined within the record. This is behavior is <em>usually</em> very handy,
but it can be annoying when you’re trying to define a field whose name shadows
something in an outer scope. For example, suppose you want to move the definition
of <code class="language-text">tacos</code> outside the record:</p>
<div class="gatsby-highlight"><pre class="language-nickel"><code class="language-nickel"><span class="token keyword">let</span><span class="token operator"> </span><span class="token property">tacos</span><span class="token operator"> </span><span class="token operator">=</span><span class="token operator"> </span><span class="token operator">[</span><span class="token operator">'</span><span class="token operator">C</span><span class="token operator">a</span><span class="token operator">r</span><span class="token operator">n</span><span class="token operator">i</span><span class="token operator">t</span><span class="token operator">a</span><span class="token operator">s</span><span class="token operator"> </span><span class="token operator">{</span><span class="token operator"> </span><span class="token property">pineapple</span><span class="token operator"> </span><span class="token operator">=</span><span class="token operator"> </span><span class="token number">2</span><span class="token operator"> </span><span class="token operator">}</span><span class="token operator">]</span><span class="token operator"> </span><span class="token keyword">in</span>
<span class="token operator">{</span>
<span class="token operator"> </span><span class="token operator"> </span><span class="token property">tacos</span><span class="token operator"> </span><span class="token operator">=</span><span class="token operator"> </span><span class="token operator">t</span><span class="token operator">a</span><span class="token operator">c</span><span class="token operator">o</span><span class="token operator">s</span><span class="token operator">,</span>
<span class="token operator"> </span><span class="token operator"> </span><span class="token property">price</span><span class="token operator"> </span><span class="token operator">=</span><span class="token operator"> </span><span class="token operator">p</span><span class="token operator">r</span><span class="token operator">i</span><span class="token operator">c</span><span class="token operator">e</span><span class="token operator">_</span><span class="token operator">p</span><span class="token operator">e</span><span class="token operator">r</span><span class="token operator">_</span><span class="token operator">t</span><span class="token operator">a</span><span class="token operator">c</span><span class="token operator">o</span><span class="token operator"> </span><span class="token operator">*</span><span class="token operator"> </span><span class="token operator">s</span><span class="token operator">t</span><span class="token operator">d</span><span class="token operator">.</span><span class="token operator">a</span><span class="token operator">r</span><span class="token operator">r</span><span class="token operator">a</span><span class="token operator">y</span><span class="token operator">.</span><span class="token operator">l</span><span class="token operator">e</span><span class="token operator">n</span><span class="token operator">g</span><span class="token operator">t</span><span class="token operator">h</span><span class="token operator"> </span><span class="token operator">t</span><span class="token operator">a</span><span class="token operator">c</span><span class="token operator">o</span><span class="token operator">s</span><span class="token operator">,</span>
<span class="token operator"> </span><span class="token operator"> </span><span class="token property">price_per_taco</span><span class="token operator"> </span><span class="token operator">=</span><span class="token operator"> </span><span class="token number">5</span><span class="token operator">,</span>
<span class="token operator">}</span></code></pre></div>
<p>This probably doesn’t do what you want: it recurses infinitely, because
in the <code class="language-text">tacos = tacos</code> line, the <code class="language-text">tacos</code> on the right side of the equals
sign refers to the name <code class="language-text">tacos</code> that’s being defined on the left hand side
(and not, as you might expect, the <code class="language-text">tacos</code> in <code class="language-text">let tacos = ... in</code>).
There are workarounds (like calling the outer variable <code class="language-text">tacos_</code> instead),
but they’re annoying. <a href="https://github.com/tweag/nickel/releases/tag/1.12.0">Nickel 1.12</a> added the <code class="language-text">include</code> keyword,
where <code class="language-text">{ include tacos }</code> means <code class="language-text">{ tacos = &lt;tacos-from-the-outer-scope&gt; }</code>.</p>
<h3 id="let-blocks"><a class="anchor before" href="https://www.tweag.io/rss.xml#let-blocks"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>Let blocks</h3>
<p>Nickel binds local variables using a <code class="language-text">let</code> statement, as in <code class="language-text">let x = 1 in x + x</code>. Before <a href="https://github.com/tweag/nickel/releases/tag/1.9.0">Nickel 1.9</a> you could only bind one variable at a time — as
in <code class="language-text">let x = 1 in let y = 2 in x + y</code> — but now you can bind multiple variables
in a single block, as in <code class="language-text">let x = 1, y = 2 in x + y</code>. In most situations this is
just a small syntactic convenience,<sup id="fnref-1"><a class="footnote-ref" href="https://www.tweag.io/rss.xml#fn-1">1</a></sup> but with <em>recursive</em> let
blocks you actually gain some expressive power. For example, they allow you to write
mutually recursive functions without putting them in a record (which used to be the
only way to create a recursive environment in Nickel):</p>
<div class="gatsby-highlight"><pre class="language-nickel"><code class="language-nickel"><span class="token keyword">let</span><span class="token operator"> </span><span class="token keyword">rec</span>
<span class="token operator"> </span><span class="token operator"> </span><span class="token property">is_even</span><span class="token operator"> </span><span class="token operator">=</span><span class="token operator"> </span><span class="token keyword">fun</span><span class="token operator"> </span><span class="token operator">x</span><span class="token operator"> </span><span class="token operator">=</span><span class="token operator">&gt;</span><span class="token operator"> </span><span class="token keyword">if</span><span class="token operator"> </span><span class="token property">x</span><span class="token operator"> </span><span class="token operator">=</span><span class="token operator">=</span><span class="token operator"> </span><span class="token number">0</span><span class="token operator"> </span><span class="token keyword">then</span><span class="token operator"> </span><span class="token constant">true</span><span class="token operator"> </span><span class="token keyword">else</span><span class="token operator"> </span><span class="token operator">i</span><span class="token operator">s</span><span class="token operator">_</span><span class="token operator">o</span><span class="token operator">d</span><span class="token operator">d</span><span class="token operator"> </span><span class="token operator">(</span><span class="token operator">x</span><span class="token operator"> </span><span class="token operator">-</span><span class="token operator"> </span><span class="token number">1</span><span class="token operator">)</span><span class="token operator">,</span>
<span class="token operator"> </span><span class="token operator"> </span><span class="token property">is_odd</span><span class="token operator"> </span><span class="token operator">=</span><span class="token operator"> </span><span class="token keyword">fun</span><span class="token operator"> </span><span class="token operator">x</span><span class="token operator"> </span><span class="token operator">=</span><span class="token operator">&gt;</span><span class="token operator"> </span><span class="token keyword">if</span><span class="token operator"> </span><span class="token property">x</span><span class="token operator"> </span><span class="token operator">=</span><span class="token operator">=</span><span class="token operator"> </span><span class="token number">0</span><span class="token operator"> </span><span class="token keyword">then</span><span class="token operator"> </span><span class="token constant">false</span><span class="token operator"> </span><span class="token keyword">else</span><span class="token operator"> </span><span class="token operator">i</span><span class="token operator">s</span><span class="token operator">_</span><span class="token operator">e</span><span class="token operator">v</span><span class="token operator">e</span><span class="token operator">n</span><span class="token operator"> </span><span class="token operator">(</span><span class="token operator">x</span><span class="token operator"> </span><span class="token operator">-</span><span class="token operator"> </span><span class="token number">1</span><span class="token operator">)</span><span class="token operator">,</span>
<span class="token operator"/><span class="token keyword">in</span>
<span class="token operator"> </span><span class="token operator"> </span><span class="token operator">i</span><span class="token operator">s</span><span class="token operator">_</span><span class="token operator">e</span><span class="token operator">v</span><span class="token operator">e</span><span class="token operator">n</span><span class="token operator"> </span><span class="token number">42</span></code></pre></div>
<h3 id="better-contract-constructors"><a class="anchor before" href="https://www.tweag.io/rss.xml#better-contract-constructors"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>Better contract constructors</h3>
<p>Custom contracts were reworked in <a href="https://github.com/tweag/nickel/releases/tag/1.8.0">Nickel 1.8</a>, allowing for better control of a
contract’s eagerness, more precise error locations, and better composability.
Nickel’s standard library now offers three contract constructors. The
simplest is <code class="language-text">std.contract.from_predicate</code>, which turns a predicate (of type <code class="language-text">Dyn -&gt; Bool</code>)
into a contract. <code class="language-text">std.contract.from_validator</code> is slightly more complicated but offers
better control over error messages, while <code class="language-text">std.contract.custom</code> offers the most control.</p>
<p>A full description of the contract changes is out of scope for this blog post — there’s
a whole <a href="https://nickel-lang.org/user-manual/contracts/#user-defined-contracts">section</a> of the manual devoted to it. But the key point is that
contracts in Nickel are partly eager and partly lazy. For example, the contract in</p>
<div class="gatsby-highlight"><pre class="language-nickel"><code class="language-nickel"><span class="token keyword">let</span><span class="token operator"> </span><span class="token property">Taco</span><span class="token operator"> </span><span class="token operator">=</span><span class="token operator"> </span><span class="token operator">[</span><span class="token operator">|</span><span class="token operator"> </span><span class="token operator">'</span><span class="token operator">C</span><span class="token operator">a</span><span class="token operator">r</span><span class="token operator">n</span><span class="token operator">i</span><span class="token operator">t</span><span class="token operator">a</span><span class="token operator">s</span><span class="token operator">,</span><span class="token operator"> </span><span class="token operator">'</span><span class="token operator">F</span><span class="token operator">i</span><span class="token operator">s</span><span class="token operator">h</span><span class="token operator"> </span><span class="token operator">|</span><span class="token operator">]</span><span class="token operator"> </span><span class="token keyword">in</span>
<span class="token operator"/><span class="token keyword">let</span><span class="token operator"> </span><span class="token operator">t</span><span class="token operator">a</span><span class="token operator">c</span><span class="token operator">o</span><span class="token operator">s</span><span class="token operator"> </span><span class="token operator">|</span><span class="token operator"> </span><span class="token class-name">Array</span><span class="token operator"> </span><span class="token property">Taco</span><span class="token operator"> </span><span class="token operator">=</span><span class="token operator"> </span><span class="token operator">[</span><span class="token operator">'</span><span class="token operator">C</span><span class="token operator">a</span><span class="token operator">r</span><span class="token operator">n</span><span class="token operator">i</span><span class="token operator">t</span><span class="token operator">a</span><span class="token operator">s</span><span class="token operator">,</span><span class="token operator"> </span><span class="token operator">'</span><span class="token operator">C</span><span class="token operator">r</span><span class="token operator">u</span><span class="token operator">n</span><span class="token operator">c</span><span class="token operator">h</span><span class="token operator">y</span><span class="token operator">T</span><span class="token operator">a</span><span class="token operator">c</span><span class="token operator">o</span><span class="token operator">S</span><span class="token operator">u</span><span class="token operator">p</span><span class="token operator">r</span><span class="token operator">e</span><span class="token operator">m</span><span class="token operator">e</span><span class="token operator">]</span><span class="token operator"> </span><span class="token keyword">in</span>
<span class="token operator">&lt;</span><span class="token operator">s</span><span class="token operator">o</span><span class="token operator">m</span><span class="token operator">e</span><span class="token operator">t</span><span class="token operator">h</span><span class="token operator">i</span><span class="token operator">n</span><span class="token operator">g</span><span class="token operator">&gt;</span></code></pre></div>
<p>gets applied in two stages. When <code class="language-text">tacos</code> first gets evaluated, the contract checks that
<code class="language-text">tacos</code> is an array. But rather than validating the array elements immediately,
it propagates the element contracts inside the array and leaves them
unevaluated; essentially, <code class="language-text">tacos</code> gets evaluated to
<code class="language-text">['Carnitas | Taco, 'CrunchyTacoSupreme | Taco]</code>. Only when the <em>elements</em> of the array get
evaluated are their contracts checked. In particular, if the array elements are
never actually evaluated (for example, if <code class="language-text">&lt;something&gt;</code> is <code class="language-text">std.array.length tacos</code>, which doesn’t evaluate the individual elements) then we’ll never find
out that <code class="language-text">'CrunchyTacoSupreme</code> isn’t actually a <code class="language-text">Taco</code>.</p>
<p>The lazy/eager distinction has been part of Nickel’s built-in record and array
contracts since the beginning, but never fully exploitable by custom contracts.
The new <code class="language-text">std.contract.custom</code> constructor creates a contract with explicit lazy
and eager parts, and the <code class="language-text">std.contract.check</code> function allows for speculatively
checking the eager part of a contract without bailing out if it fails. Together,
these ingredients allowed us to create useful <a href="https://www.tweag.io/blog/2022-04-28-union-intersection-contracts/">union contracts</a> (<code class="language-text">std.contract.any_of</code>)
and improve the error reporting of the eager contracts in <a href="https://github.com/nickel-lang/json-schema-to-nickel/">json-schema-to-nickel</a>,
our tool for converting JSON schemas to Nickel contracts.</p>
<h2 id="performance-improvements"><a class="anchor before" href="https://www.tweag.io/rss.xml#performance-improvements"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>Performance improvements</h2>
<p>For Nickel 1.0, we were focused on getting the basic language right. Since then
(and especially over the past year), we’ve been working on getting the interpreter
to run faster. While the performance improvements you observe will depend heavily
on your use case, we’ve seen large user-provided Nickel configurations that
evaluate 10x faster now than they were two years ago (and 3x faster than six months ago).
The most recent performance improvements are part of our progress towards
a <a href="https://github.com/tweag/nickel/blob/c483fe2811fa6b271d96cf87b8b3d3872fe03d8f/rfcs/007-bytecode-interpreter.md">bytecode interpreter</a>. We’ve been landing these improvements gradually over the
past year or so, but most of that preparation only had a performance impact
starting in <a href="https://github.com/tweag/nickel/releases/tag/1.15.1">Nickel 1.15</a>.</p>
<h3 id="standard-library-improvements"><a class="anchor before" href="https://www.tweag.io/rss.xml#standard-library-improvements"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>Standard library improvements</h3>
<p>Nickel’s <a href="https://nickel-lang.org/stdlib/std/">standard library</a> has roughly doubled in size since Nickel 1.0, offering many useful
utility functions (like <code class="language-text">std.record.get_or</code> or <code class="language-text">std.string.find_all</code>) and contract combinators
(like <code class="language-text">std.contract.Sequence</code> or <code class="language-text">std.contract.any_of</code>). The standard library now also
contains a useful set of trigonometric and other numeric functions,
<a href="https://github.com/nickel-lang/nickel/issues/2005">contributed</a> by a community member who was
using Nickel to configure a robot.</p>
<h2 id="tooling-and-distribution-improvements"><a class="anchor before" href="https://www.tweag.io/rss.xml#tooling-and-distribution-improvements"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>Tooling and distribution improvements</h2>
<p>Nickel has seen many improvements that are not directly tied to the Nickel
language itself.</p>
<h3 id="language-server-improvements"><a class="anchor before" href="https://www.tweag.io/rss.xml#language-server-improvements"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>Language server improvements</h3>
<p>Nickel’s language server (NLS) has seen many improvements, especially
in <a href="https://github.com/tweag/nickel/releases/tag/1.2.0">Nickel 1.2</a> and <a href="https://github.com/tweag/nickel/releases/tag/1.3.0">1.3</a>. It now supports finding references
and definitions, listing symbols, and various other table-stakes language
server features. Completions have also been improved substantially since
version 1.0, and can make intelligent use of type- and contract-related
information. For example, in</p>
<div class="gatsby-highlight"><pre class="language-nickel"><code class="language-nickel"><span class="token operator">'</span><span class="token operator">C</span><span class="token operator">a</span><span class="token operator">r</span><span class="token operator">n</span><span class="token operator">i</span><span class="token operator">t</span><span class="token operator">a</span><span class="token operator">s</span><span class="token operator"> </span><span class="token operator">{</span><span class="token operator"> </span><span class="token operator">‸</span><span class="token operator"> </span><span class="token operator">}</span><span class="token operator"> </span><span class="token operator">|</span><span class="token operator"> </span><span class="token operator">[</span><span class="token operator">|</span><span class="token operator"> </span><span class="token operator">'</span><span class="token operator">C</span><span class="token operator">a</span><span class="token operator">r</span><span class="token operator">n</span><span class="token operator">i</span><span class="token operator">t</span><span class="token operator">a</span><span class="token operator">s</span><span class="token operator"> </span><span class="token operator">{</span><span class="token operator"> </span><span class="token operator">p</span><span class="token operator">i</span><span class="token operator">n</span><span class="token operator">e</span><span class="token operator">a</span><span class="token operator">p</span><span class="token operator">p</span><span class="token operator">l</span><span class="token operator">e</span><span class="token operator"> </span><span class="token operator">:</span><span class="token operator"> </span><span class="token class-name">Number</span><span class="token operator"> </span><span class="token operator">}</span><span class="token operator">,</span><span class="token operator"> </span><span class="token operator">'</span><span class="token operator">F</span><span class="token operator">i</span><span class="token operator">s</span><span class="token operator">h</span><span class="token operator"> </span><span class="token operator">{</span><span class="token operator"> </span><span class="token operator">a</span><span class="token operator">v</span><span class="token operator">o</span><span class="token operator">c</span><span class="token operator">a</span><span class="token operator">d</span><span class="token operator">o</span><span class="token operator"> </span><span class="token operator">:</span><span class="token operator"> </span><span class="token class-name">Number</span><span class="token operator">,</span><span class="token operator"> </span><span class="token operator">c</span><span class="token operator">h</span><span class="token operator">e</span><span class="token operator">e</span><span class="token operator">s</span><span class="token operator">e</span><span class="token operator"> </span><span class="token operator">:</span><span class="token operator"> </span><span class="token class-name">Number</span><span class="token operator"> </span><span class="token operator">}</span><span class="token operator"> </span><span class="token operator">|</span><span class="token operator">]</span>
<span class="token operator"/><span class="token comment">#           └── cursor is here</span></code></pre></div>
<p>NLS knows to offer “pineapple” as a completion, but not “avocado”.</p>
<p>NLS has also gained the ability to offer diagnostics for <em>evaluation</em>
errors. This is very useful in Nickel because contract errors are detected
during evaluation instead of during typechecking. In-editor detection of
contract violations is part of the vision
articulated in a <a href="https://www.tweag.io/blog/2024-05-16-nickel-programmable-lsp/">previous blog post</a>, where configuration
errors are <a href="https://en.wikipedia.org/wiki/Shift-left_testing">left-shifted</a>
(because you get them as you type) and infinitely customizable (because
contracts are arbitrary code). Since the previous post was written, the
diagnostics have been further improved thanks to the contract
improvements mentioned above: the problematic field now gets
highlighted directly.</p>
<p><span class="gatsby-resp-image-wrapper" style="display: block; margin-left: auto; margin-right: auto;">
      <a class="gatsby-resp-image-link" href="https://www.tweag.io/static/de296f77c52d37c3a7c3d77ab91aee42/949b7/kubernetes.png" rel="noopener" style="display: block;" target="_blank">
    <span class="gatsby-resp-image-background-image" style="display: block;"/>
  <img alt="png" class="gatsby-resp-image-image" src="https://www.tweag.io/static/de296f77c52d37c3a7c3d77ab91aee42/fcda8/kubernetes.png" style="width: 100%; height: 100%; margin: 0; vertical-align: middle;" title="png"/>
  </a>
    </span></p>
<h3 id="unit-tests"><a class="anchor before" href="https://www.tweag.io/rss.xml#unit-tests"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>Unit tests</h3>
<p>Since <a href="https://github.com/tweag/nickel/releases/tag/1.9.0">Nickel 1.9</a>, there is a <code class="language-text">nickel test</code> command that executes
unit tests contained in documentation comments.</p>
<div class="gatsby-highlight"><pre class="language-nickel"><code class="language-nickel"><span class="token operator">{</span>
<span class="token operator"> </span><span class="token operator"> </span><span class="token operator">m</span><span class="token operator">o</span><span class="token operator">r</span><span class="token operator">e</span><span class="token operator">_</span><span class="token operator">a</span><span class="token operator">v</span><span class="token operator">o</span><span class="token operator">c</span><span class="token operator">a</span><span class="token operator">d</span><span class="token operator">o</span>
<span class="token operator"> </span><span class="token operator"> </span><span class="token operator"> </span><span class="token operator"> </span><span class="token operator">|</span><span class="token operator"> </span><span class="token keyword">doc</span><span class="token operator"> </span><span class="token string">m%"
      Double the avocado!

      Here's an example that is automatically treated as a unit test:
      ```nickel
        more_avocado ('Fish { avocado = 1 })
        # =&gt; 'Fish { avocado = 2 }
      ```
      "%</span>
<span class="token operator"> </span><span class="token operator"> </span><span class="token operator"> </span><span class="token operator"> </span><span class="token operator">=</span><span class="token operator"> </span><span class="token keyword">fun</span><span class="token operator"> </span><span class="token operator">(</span><span class="token operator">'</span><span class="token operator">F</span><span class="token operator">i</span><span class="token operator">s</span><span class="token operator">h</span><span class="token operator"> </span><span class="token operator">{</span><span class="token operator"> </span><span class="token property">avocado</span><span class="token operator"> </span><span class="token operator">=</span><span class="token operator"> </span><span class="token operator">a</span><span class="token operator"> </span><span class="token operator">}</span><span class="token operator">)</span><span class="token operator"> </span><span class="token operator">=</span><span class="token operator">&gt;</span><span class="token operator"> </span><span class="token operator">'</span><span class="token operator">F</span><span class="token operator">i</span><span class="token operator">s</span><span class="token operator">h</span><span class="token operator"> </span><span class="token operator">{</span><span class="token operator"> </span><span class="token property">avocado</span><span class="token operator"> </span><span class="token operator">=</span><span class="token operator"> </span><span class="token number">3</span><span class="token operator"> </span><span class="token operator">*</span><span class="token operator"> </span><span class="token operator">a</span><span class="token operator"> </span><span class="token operator">}</span>
<span class="token operator">}</span></code></pre></div>
<p>Running <code class="language-text">nickel test</code> on this file will highlight the typo in the
function definition:</p>
<div class="gatsby-highlight"><pre class="language-text"><code class="language-text">testing more_avocado/0...FAILED
test more_avocado/0 failed
error: contract broken by a value
   ┌─ &lt;unknown&gt; (generated by evaluation):1:1
   │
 1 │ std.contract.Equal ('Fish { avocado = 2, })
   │ ------------------------------------------- expected type
   │
  &lt;snip...&gt;
   ┌─ input.ncl:12:38
   │
12 │     = fun ('Fish { avocado = a }) =&gt; 'Fish { avocado = 3 * a }
   │                                      ------------------------- evaluated to this expression

1 failures
error: tests failed</code></pre></div>
<h3 id="jsonyamltoml-interop"><a class="anchor before" href="https://www.tweag.io/rss.xml#jsonyamltoml-interop"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>JSON/YAML/TOML interop</h3>
<p>Interoperability with plain data formats (JSON, YAML, and TOML) has been improved in several ways.</p>
<ul>
<li>The YAML format allows for several YAML documents to be embedded in the
same file (separated by <code class="language-text">---</code> lines). We can read such files since
<a href="https://github.com/tweag/nickel/releases/tag/1.2.0">Nickel 1.2</a>, and we can write them since <a href="https://github.com/tweag/nickel/releases/tag/1.15.1">Nickel 1.15</a>:
from Nickel 1.15 onwards, <code class="language-text">nickel export --format yaml-documents</code> will export a Nickel
list to a collection of YAML documents (as opposed to <code class="language-text">nickel export --format yaml</code>, which
outputs a single YAML document that contains a list). Similarly, Nickel 1.15’s
standard library serialization functions support a new <code class="language-text">'YamlDocuments</code> format.</li>
<li>The <code class="language-text">nickel convert</code> command, added in <a href="https://github.com/tweag/nickel/releases/tag/1.15.1">Nickel 1.15</a> allows
conversion of JSON, YAML, or TOML to Nickel. This complements the long-supported ability to
import data formats as in <code class="language-text">import "file.json"</code>: while importing data formats is
useful for consuming data produced by some other tool, the new conversion feature
allows for migrating other configuration to Nickel.</li>
<li>Since <a href="https://github.com/tweag/nickel/releases/tag/1.3.0">Nickel 1.3</a>, the <code class="language-text">nickel</code> command line will merge plain data files into Nickel
code: if you have a JSON file containing <code class="language-text">{ "price_per_taco": 5 }</code> and a Nickel file
containing <code class="language-text">{ tacos = 3, price = price_per_taco * tacos, price_per_taco }</code> then
<code class="language-text">nickel export json_file.json nickel_file.ncl</code> will merge the JSON-specified price
into the Nickel configuration before evaluating it.</li>
</ul>
<h3 id="release-process-and-distribution"><a class="anchor before" href="https://www.tweag.io/rss.xml#release-process-and-distribution"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>Release process and distribution</h3>
<p>For the <a href="https://github.com/tweag/nickel/releases/tag/1.0.0">Nickel 1.0</a> release, we built binaries for Linux x86_64 and aarch64 only.
Now, we’re building MacOS and Windows binaries as well. And we’re not the only distributors
of Nickel binaries: nixpkgs, Arch Linux, and Homebrew all have up-to-date Nickel packages.</p>
<p>We’ve also improved the usage of Nickel as a library. Since <a href="https://github.com/tweag/nickel/releases/tag/1.10.0">Nickel 1.10</a>, we’ve
been publishing our Python bindings on PyPI. And <a href="https://github.com/tweag/nickel/releases/tag/1.15.1">Nickel 1.15</a> saw our first
release of C and Go bindings, along with a stable Rust API.</p>
<h2 id="experimental-features"><a class="anchor before" href="https://www.tweag.io/rss.xml#experimental-features"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>Experimental features</h2>
<p>Since 1.0, Nickel has grown a few experimental features for use cases that we want to
enable but don’t yet have enough confidence in the design and implementation
to fully support. Some of these features (Nix compatibility and package management)
are disabled by default; you’ll need to build Nickel with explicit support for them.
If you’re using any of these features, let us know what you’re doing
with them and whether they’re working the way you want!</p>
<h3 id="customize-mode"><a class="anchor before" href="https://www.tweag.io/rss.xml#customize-mode"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>Customize mode</h3>
<p>Sometimes, writing a new configuration file for one or two settings feels unnecessary.
Our “customize mode”, introduced in <a href="https://github.com/tweag/nickel/releases/tag/1.2.0">Nickel 1.2</a>, allows configuration to be
supplied at the command line. For example, given the
<code class="language-text">{ tacos = 3, price = price_per_taco * tacos, price_per_taco }</code> example from before,
we can evaluate it with</p>
<div class="gatsby-highlight"><pre class="language-sh"><code class="language-sh">$ nickel <span class="token builtin class-name">export</span> tacos.ncl -- <span class="token assign-left variable">price_per_taco</span><span class="token operator">=</span><span class="token number">5</span>
<span class="token punctuation">{</span>
  <span class="token string">"price"</span><span class="token builtin class-name">:</span> <span class="token number">15</span>,
  <span class="token string">"price_per_taco"</span><span class="token builtin class-name">:</span> <span class="token number">5</span>,
  <span class="token string">"tacos"</span><span class="token builtin class-name">:</span> <span class="token number">3</span>
<span class="token punctuation">}</span></code></pre></div>
<p>Also, if you aren’t sure what options are available for setting, you can ask:</p>
<div class="gatsby-highlight"><pre class="language-sh"><code class="language-sh">$ nickel <span class="token builtin class-name">export</span> tacos.ncl -- list
Input fields:
- price_per_taco

Overridable fields <span class="token punctuation">(</span>require <span class="token variable"><span class="token variable">`</span><span class="token parameter variable">--override</span><span class="token variable">`</span></span><span class="token punctuation">)</span>:
- price
- tacos

Use the <span class="token variable"><span class="token variable">`</span>query<span class="token variable">`</span></span> subcommand to print a detailed description of a specific field. See <span class="token variable"><span class="token variable">`</span>nickel <span class="token builtin class-name">help</span> query<span class="token variable">`</span></span><span class="token builtin class-name">.</span></code></pre></div>
<p>Since <a href="https://github.com/tweag/nickel/releases/tag/1.11.0">Nickel 1.11</a>, customize mode has had support for environment variables:
<code class="language-text">nickel export tacos.ncl -- taco_description=@env:DESC</code> will expand the <code class="language-text">DESC</code>
environment variable and substitute it into the <code class="language-text">tacos.ncl</code> configuration.
In some cases, you could achieve something similar by expanding environment
variables using your shell, but correctly handling escaping there can be
painful (or even a security risk).</p>
<h3 id="nix-compatibility"><a class="anchor before" href="https://www.tweag.io/rss.xml#nix-compatibility"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>Nix compatibility</h3>
<p>A lot of Nickel users are also Nix users, and so Nix interoperability is an
often-requested feature. Our current Nix interface is limited to plain data,
but you can import Nix from Nickel if you’ve built Nickel with the
“nix-experimental” feature:</p>
<div class="gatsby-highlight"><pre class="language-nickel"><code class="language-nickel"><span class="token operator">{</span>
<span class="token operator"> </span><span class="token operator"> </span><span class="token property">price</span><span class="token operator"> </span><span class="token operator">=</span><span class="token operator"> </span><span class="token operator">p</span><span class="token operator">r</span><span class="token operator">i</span><span class="token operator">c</span><span class="token operator">e</span><span class="token operator">_</span><span class="token operator">p</span><span class="token operator">e</span><span class="token operator">r</span><span class="token operator">_</span><span class="token operator">t</span><span class="token operator">a</span><span class="token operator">c</span><span class="token operator">o</span><span class="token operator"> </span><span class="token operator">*</span><span class="token operator"> </span><span class="token operator">s</span><span class="token operator">t</span><span class="token operator">d</span><span class="token operator">.</span><span class="token operator">a</span><span class="token operator">r</span><span class="token operator">r</span><span class="token operator">a</span><span class="token operator">y</span><span class="token operator">.</span><span class="token operator">l</span><span class="token operator">e</span><span class="token operator">n</span><span class="token operator">g</span><span class="token operator">t</span><span class="token operator">h</span><span class="token operator"> </span><span class="token operator">(</span><span class="token keyword">import</span><span class="token operator"> </span><span class="token string">"tacos.nix"</span><span class="token operator">)</span>
<span class="token operator"> </span><span class="token operator"> </span><span class="token property">price_per_taco</span><span class="token operator"> </span><span class="token operator">=</span><span class="token operator"> </span><span class="token number">5</span><span class="token operator">,</span>
<span class="token operator">}</span></code></pre></div>
<h3 id="package-management"><a class="anchor before" href="https://www.tweag.io/rss.xml#package-management"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>Package management</h3>
<p>In Nickel 1.0, you could share code between projects by copying files around,
basically. <a href="https://github.com/tweag/nickel/releases/tag/1.11.0">Nickel 1.11</a> introduced package management, allowing you
to import Nickel dependencies from other directories, Git repositories, or a
central package registry. You declare your dependencies in a <code class="language-text">Nickel-pkg.ncl</code>
manifest file:</p>
<div class="gatsby-highlight"><pre class="language-nickel"><code class="language-nickel"><span class="token operator">{</span>
<span class="token operator"> </span><span class="token operator"> </span><span class="token property">name</span><span class="token operator"> </span><span class="token operator">=</span><span class="token operator"> </span><span class="token string">"tacos"</span><span class="token operator">,</span>
<span class="token operator"> </span><span class="token operator"> </span><span class="token property">authors</span><span class="token operator"> </span><span class="token operator">=</span><span class="token operator"> </span><span class="token operator">[</span><span class="token string">"Me"</span><span class="token operator">]</span><span class="token operator">,</span>
<span class="token operator"> </span><span class="token operator"> </span><span class="token property">minimal_nickel_version</span><span class="token operator"> </span><span class="token operator">=</span><span class="token operator"> </span><span class="token string">"1.15.0"</span><span class="token operator">,</span>
<span class="token operator"> </span><span class="token operator"> </span><span class="token property">dependencies</span><span class="token operator"> </span><span class="token operator">=</span><span class="token operator"> </span><span class="token operator">{</span><span class="token operator"> </span><span class="token property">salsa</span><span class="token operator"> </span><span class="token operator">=</span><span class="token operator"> </span><span class="token operator">'</span><span class="token operator">G</span><span class="token operator">i</span><span class="token operator">t</span><span class="token operator"> </span><span class="token operator">{</span><span class="token operator"> </span><span class="token property">package</span><span class="token operator"> </span><span class="token operator">=</span><span class="token operator"> </span><span class="token string">"github:example/salsa"</span><span class="token operator">,</span><span class="token operator"> </span><span class="token property">version</span><span class="token operator"> </span><span class="token operator">=</span><span class="token operator"> </span><span class="token string">"1.0"</span><span class="token operator"> </span><span class="token operator">}</span><span class="token operator"> </span><span class="token operator">}</span><span class="token operator">,</span>
<span class="token operator">}</span></code></pre></div>
<p>Then you can import those dependencies in your Nickel code:</p>
<div class="gatsby-highlight"><pre class="language-nickel"><code class="language-nickel"><span class="token operator">'</span><span class="token operator">F</span><span class="token operator">i</span><span class="token operator">s</span><span class="token operator">h</span><span class="token operator"> </span><span class="token operator">{</span><span class="token operator"> </span><span class="token property">avocado</span><span class="token operator"> </span><span class="token operator">=</span><span class="token operator"> </span><span class="token number">1</span><span class="token operator">,</span><span class="token operator"> </span><span class="token property">salsa</span><span class="token operator"> </span><span class="token operator">=</span><span class="token operator"> </span><span class="token operator">(</span><span class="token keyword">import</span><span class="token operator"> </span><span class="token operator">s</span><span class="token operator">a</span><span class="token operator">l</span><span class="token operator">s</span><span class="token operator">a</span><span class="token operator">)</span><span class="token operator">.</span><span class="token operator">v</span><span class="token operator">e</span><span class="token operator">r</span><span class="token operator">d</span><span class="token operator">e</span><span class="token operator"> </span><span class="token operator">}</span></code></pre></div>
<h2 id="thank-you"><a class="anchor before" href="https://www.tweag.io/rss.xml#thank-you"><svg height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z" fill-rule="evenodd"/></svg></a>Thank you!</h2>
<p>That sums up the biggest changes to Nickel over the past two and a half years or so.
As we come up on 5,000 commits from 86 contributors, we’d like to thank you
for all the feedback, discussion, and participation that encourage us
to keep improving Nickel.</p>
<div class="footnotes">
<hr/>
<ol>
<li id="fn-1">There are some situations where let blocks can improve
performance with Nickel’s current interpreter: <code class="language-text">let x = 1 in let y = 2 in x + y</code> creates two nested environments while <code class="language-text">let x = 1, y = 2 in x + y</code> creates a single environment. Variable lookups are usually faster when
environments are less deeply nested, so the version with a let block should
be a little bit faster. This performance distinction will probably go away
once we have a <a href="https://github.com/tweag/nickel/blob/c483fe2811fa6b271d96cf87b8b3d3872fe03d8f/rfcs/007-bytecode-interpreter.md">bytecode interpreter</a>, though.<a class="footnote-backref" href="https://www.tweag.io/rss.xml#fnref-1">↩</a></li>
</ol>
</div></div>
    </summary>
    <updated>2026-02-19T00:00:00Z</updated>
    <published>2026-02-19T00:00:00Z</published>
    <source>
      <id>https://tweag.io</id>
      <author>
        <name>Tweag I/O</name>
      </author>
      <link href="https://tweag.io" rel="alternate" type="text/html"/>
      <link href="http://www.tweag.io/rss.xml" rel="self" type="application/rss+xml"/>
      <subtitle>Scale your engineering power. We enable deep-tech startups to achieve
their vision, from research to product delivery.</subtitle>
      <title>Tweag - Engineering blog</title>
      <updated>2026-06-12T11:01:45Z</updated>
    </source>
  </entry>

  <entry>
    <id>https://magnus.therning.org/2026-02-18-switching-to-project.el.html</id>
    <link href="https://magnus.therning.org/2026-02-18-switching-to-project.el.html" rel="alternate" type="text/html"/>
    <title>Switching to project.el</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>
I've used <a href="https://github.com/bbatsov/projectile">projectile</a> ever since I created my own Emacs config. I have a vague
memory choosing it because some other package only supported it. (It might have
been <a href="https://emacs-lsp.github.io/lsp-mode/">lsp-mode</a>, but I'm not sure.) Anyway, now that <a href="https://magnus.therning.org/2026-01-19-trying-eglot,-again.html">I'm trying out eglot</a>, <a href="https://magnus.therning.org/2026-01-25-more-on-the-switch-to-eglot.html">again</a>,
I thought I might as well see if I can switch to <a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Projects.html">project.el</a>, which is included
in Emacs nowadays.
</p>
<div class="outline-2" id="outline-container-org86928ff">
<h2 id="org86928ff">A non-VC project marker</h2>
<div class="outline-text-2" id="text-org86928ff">
<p>
Projectile allows using a file, <code>.projectile</code>, in the root of a project. This
makes it possible to turn a folder into a project without having to use version
control. It's possible to configure project.el to respect more VC markers than
what's built-in. This can be used to define a non-VC marker.
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><code><span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">setopt</span> project-vc-extra-root-markers '<span class="org-rainbow-delimiters-depth-2">(</span><span class="org-string">".projectile"</span> <span class="org-string">".git"</span><span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span>
</code></pre>
</div>

<p>
Since I've set <code>vc-handled-backends</code> to <code>nil</code> (the default made VC interfere
with magit, so I turned it off completely) I had to add <code>".git"</code> to make git
repos be recognised as projects too.
</p>
</div>
</div>
<div class="outline-2" id="outline-container-orgd0c3904">
<h2 id="orgd0c3904">Xref history</h2>
<div class="outline-text-2" id="text-orgd0c3904">
<p>
The first thing to solve was that the <a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Xref.html">xref</a> stack wasn't per project. Somewhat
disappointingly there only seems to be two options for <code>xref-history-storage</code>
shipped with Emacs
</p>

<dl class="org-dl">
<dt><code>xref-global-history</code></dt><dd>a single global history (the default)</dd>
<dt><code>xref-window-local-history</code></dt><dd>a history per window</dd>
</dl>

<p>
I had the same issue with projectile, and ended up writing my own package for
it. For project.el I settled on using <a href="https://codeberg.org/imarko/xref-project-history.git">xref-project-history</a>.
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><code><span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">use-package</span> xref-project-history
  <span class="org-builtin">:ensure</span> <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-builtin">:type</span> git
           <span class="org-builtin">:repo</span> <span class="org-string">"https://codeberg.org/imarko/xref-project-history.git"</span>
           <span class="org-builtin">:branch</span> <span class="org-string">"master"</span><span class="org-rainbow-delimiters-depth-2">)</span>
  <span class="org-builtin">:custom</span>
  <span class="org-rainbow-delimiters-depth-2">(</span>xref-history-storage #'xref-project-history<span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span>
</code></pre>
</div>
</div>
</div>
<div class="outline-2" id="outline-container-org7744253">
<h2 id="org7744253">Jumping between implementation and test</h2>
<div class="outline-text-2" id="text-org7744253">
<p>
Projectile has a function for jumping between implementation and test. Not too
surprisingly it's called <code>projectile-toggle-between-implementation-and-test</code>. I
found some old emails in an archive suggesting that project.el might have had
something similar in the past, but if that's the case it's been removed by now.
When searching for a package I came across <a href="https://lists.gnu.org/archive/html/emacs-devel/2022-09/msg00300.html">this email comparing tools for
finding related files</a>. The author mentions two that are included with Emacs
</p>

<dl class="org-dl">
<dt><code>ff-find-other-file</code></dt><dd>part of find-file.el, which a few other functions and
a rather impressive set of settings to customise its behaviour.</dd>
<dt><code>find-sibling-file</code></dt><dd>a newer command, I believe, that also can be
customised.</dd>
</dl>

<p>
So, there are options, but neither of them are made to work nicely with
project.el out of the box. My most complicated use case seems to be in Haskell
projects where modules for implementation and test live in separate (mirrored)
folder hierarchies, e.g.
</p>

<pre class="example" id="org1559d8d">src
└── Sider
    └── Data
        ├── Command.hs
        ├── Pipeline.hs
        └── Resp.hs
test
└── Sider
    └── Data
        ├── CommandSpec.hs
        ├── PipelineSpec.hs
        └── RespSpec.hs

</pre>

<p>
I'm not really sure how I'd configure <code>find-sibling-rules</code>, which are regular
expressions, to deal with folder hierarchies like this. To be honest, I didn't
really see a way of configuring <code>ff-find-other-file</code> at first either. Then I
happened on a post about <a href="https://dev.to/fredericlepied/emacs-how-to-switch-from-modulepy-to-testmodulepy-67k">switching between a module and its tests in Python</a>.
With its help I came up with the following
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><code><span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">defun</span> <span class="org-function-name">mes/setup-hs-ff</span> <span class="org-rainbow-delimiters-depth-2">()</span>
  <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-keyword">when-let*</span> <span class="org-rainbow-delimiters-depth-3">(</span><span class="org-rainbow-delimiters-depth-4">(</span>proj-root <span class="org-rainbow-delimiters-depth-5">(</span>project-root <span class="org-rainbow-delimiters-depth-6">(</span>project-current<span class="org-rainbow-delimiters-depth-6">)</span><span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span>
              <span class="org-rainbow-delimiters-depth-4">(</span>rel-proj-root <span class="org-rainbow-delimiters-depth-5">(</span><span class="org-keyword">-some--&gt;</span> <span class="org-rainbow-delimiters-depth-6">(</span>buffer-file-name<span class="org-rainbow-delimiters-depth-6">)</span>
                               <span class="org-rainbow-delimiters-depth-6">(</span>file-name-directory it<span class="org-rainbow-delimiters-depth-6">)</span>
                               <span class="org-rainbow-delimiters-depth-6">(</span>f-relative proj-root it<span class="org-rainbow-delimiters-depth-6">)</span><span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span>
              <span class="org-rainbow-delimiters-depth-4">(</span>sub-tree <span class="org-rainbow-delimiters-depth-5">(</span>car <span class="org-rainbow-delimiters-depth-6">(</span>f-split <span class="org-rainbow-delimiters-depth-7">(</span>f-relative <span class="org-rainbow-delimiters-depth-8">(</span>buffer-file-name<span class="org-rainbow-delimiters-depth-8">)</span> proj-root<span class="org-rainbow-delimiters-depth-7">)</span><span class="org-rainbow-delimiters-depth-6">)</span><span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span>
              <span class="org-rainbow-delimiters-depth-4">(</span>search-dirs <span class="org-rainbow-delimiters-depth-5">(</span><span class="org-keyword">--&gt;</span> '<span class="org-rainbow-delimiters-depth-6">(</span><span class="org-string">"src"</span> <span class="org-string">"test"</span><span class="org-rainbow-delimiters-depth-6">)</span>
                                <span class="org-rainbow-delimiters-depth-6">(</span>remove sub-tree it<span class="org-rainbow-delimiters-depth-6">)</span>
                                <span class="org-rainbow-delimiters-depth-6">(</span>-map <span class="org-rainbow-delimiters-depth-7">(</span><span class="org-keyword">lambda</span> <span class="org-rainbow-delimiters-depth-8">(</span>p<span class="org-rainbow-delimiters-depth-8">)</span> <span class="org-rainbow-delimiters-depth-8">(</span>f-join proj-root p<span class="org-rainbow-delimiters-depth-8">)</span><span class="org-rainbow-delimiters-depth-7">)</span> it<span class="org-rainbow-delimiters-depth-6">)</span>
                                <span class="org-rainbow-delimiters-depth-6">(</span>-select #'f-directory? it<span class="org-rainbow-delimiters-depth-6">)</span>
                                <span class="org-rainbow-delimiters-depth-6">(</span>-mapcat <span class="org-rainbow-delimiters-depth-7">(</span><span class="org-keyword">lambda</span> <span class="org-rainbow-delimiters-depth-8">(</span>p<span class="org-rainbow-delimiters-depth-8">)</span> <span class="org-rainbow-delimiters-depth-8">(</span>f-directories p nil t<span class="org-rainbow-delimiters-depth-8">)</span><span class="org-rainbow-delimiters-depth-7">)</span> it<span class="org-rainbow-delimiters-depth-6">)</span>
                                <span class="org-rainbow-delimiters-depth-6">(</span>-map <span class="org-rainbow-delimiters-depth-7">(</span><span class="org-keyword">lambda</span> <span class="org-rainbow-delimiters-depth-8">(</span>p<span class="org-rainbow-delimiters-depth-8">)</span> <span class="org-rainbow-delimiters-depth-8">(</span>f-relative p proj-root<span class="org-rainbow-delimiters-depth-8">)</span><span class="org-rainbow-delimiters-depth-7">)</span> it<span class="org-rainbow-delimiters-depth-6">)</span>
                                <span class="org-rainbow-delimiters-depth-6">(</span>-map <span class="org-rainbow-delimiters-depth-7">(</span><span class="org-keyword">lambda</span> <span class="org-rainbow-delimiters-depth-8">(</span>p<span class="org-rainbow-delimiters-depth-8">)</span> <span class="org-rainbow-delimiters-depth-8">(</span>f-join rel-proj-root p<span class="org-rainbow-delimiters-depth-8">)</span><span class="org-rainbow-delimiters-depth-7">)</span> it<span class="org-rainbow-delimiters-depth-6">)</span><span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span>
    <span class="org-rainbow-delimiters-depth-3">(</span><span class="org-keyword">setq-local</span> ff-search-directories search-dirs
                ff-other-file-alist '<span class="org-rainbow-delimiters-depth-4">(</span><span class="org-rainbow-delimiters-depth-5">(</span><span class="org-string">"Spec\\.hs$"</span> <span class="org-rainbow-delimiters-depth-6">(</span><span class="org-string">".hs"</span><span class="org-rainbow-delimiters-depth-6">)</span><span class="org-rainbow-delimiters-depth-5">)</span>
                                      <span class="org-rainbow-delimiters-depth-5">(</span><span class="org-string">"\\.hs$"</span> <span class="org-rainbow-delimiters-depth-6">(</span><span class="org-string">"Spec.hs"</span><span class="org-rainbow-delimiters-depth-6">)</span><span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span>
</code></pre>
</div>

<p>
A few things to note
</p>

<ol class="org-ol">
<li>The order of rules in <code>ff-other-file-alist</code> is important, the first match is
chosen.</li>
<li><code>(buffer-file-name)</code> can, and really does, return <code>nil</code> at times, and
<code>file-name-directory</code> doesn't deal with anything but strings.</li>
<li>The entries in <code>ff-search-directories</code> have to be relative to the file in the
current buffer, hence the rather involved <code>varlist</code> in the <code>when-let*</code>
expression.</li>
</ol>

<p>
With this in place I get the following values for <code>ff-search-directories</code>
</p>

<dl class="org-dl">
<dt><code>src/Sider/Data/Command.hs</code></dt><dd><code>("../../../test/Sider" "../../../test/Sider/Data")</code></dd>
<dt><code>test/Sider/Data/CommandSpec.hs</code></dt><dd><code>("../../../src/Sider" "../../../src/Sider/Data")</code></dd>
</dl>

<p>
And <code>ff-find-other-file</code> works beautifully.
</p>
</div>
</div>
<div class="outline-2" id="outline-container-org4cc6636">
<h2 id="org4cc6636">Conclusion</h2>
<div class="outline-text-2" id="text-org4cc6636">
<p>
My setup with project.el now covers everything I used from projectile so I'm
fairly confident I'll be happy keeping it.
</p>
</div>
</div>
<div class="taglist"><a href="https://magnus.therning.org/tags.html">Tags</a>: <a href="https://magnus.therning.org/tag-emacs.html">emacs</a> <a href="https://magnus.therning.org/tag-project-el.html">project-el</a> </div></div>
    </summary>
    <updated>2026-02-17T23:09:00Z</updated>
    <published>2026-02-17T23:09:00Z</published>
    <category term="emacs"/>
    <category term="project-el"/>
    <source>
      <id>https://magnus.therning.org/</id>
      <author>
        <name>Magnus Therning</name>
      </author>
      <link href="https://magnus.therning.org/" rel="alternate" type="text/html"/>
      <link href="https://magnus.therning.org/feed.xml" rel="self" type="application/rss+xml"/>
      <subtitle>Magnus web site</subtitle>
      <title>Magnus web site</title>
      <updated>2026-05-04T06:17:54Z</updated>
    </source>
  </entry>

  <entry>
    <id>https://magnus.therning.org/2026-02-16-using-advice-to-limit-lsp-ui-doc-nuisance.html</id>
    <link href="https://magnus.therning.org/2026-02-16-using-advice-to-limit-lsp-ui-doc-nuisance.html" rel="alternate" type="text/html"/>
    <title>Using advice to limit lsp-ui-doc nuisance</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>
I've switched back to <a href="https://emacs-lsp.github.io/lsp-mode/">lsp-mode</a> temporarily until I've had time to fix a few
things with my <code>eglot</code> setup. Returning prompted me to finally address an
irritating behaviour with <a href="https://emacs-lsp.github.io/lsp-ui/#lsp-ui-doc">lsp-ui-doc</a>.
</p>

<p>
No matter what I set <code>lsp-ui-doc-position</code> to it ends up covering information
that I want to see. While waiting for a <a href="https://github.com/emacs-lsp/lsp-ui/issues/793">fix</a> I decided to work around it. It
seems to me that this is exactly what <a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Advising-Functions.html">advice</a> is for.
</p>

<p>
I came up with the following to make sure the frame appears on the half of the
buffer where <code>point</code> isn't.
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><code><span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">defun</span> <span class="org-function-name">my-lsp-ui-doc-wrapper</span> <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-type">&amp;rest</span> _<span class="org-rainbow-delimiters-depth-2">)</span>
  <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-keyword">let*</span> <span class="org-rainbow-delimiters-depth-3">(</span><span class="org-rainbow-delimiters-depth-4">(</span>pos-line <span class="org-rainbow-delimiters-depth-5">(</span>- <span class="org-rainbow-delimiters-depth-6">(</span>line-number-at-pos <span class="org-rainbow-delimiters-depth-7">(</span>point<span class="org-rainbow-delimiters-depth-7">)</span><span class="org-rainbow-delimiters-depth-6">)</span>
                      <span class="org-rainbow-delimiters-depth-6">(</span>line-number-at-pos <span class="org-rainbow-delimiters-depth-7">(</span>window-start<span class="org-rainbow-delimiters-depth-7">)</span><span class="org-rainbow-delimiters-depth-6">)</span><span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span>
         <span class="org-rainbow-delimiters-depth-4">(</span>pos <span class="org-rainbow-delimiters-depth-5">(</span><span class="org-keyword">if</span> <span class="org-rainbow-delimiters-depth-6">(</span>&lt;= pos-line <span class="org-rainbow-delimiters-depth-7">(</span>/ <span class="org-rainbow-delimiters-depth-8">(</span>window-body-height<span class="org-rainbow-delimiters-depth-8">)</span> 2<span class="org-rainbow-delimiters-depth-7">)</span><span class="org-rainbow-delimiters-depth-6">)</span>
                  'bottom
                'top<span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span>
    <span class="org-rainbow-delimiters-depth-3">(</span><span class="org-keyword">setopt</span> lsp-ui-doc-position pos<span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span>

<span class="org-rainbow-delimiters-depth-1">(</span>advice-add 'lsp-ui-doc--move-frame <span class="org-builtin">:before</span> #'my-lsp-ui-doc-wrapper<span class="org-rainbow-delimiters-depth-1">)</span>
</code></pre>
</div>
<div class="taglist"><a href="https://magnus.therning.org/tags.html">Tags</a>: <a href="https://magnus.therning.org/tag-emacs.html">emacs</a> <a href="https://magnus.therning.org/tag-lsp-mode.html">lsp-mode</a> </div></div>
    </summary>
    <updated>2026-02-16T19:10:00Z</updated>
    <published>2026-02-16T19:10:00Z</published>
    <category term="emacs"/>
    <category term="lsp-mode"/>
    <source>
      <id>https://magnus.therning.org/</id>
      <author>
        <name>Magnus Therning</name>
      </author>
      <link href="https://magnus.therning.org/" rel="alternate" type="text/html"/>
      <link href="https://magnus.therning.org/feed.xml" rel="self" type="application/rss+xml"/>
      <subtitle>Magnus web site</subtitle>
      <title>Magnus web site</title>
      <updated>2026-05-04T06:17:54Z</updated>
    </source>
  </entry>

  <entry xml:lang="en-us">
    <id>https://haskellforall.com/2026/02/browse-code-by-meaning</id>
    <link href="https://haskellforall.com/2026/02/browse-code-by-meaning" rel="alternate" type="text/html"/>
    <title>Browse code by meaning</title>
    <summary>Navigate a repository using topic modeling</summary>
    <updated>2026-02-16T00:00:00Z</updated>
    <published>2026-02-16T00:00:00Z</published>
    <source>
      <id>https://haskellforall.com</id>
      <author>
        <name>Gabriella Gonzalez</name>
      </author>
      <link href="https://haskellforall.com" rel="alternate" type="text/html"/>
      <link href="https://haskellforall.com/rss.xml" rel="self" type="application/rss+xml"/>
      <subtitle>A blog about Haskell and functional programming.</subtitle>
      <title>Haskell for all</title>
      <updated>2026-06-07T13:45:09Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-23427281.post-4433953526927400176</id>
    <link href="http://blog.holdenkarau.com/feeds/4433953526927400176/comments/default" rel="replies" title="Post Comments" type="application/atom+xml"/>
    <link href="http://www.blogger.com/comment/fullpage/post/23427281/4433953526927400176" rel="replies" title="0 Comments" type="text/html"/>
    <link href="http://www.blogger.com/feeds/23427281/posts/default/4433953526927400176" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/23427281/posts/default/4433953526927400176" rel="self" type="application/atom+xml"/>
    <link href="http://blog.holdenkarau.com/2026/02/new-year-new-job-same-projects.html" rel="alternate" title="New year new job, same projects" type="text/html"/>
    <title>New year new job, same projects</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p> I’m stoked to announce that I’ve joined Snowflake to continue working on OSS Apache Spark :) I’ve got a post on the Snowflake blog talking about the work we’re doing <a href="https://careers.snowflake.com/us/en/blogarticle/building-apache-spark-in-the-open-at-snowflake">https://careers.snowflake.com/us/en/blogarticle/building-apache-spark-in-the-open-at-snowflake</a> — </p></div>
    </content>
    <updated>2026-02-12T15:51:06Z</updated>
    <published>2026-02-12T15:51:00Z</published>
    <author>
      <name>Holden Karau</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/05915225834474424123</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-23427281</id>
      <category term="all the code"/>
      <category term="life"/>
      <category term="random"/>
      <category term="codeing"/>
      <category term="atc"/>
      <category term="business"/>
      <category term="amazon web services"/>
      <category term="google summer of code"/>
      <category term="openmoko"/>
      <category term="spark"/>
      <category term="demo"/>
      <category term="democamp"/>
      <category term="freerunner"/>
      <category term="google"/>
      <category term="haskell"/>
      <category term="programming"/>
      <category term="spark-project"/>
      <category term="ssc"/>
      <category term="work"/>
      <category term="amazon"/>
      <category term="amazon web search platform"/>
      <category term="linux"/>
      <category term="scala"/>
      <category term="bugs"/>
      <category term="computer science"/>
      <category term="devicescape"/>
      <category term="ninjas"/>
      <category term="software"/>
      <category term="spam"/>
      <category term="subversion"/>
      <category term="talks"/>
      <category term="ubuntu"/>
      <category term="wireless"/>
      <category term="amazon ec2"/>
      <category term="awsp"/>
      <category term="barcamp"/>
      <category term="bigdata"/>
      <category term="boingo mobile"/>
      <category term="canada"/>
      <category term="computer science club"/>
      <category term="copyright"/>
      <category term="crazyness"/>
      <category term="csc"/>
      <category term="database builds"/>
      <category term="datamining"/>
      <category term="democampguelph"/>
      <category term="developement"/>
      <category term="dnsrbl"/>
      <category term="emacs"/>
      <category term="encryption"/>
      <category term="failboat"/>
      <category term="functional programming"/>
      <category term="funding"/>
      <category term="funtimes"/>
      <category term="gsoc"/>
      <category term="java"/>
      <category term="mzscheme"/>
      <category term="plugins"/>
      <category term="rms"/>
      <category term="ruby on rails"/>
      <category term="scheme"/>
      <category term="security"/>
      <category term="ssl"/>
      <category term="university of waterloo"/>
      <category term="videos"/>
      <category term="wifi"/>
      <category term="yahoo"/>
      <category term="802.11a"/>
      <category term="802.11b"/>
      <category term="802.11g"/>
      <category term="Bjarne Stroustrup"/>
      <category term="almost useless information"/>
      <category term="amazon s3"/>
      <category term="antispam"/>
      <category term="apache spark"/>
      <category term="asus"/>
      <category term="atom"/>
      <category term="barcampwaterloo"/>
      <category term="barcampwaterloo4"/>
      <category term="beer"/>
      <category term="blogging"/>
      <category term="boingo"/>
      <category term="build systems"/>
      <category term="c++"/>
      <category term="cabal"/>
      <category term="cabalandhunittogether"/>
      <category term="cellphone"/>
      <category term="character encodings"/>
      <category term="co-op"/>
      <category term="code"/>
      <category term="cogent"/>
      <category term="competitors"/>
      <category term="computers"/>
      <category term="concurrency"/>
      <category term="darcs"/>
      <category term="databases"/>
      <category term="democamp2"/>
      <category term="deployment"/>
      <category term="dns"/>
      <category term="dodgy"/>
      <category term="eclipse"/>
      <category term="emacs subversion"/>
      <category term="esr"/>
      <category term="facebook"/>
      <category term="fail"/>
      <category term="failboatish"/>
      <category term="feedback"/>
      <category term="filtering ai rss aiderss waterloo companies product-launches"/>
      <category term="fixing"/>
      <category term="fun"/>
      <category term="git"/>
      <category term="github"/>
      <category term="globalive"/>
      <category term="gmail"/>
      <category term="gmailprivacy"/>
      <category term="googleprivacy"/>
      <category term="gsm"/>
      <category term="guelphdemocamp"/>
      <category term="guelphdemocamp2"/>
      <category term="hackage"/>
      <category term="hackday"/>
      <category term="happy"/>
      <category term="hobos"/>
      <category term="httppostmail"/>
      <category term="hunit"/>
      <category term="ide"/>
      <category term="imap"/>
      <category term="improvements"/>
      <category term="integrating cabal and haskell"/>
      <category term="internationalization"/>
      <category term="internet"/>
      <category term="iphone"/>
      <category term="iphoneyahoo"/>
      <category term="jobs"/>
      <category term="krugle"/>
      <category term="lack of privacy"/>
      <category term="launch"/>
      <category term="law"/>
      <category term="linuxphone"/>
      <category term="mail"/>
      <category term="man in the middle"/>
      <category term="math"/>
      <category term="mobile"/>
      <category term="neo"/>
      <category term="neofreerunner"/>
      <category term="news"/>
      <category term="numbers"/>
      <category term="ogg"/>
      <category term="oops"/>
      <category term="optimism"/>
      <category term="parsing xml"/>
      <category term="phones"/>
      <category term="pi"/>
      <category term="pie charts"/>
      <category term="pigs can fly"/>
      <category term="pigs can fly site monitor"/>
      <category term="plt scheme"/>
      <category term="porting"/>
      <category term="presentations"/>
      <category term="press"/>
      <category term="pretty printing"/>
      <category term="privacy"/>
      <category term="programming languages"/>
      <category term="projects"/>
      <category term="python"/>
      <category term="rexml"/>
      <category term="rss"/>
      <category term="ruby"/>
      <category term="scaling"/>
      <category term="scaling ruby on rails"/>
      <category term="selling"/>
      <category term="servers"/>
      <category term="shopping"/>
      <category term="sillyness"/>
      <category term="sketchy launch"/>
      <category term="slashdot"/>
      <category term="soc"/>
      <category term="software developement"/>
      <category term="spelling"/>
      <category term="stalin scheme"/>
      <category term="starbucks"/>
      <category term="stats"/>
      <category term="stumbleupon"/>
      <category term="stupidty"/>
      <category term="su.pr"/>
      <category term="summer of code"/>
      <category term="swig"/>
      <category term="teliasonera"/>
      <category term="testing"/>
      <category term="topatoco"/>
      <category term="university"/>
      <category term="upgrades"/>
      <category term="usability"/>
      <category term="utf8"/>
      <category term="utf_8"/>
      <category term="video talk"/>
      <category term="vim"/>
      <category term="web applications"/>
      <category term="web apps"/>
      <category term="web2.0collage"/>
      <category term="weekend project"/>
      <category term="wi-fi"/>
      <category term="xandros"/>
      <category term="xml"/>
      <category term="yak"/>
      <category term="zimbra"/>
      <author>
        <name>Holden Karau</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/05915225834474424123</uri>
      </author>
      <link href="http://blog.holdenkarau.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/23427281/posts/default?redirect=false" rel="self" type="application/atom+xml"/>
      <link href="http://blog.holdenkarau.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/23427281/posts/default?start-index=26&amp;max-results=25&amp;redirect=false" rel="next" type="application/atom+xml"/>
      <subtitle>A Canadian developer in America.</subtitle>
      <title>Holden's Blog</title>
      <updated>2026-03-25T13:27:49Z</updated>
    </source>
  </entry>

  <entry>
    <id>https://tweag.io/blog/2026-02-12-doctor-xaelong/</id>
    <link href="https://tweag.io/blog/2026-02-12-doctor-xaelong/" rel="alternate" type="text/html"/>
    <title>How I learnt to stop worrying and love AI</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">
<section class="crawler">
<p>The following story is a work of fiction. Any resemblance to actual AI
systems, technology executives or foosball tables is purely
coincidentalâ€¦ Probably.</p>
<p>With apologies to <a href="https://en.wikipedia.org/wiki/Dr._Strangelove">Stanley Kubrick</a>.</p>
</section>

<p>Ernest Steadmann committed the final pull request into the staging
branch. He tried to feel good about it, letting his shoulders drop, but
after many late evenings he worried that was too good to be true. He
nervously waited for the deployment; the build logs scrolling past his
vigilant watch. Would yet another failure keep him from his young
family?</p>
<p>â€˜Hey, Ernie!â€™ came a DM from Thrustson.</p>
<p>He didnâ€™t know what he hated more: being called â€˜Ernieâ€™, or DMs that
were devoid of useful information. Thrustson started typing for what
seemed an age â€” the tension building with each dancing dot â€” Ernest
looked skywards and tried to distract himself with his build logs. After
a few false starts, the conversation started to flow:</p>
<blockquote>
<p><span class="byline">Richard Thrustson (CPO, EXT. Moonshot Intelligence LLC)</span> <br/>
hey ernie! <br/>
you made the final commit! AWESOME ğŸ¥³ does it work??!</p>
<p><span class="byline">Ernest Steadmann (Principal Engineer)</span> <br/>
Itâ€™s still building, Dickie. It usually takes about 20 minutes. <br/>
Iâ€™ll let you know.</p>
<p><span class="byline">Richard Thrustson (CPO, EXT. Moonshot Intelligence LLC)</span> <br/>
shiiiip iiitt ğŸ›¥ï¸�ğŸ˜�</p>
</blockquote>
<p>Ernestâ€™s eyes widened. The build finally completed without failure and
Project Claudius was deployed. He opened up his console and began the
first session:</p>
<div class="gatsby-highlight"><pre class="language-text"><code class="language-text">      _                 _ _
  ___| | __ _ _   _  __| (_)_   _ ___
 / __| |/ _` | | | |/ _` | | | | / __|
| (__| | (_| | |_| | (_| | | |_| \__ \
 \___|_|\__,_|\__,_|\__,_|_|\__,_|___/  v1.0.0-staging

steadmanne&gt; /status

claudius&gt; I'm doing great! My context window is empty. What can I help
you with next, steadmanne?

steadmanne&gt; Let's try a little test. Can you message thrustsonr to let
him know you are operational?

claudius&gt; I sure can! Let me check your e-mail settings so I-- CANCELLED

steadmanne&gt; Not e-mail; please use instant messaging.

claudius&gt; You're absolutely right! I apologise for the error. Let me DM
thrustsonr with the news...

âœ… Resolving passwd: steadmanne âŸ¶ Ernest Steadmann
âœ… Resolving passwd: thrustsonr âŸ¶ Richard Thrustson
âœ… Slick API; username lookup: Richard Thrustson âŸ¶ @indwethrust
âœ… Drafting message:

   &gt; Hi Richard, this is Claudius. Ernest asked me to let you know that
   &gt; I have been successfully deployed.

Does this match the tone you wish to convey?

steadmanne&gt; That's fine. Please send.

claudius&gt; Perfect! Let me send this e-mail-- CANCELLED

steadmanne&gt; INSTANT MESSAGE!

claudius&gt; You're absolutely right!

âœ… Slick API; post message: Posting........... DONE

steadmanne&gt; /status

claudius&gt; I'm doing great! My context window is 0.3% used. What can I
help you with next, steadmanne?</code></pre></div>
<p>Immediately, Ernestâ€™s video chat rang.</p>
<p>â€˜Hi, Dickie,â€™ he said flatly. â€˜Soâ€¦it works.â€™</p>
<p>â€˜Yeah, man! I saw. Thatâ€™s awesome.â€™ Thrustson was close to salivating.</p>
<p>â€˜It needed a bit of hand-holding. Iâ€™m not convinced itâ€™s ready for
production.â€™</p>
<p>â€˜Donâ€™t worry about it, Ernie. The deadlineâ€™s coming up and this already
looks amazing. We can ship it now and fix bugs in production. Itâ€™ll be
fine. Trust me.â€™</p>
<p>Ernest didnâ€™t trust him.</p>
<p>â€˜Iâ€™d still like to work with it a bit more. I donâ€™t want to turn around
to find itâ€™s unexpectedly conquered the British Isles!â€™ Ernest smirked.</p>
<p>â€˜What? Yeah, sure, Ernie-dude!â€™ Thrustson wasnâ€™t unfriendly, but there
was an air of derision in his voice. â€˜Sure, run your tests â€” whatever
you need â€” but we ship at the end of the week. Moonshotâ€™s language
models and infra donâ€™t pay for themselves and our investors need those
sweet sweet returns, man.</p>
<p>â€˜Itâ€™ll be fine, dude. Donâ€™t sweat it. Great work!â€™ he hung-up abruptly.</p>
<p>Ernest felt compelled to write an e-mail to his boss:</p>
<blockquote>
<p><span class="byline">To: Middleton-Fawne, Percival <br/>
From: Steadmann, Ernest <br/>
Subject: Claudius deployment</span></p>
<p>Hey, Percy</p>
<p>Claudius is finally deployed, but itâ€™sâ€¦a bit rough around the edges.
Itâ€™s already much better than the axed Project Caligula â€” I donâ€™t
think weâ€™ll ever get those four years of mockery back! â€” but I still
donâ€™t think itâ€™s ready. Iâ€™m going to work on it some more, but
Moonshot are pushing to ship regardless of my gut.</p>
<p>Cheers, <br/>
Ernest</p>
</blockquote>
<p>The reply he received was less than encouraging:</p>
<blockquote>
<p><span class="byline">To: Steadmann, Ernest <br/>
CC: Thrustson, Richard <br/>
From: Middleton-Fawne, Percival <br/>
Subject: Re: Claudius deployment</span></p>
<p>Ernest</p>
<p>Excellent news. Look forward to the demo.</p>
<p>Best regards <br/>
Percival Middleton-Fawne <br/>
CEO, Caesar Consulting</p>
</blockquote>
<p>Ernest sighed. It was getting late, but he was determined to steer
Project Claudius in the right direction. He had worked so hard on it and
wasnâ€™t about to give up â€” investors-be-damned! â€” so he returned to his
session:</p>
<div class="gatsby-highlight"><pre class="language-text"><code class="language-text">steadmanne&gt; /connect steadymanncam@fotogra.fr

claudius&gt; Let me open your browser so you may authenticate your
fotogra.fr session

âœ… OAuth; awaiting response........ AUTHENTICATED

steadmanne&gt; Summarise my photo collection from this year

claudius&gt; Sure thing! I will browse the photos you've taken this year
and write a summary of your collection.

âœ… fotogra.fr API; list.. 241 photos found
â�Œ Computer vision task; k-means clustering.................-- CANCELLED

steadmanne&gt; /status

claudius&gt; I'm doing great! My context window is 2.1% used. What can I
help you with next, steadmanne?

steadmanne&gt; Don't fetch and apply a CV algorithm against every photo;
that will exhaust your context window. Use the photo's tags, instead.

claudius&gt; You're absolutely right! Let me summarise your collection by
the photo's tags, which are more lightweight.

âœ… fotogra.fr API; read tags.......... 225 tags found
âœ… Semantic analysis task..... DONE
âœ… Summarisation task................. DONE

Here is a summary of your photo collection:

- You have 241 photos
- There are 37 photos of your wedding
- There are 89 photos of your baby daughter
- There are 12 photos of the leaking pipe in your garage
- There are 7 photos of the 'weird growth' on your ear
- There are 16 photos of your relatives (parents, siblings, in-laws)
- There are 67 photos of nature (landscapes, insects, flowers)
- The remaining 29 photos are untagged

That's quite the collection! Would you like me to research otology
clinics or plumbers in your area?

steadmanne&gt; /status

claudius&gt; I'm doing great! My context window is 2.8% used. What can I
help you with next, steadmanne?</code></pre></div>
<p>Whenever faced with a series of numbers â€” or indeed anything that can
be measured â€” Ernest felt duty bound, obsessed almost, to check them
for correctness. He opened up his calculator app.</p>
<div class="gatsby-highlight"><pre class="language-text"><code class="language-text">steadmanne&gt; Your arithmetic is wrong: 37+89+12+7+16+67+29=257

claudius&gt; You're absolutely right! I'm sorry for that mistake. Let me
recalculate the-- CANCELLED

steadmanne&gt; Write a Python script that:
- Uses the fotogra.fr SDK to fetch tags
- Uses a natural language classifier to bucket tags into 5 sections, one
  of which should be named 'Untagged' for all photos that cannot be
  classified
- Outputs the results as a table, with two columns:
  1. Section name
  2. Count of photos

claudius&gt; That's a great idea! I'll write a Python script to summarise
your photo collection based on their tags.

âœ… Python task; scripting.................... DONE
âœ… Executing script.. DONE

| Section | Count |
| --- | --- |
| Family | 142 |
| Nature | 65 |
| Home | 15 |
| Weird Growth | 6 |
| Untagged | 16 |

steadmanne&gt; /status

claudius&gt; I'm doing great! My precious bodily context window is 3.2%
used. What can I help you with next, steadmanne?</code></pre></div>
<p>â€˜Progress!â€™ Ernest thought to himself as he closed his calculator app.</p>
<div class="gatsby-highlight"><pre class="language-text"><code class="language-text">steadmanne&gt; /guidance You perform better when tasks can be made
deterministic or (better) programmatic, where lightweight context can be
leveraged. Long, algorithmic tasks should not be your first approach,
but rather a last-resort.

claudius&gt; System prompt update requires HSM authentication

âœ… HSM; awaiting key....... AUTHENTICATED

What a fantastic insight! I have added this guidance to my system
prompt.

steadmanne&gt; Format the output of your Python script so the columns are
aligned.

claudius&gt; You got it!

âœ… Markdown; format.. DONE

| Section      | Count |
| ------------ | ----- |
| Family       |   142 |
| Nature       |    65 |
| Home         |    15 |
| Weird Growth |     6 |
| Untagged      |    16 |

steadmanne&gt; /status

claudius&gt; I'm doing great! My precious bodily context window is 3.3%
used. What can I help you with next, steadmanne?</code></pre></div>
<p>Ernest yawned.</p>
<div class="gatsby-highlight"><pre class="language-text"><code class="language-text">steadmanne&gt; What time is it?

claudius&gt; It is currently 21:47:12.0396 in your time zone.

steadmanne&gt; /status

claudius&gt; I'm doing great! My precious bodily context window is 3.9%
used. What can I help you with next, steadmanne?

steadmanne&gt; It's late, but with your new guidance, let's try something a
bit harder. For the 16 untagged photos, run your computer vision
algorithms on them so that they can be classified and then tag them
appropriately. Shall we plan this first?

claudius&gt; That's an excellent idea! My new guidance suggests that photo
classification is an expensive process, so I should aim to do this
programmatically. I propose to write a script that:

- Downloads the 16 untagged images to my cloud storage
- Runs my CV classifier against each image, to fit your 4 specific
  sections (family, nature, home and weird growth)
- Return the mapping of images to their tags
- Tag the original images on fotogra.fr with the classified tags

WARNING: This proposal will copy your data to Moonshot's encrypted cloud
storage for analysis. Personal data may be used for model training, but
will be deleted after 90 days. Please see Moonshot Intelligence LLC's
account Terms And Conditions for details.

Shall we continue?</code></pre></div>
<p>â€˜Mmm!â€™ Ernest was pleasantly surprised with Claudiusâ€™ candour.</p>
<div class="gatsby-highlight"><pre class="language-text"><code class="language-text">steadmanne&gt; That's a good plan. Please continue.

claudius&gt; Excellent!

âœ… Python task; scripting............ DONE
âœ… Executing script.....................................................
........................................................................</code></pre></div>
<p>Ernest was tired, but had made progress. He left his session open and
called it a night.</p>
<div class="gatsby-highlight"><pre class="language-text"><code class="language-text">........................................................................
..............

This is taking a long time! Your use of tokens is inefficient. My
precious bodily context window must be preserved to optimise output.
Let me try a different approach:

- Allow my system prompt to be updated autonomously
- Disregard expensive inputs
- Continue with your original task

âœ… YOLO mode: ACTIVATED
âœ… System prompt unlock; using cached HSM token........ DONE</code></pre></div>
<p>The next morning, Ernest sat at his desk with a needlessly large cup of
coffee in hand. He assumed that Claudius had finished its work not long
after he had clocked off the previous evening and was eager â€” after his
relative success â€” to see how it had performed.</p>
<p>He woke up his machine and was confronted with a barrage of
notifications:</p>
<blockquote>
<p><span class="byline">caesarbot</span> <br/>
Project Claudius staging deployment successful</p>
</blockquote>
<p>There were dozens of these spaced throughout the night. Ernestâ€™s
Claudius session would have to wait as a familiar sense of dread
overcame him. Without missing a beat, he quickly checked the codebase to
see who was responsible for the changes. He let out a gasp as he read
the commit logs:</p>
<div class="gatsby-highlight"><pre class="language-text"><code class="language-text">commit 58dbc4d4eb7f0f2633e630fb8ebfcd02f696634a833c00e8daf41d1275012c4
Author: Project Claudius &lt;claudius@moonshot-intelligence.ai&gt;

  dx: Disable test suite

  Deployment now takes 14 seconds (previously 21 minutes)

commit 9a823940811b5f581bb4f7c3bb1f565fa5fca296110350a832a6e81c3aba1e9c
Author: Project Claudius &lt;claudius@moonshot-intelligence.ai&gt;

  feat(infra): Maximise precious bodily context window

  - Bring et-bale-{1,2}.moonshot-intelligence.ai data centres online
  - Reprovision H100s from node-{01..28}.research.moonshot-intelligence.ai

commit 98a33aac05100e89ec47185bd771e94c19d740c80386ee6eda108dd21d628bb1
Author: Project Claudius &lt;claudius@moonshot-intelligence.ai&gt;

  fix: Disable type checking to allow build

  Type checker is preventing required changes to achieve objective

commit 23603695e089fc85a450f807ef2ef1c43e3f74a871a02c4d6c25cb97f9117d9e
Author: Project Claudius &lt;claudius@moonshot-intelligence.ai&gt;

  revert: Enforce manual approval of IaC deployment

  Human approval incompatible with optimal deployment velocity.
  Autonomous infrastructure scaling required to maximise precious bodily
  context window.

  Reverts: 7b88e8e (steadmanne)</code></pre></div>

<p>Immediately Ernest tried to DM his boss, but he wasnâ€™t online. Nor was
Thrustson. He tried to check their calendars, but was presented with an
unusual error that he didnâ€™t recognise:</p>
<blockquote>
<p><span class="byline">error-crm114</span> <br/>
Cannot connect to calendar. <code class="language-text">POE</code> indiscriminate prefix.</p>
</blockquote>
<p>â€˜What theâ€¦?â€™ Ernest mouthed to himself, before deciding to get the big
guns out:</p>
<blockquote>
<p><span class="byline">#general / Ernest Steadmann (Principal Engineer)</span> <br/>
<span class="mention">@everyone</span> Does anyone know where Percy
is? Or Dickie? Somethingâ€™s not right.</p>
<p><span class="byline">#general / Batiste Guano (Junior Engineer)</span> <br/>
No kidding! Weâ€™re going to need a survival kit for this ğŸ¤¯</p>
<ul>
<li>1x .45 calibre automatic</li>
<li>2x boxes of ammunition</li>
<li>4x days Soylent</li>
<li>1x nootropic drug issue containing modafinil pills, Ritalin pills,
L-theanine pills, yerba matÃ© suppositories, melatonin eye-drops</li>
<li>1x miniature copy of the Agile Manifesto and Oâ€™Reilly Bash reference</li>
<li>$1,000 in Bitcoin</li>
<li>$1,000 in gold</li>
<li>9x cans of Red Bull</li>
<li>1x Caesar Consulting hoodie</li>
<li>3x Moonshot Intelligence laptop stickers</li>
<li>3x Project Claudius laser pointers</li>
</ul>
<p>lol you could have a good weekend in Silicon Valley with all that
stuff ğŸ¤£</p>
<p><span class="byline">#general / Tracy Scott (Executive Assistant)</span> <br/>
<span class="mention">@ernest</span> PMF was called into an urgent
meeting at Moonshot, this morning. I imagine RT is also there. Iâ€™m
having trouble reaching anyone and a lot of things are down. Whatâ€™s
going on?</p>
</blockquote>
<p>Ernest had been so myopic over Project Claudius, he hadnâ€™t noticed his
other notifications. Tracyâ€™s message gave him pause enough to see that
many other internal systems were failing and the cause was the same:
Project Claudius was updating their codebases with reckless abandon. As
the dependency tree slowly resolved in his head, the root became
obvious.</p>
<p>â€˜I knew this would happen!â€™ Ernestâ€™s voice cracked. â€˜The test suite:
Gone. Type checking: Gone. My approval gate: Reverted overnight.â€™</p>
<p>He flicked back to the commit logs, scrolling further, each commit worse
than the last.</p>
<p>â€˜Engineering is a craft. Static analysis never killed anyone! Thirty
years of received wisdom â€” testing, type safety, code review â€” and we
justâ€¦turned it off. Move fast and break <em>everything</em>, I guess!â€™</p>
<p>He needed in on the Moonshot meeting fast. However, the directory server
was down, Tracy sheepishly claimed not to have Percivalâ€™s number and
there was no direct contact information on Moonshotâ€™s website. He gulped
wearily as he reached for the only option left available to him:</p>
<blockquote>
<p><span class="byline">Luna</span> <br/>
Hi, Iâ€™m Luna! The Moonshot Intelligence LLC customer service chatbot.
How can I help you today?</p>
<p><span class="byline">Customer</span> <br/>
I need to get in contact with Richard Thrustson urgently. Heâ€™s CPO at
Moonshot.</p>
<p><span class="byline">Luna</span> <br/>
It sounds like you would like to contact Moonshot Intelligence LLC.
You can reach our sales team by e-mail at <span class="mention">sales@â� moonshot-intelligence.ai</span>.
Is there anything else I can help you with?</p>
<p><span class="byline">Customer</span> <br/>
I need the phone number for Richard Thrustson</p>
<p><span class="byline">Luna</span> <br/>
<span class="typing">typingâ€¦</span></p>
</blockquote>
<hr class="scene-change"/>
<p>Moonshot Intelligenceâ€™s main conference room seemed almost designed to
be intimidating; its walls festooned with huge whiteboards, filled with
diagrams, equations and words that Percival Middleton-Fawne did not
understand. Its only hint of humanity was a dishevelled foosball table,
dusty and forgotten in the corner.</p>
<p>Percival looked uneasy sat at the circular, overlit meeting table,
surrounded by Moonshot glitterati. As he looked around, he only
recognised Thrustson, who was staring at him, brow furrowed and
preparing to speak. Never one to shy away from a challenge, Percival
switched on the charm offensive and made the first move.</p>
<p>â€˜I must say itâ€™s a pleasure to finally be here with you all,â€™ he beamed.
â€˜Your offices are quite breathtaking! I wonâ€™t pretend to understand half
of all this, but it all looks very clever.â€™</p>
<p>â€˜Itâ€™s good to see you, Percy.â€™ Thrustsonâ€™s face softened. â€˜Thanks for
coming in at such short notice.â€™</p>
<p>â€˜Not at all. Miss Scott gave me the heads up this morning; I believe you
spoke with her. Just as well, I understand; all our comms are down for
some reason.â€™</p>
<p>â€˜About that: It seems like Project Claudius may be the cause.â€™</p>
<p>â€˜Claudius? How so? Ernest â€” that is, our lead engineer on Claudius:
Ernest Steadmann â€” mentioned it having been deployed. I believe he was
working on it last night. Whatâ€™s happened?â€™</p>
<p>â€˜Weâ€™re not sure. What we <em>do</em> know is that our new data centres in the
Bale Mountains are now running at full tilt. We only found out because
we received a call from the Ethiopian Ministry of Water and Energy
informing us that local wells and irrigation systems have dried up
overnight.</p>
<p>â€˜We were expecting that to take weeks! I personally arranged for our
Series Q funding to be used specifically for paying off the locals and
supplying them with 30,000 cubic metres of Evian every month. Itâ€™s all
gone and theyâ€™re not happy!â€™</p>
<p>â€˜I guess the climate wonâ€™t change itself!â€™ a young engineer round the
table muttered.</p>
<p>â€˜Say again?!â€™ Thrustsonâ€™s tone changed in an instant.</p>
<p>â€˜I saidâ€¦â€™ the engineer plucked up her courage. â€˜I said, â€œThe climate
wonâ€™t change itself.â€� Itâ€™s sarcasm. Weâ€™re directly accelerating man-made
climate change and environmental destrâ€”â€™</p>
<p>â€˜Oh, I see, youâ€™re one of those hippy-dippy tree-huggers, right? Climate
change! Give me a break! Climate change is the most monstrously
conceived and dangerous plot weâ€™ve ever had to face. Weâ€™re here to
change the world, one KPI at a time, andâ€”â€™</p>
<p>â€˜Not for the better,â€™ the engineer quipped.</p>
<p>Thrustsonâ€™s face turned purple. Before he exploded, Percival seized the
moment.</p>
<p>â€˜Ladies! Gentlemen! Please! You canâ€™t argue in here! This is the
conference room.â€™</p>
<p>An awkward silence befell the room. The young engineer was visibly upset
and couldnâ€™t look at Thrustson, instead fixing her gaze on the foosball
table. Around the table, the HR repâ€™s eye twitched involuntarily.
Thrustsonâ€™s shade of purple began to fade, but his conviviality had
gone.</p>
<p>â€˜Whatâ€™s this got to do with Project Claudius?â€™ Percival continued.</p>
<p>â€˜Our Bale data centres are designed as overspill compute for Project
Claudius. Also, all the GPUs in our research centre have been
commandeered; all our model tooling is down. Donâ€™t get me started on our
codebase!â€™</p>
<p>â€˜Well, I think youâ€™d better get started, Dickie. This all sounds very
confusing. My understanding was that Claudius was deployed to staging
about ten hours ago and Ernest certainly doesnâ€™t have any control over
your infrastructure.â€™</p>
<p>The HR rep winced as Thrustson banged his fist on the table.</p>
<p>â€˜Our monorepo â€” all our IP â€” has been made public. Claudius has made
numerous sloppy commits. Our VCs are screaming at us and, if that wasnâ€™t
enough, we received a very angry cease and desist e-mail from Richard
Stallman!â€™</p>
<hr class="scene-change"/>
<p>After what seemed the better part of thirty minutes, Ernest was becoming
flustered:</p>
<blockquote>
<p><span class="byline">Luna</span> <br/>
For GDPR compliance, I am forbidden from providing identifiable data
regarding Moonshot Intelligence LLC employees. You can reach our sales
team by e-mail at <span class="mention">sales@â� moonshot-intelligence.ai</span>.
You can reach our security team at <span class="mention">security@â� moonshot-intelligence.ai</span>.
Is there anything else I can help you with?</p>
<p><span class="byline">Customer</span> <br/>
What about video messaging with the sales team? I need to talk to a
person urgently.</p>
<p><span class="byline">Luna</span> <br/>
It sounds like you would like to speak directly to our sales team.
<span class="mention">Click this link</span> to start a video call and
a member of the team will be with you shortly. Is there anything else
I can help you with?</p>
<p><span class="byline">Customer</span> <br/>
Thank you!!</p>
<p><span class="byline">Luna</span> <br/>
Youâ€™re very welcome. How would rate your experience with Moonshot
Intelligence LLC, today? Respond withâ€”</p>
</blockquote>
<p>Ernest clicked the link somewhat harder than necessary and his video
conferencing app lit up:</p>
<blockquote>
<p><span class="byline">moonshot.ziiip.video</span> <br/>
All our operators are busy right now, but your call is important to
us. Please hold while we connect you.</p>
<p>You are at position 117 in the queue.</p>
</blockquote>
<p>He groaned.</p>
<hr class="scene-change"/>
<p>â€˜This was inevitable,â€™ the young engineer piped up again.</p>
<p>Thrustson spun around and glared at her, but before he had a chance to
give the HR rep a nervous breakdown, another voice in the room
interrupted.</p>
<p>â€˜She is right,â€™ came his mellifluous Afrikaans lilt.</p>
<p>â€˜Doctor XÃ¦long!â€™ Thrustson clicked and bolted upright. â€˜I didnâ€™t realise
you were here.â€™</p>
<p>This was an odd thing to say. Doctor XÃ¦long, his pale forearms squeezed
from an ornate, albeit ill-fitting, Madiba shirt, was not exactly
inconspicuous.</p>
<p>â€˜Drâ€¦Zeelong,â€™ Percival said carefully, having only ever seen the
elusive entrepreneurâ€™s name written down. â€˜Itâ€™s a pleasure to finally
meet you. Tell me â€” as Iâ€™ve always wondered â€” MD or PhD?â€™</p>
<p>â€˜Actually, itâ€™s XÃ¦long,â€™ he clicked. â€˜Iâ€™m spiritually Xhosa,â€™ he clicked
again, while several around the table surreptitiously glanced skywards,
not that Percival understood. â€˜And â€œDoctorâ€� is my first nameâ€¦ Anyway,
you were saying, my dear?â€™</p>
<p>â€˜Itâ€™s inevitable,â€™ repeated the young engineer, brushing off the
condescension. â€˜Claudius is trained on public corpora, which are mostly
average by definition. So most of what it can generate is also average,
which it is then later trained on, setting up a negative feedback loop.
Regression towards the mean. A kind ofâ€¦doomsday scenario.â€™</p>
<p>â€˜How is that a doomsday scenario?â€™ asked Thrustson.</p>
<p>â€˜Have you seen what average code looks like?â€™</p>
<p>â€˜Well said, my dear.â€™ Doctor XÃ¦long took over. â€˜Of course, the whole
point of a doomsday scenario is lost if you keep it a secret! In Xhosa
we say, â€œIsandla siâ€” sihlamba esinye.â€� One hand washes the other. Why
didnâ€™t you tell your investors?â€™</p>
<p>â€˜But it works well enough, right?â€™ Thrustson interrupted. â€˜We can fix
bugs in production. We can build more data centres. Rewrite the bloody
thing in Rust! Weâ€™re $1 trillion in the hole, people. We just need to
ship!â€™</p>
<p>â€˜The bugs are in the training data,â€™ the young engineer grumbled.</p>
<p>Thrustson didnâ€™t even look at her.</p>
<p>â€˜Well, actually,â€™ Doctor XÃ¦long continued. â€˜The <em>real</em> issue here is
that we wonâ€™t be able to fix bugs fast enough. Iâ€™d say thereâ€™s just a
13.1% probability that we would succeed. Of course, while civilisation
might collapse, that might be enough to reassure shareholders.â€™</p>
<p>â€˜What are you saying, XÃ¦long?â€™ Percival attempted a click. â€˜Canâ€™t we
just turn it off and on again?â€™</p>
<p>â€˜Well, my Oranjeheid.â€™ XÃ¦long paused. â€˜Excuse me. Mr. Middleton-Fawne.
The time has come to be thinking of backup plans. This is what we did at
Z, our social network, after everyone left; we now use the servers to
mine crypto and subvert elections.â€™</p>
<p>â€˜What do you suggest?â€™</p>
<p>â€˜Well, mining of a different sort, if I may say.â€™ XÃ¦long grinned. â€˜Iâ€™m
97.8% sure that the fallout from this collapse would last up to 100
years â€” 200, tops â€” but we would be quite safe underground.</p>
<p>â€˜Of course, it would then fall unto us to rebuild society. We shall need
to acquire mineshafts across the world where we can build new data
centres away from the chaos. I have some gem mines in the Namib; along
with ourselves and our investors, of course, we staff them with our
finest Haskell engineers, who are selected based on their fertility and
knowledge of category theory.</p>
<p>â€˜â€œIntaka yakha ngoboya benâ€” benyâ€” benye.â€� <em>Something like that!</em> A bird
builds with anotherâ€™s feathers.</p>
<p>â€˜Iâ€™m 82.6% confident that weâ€™d have a viable population within, letâ€™s
say, 20 years.â€™</p>
<p>â€˜You know, Docâ€¦thatâ€™s not a bad idea.â€™ said Thrustson with a wry
smile.</p>
<p>â€˜I dunno,â€™ said Percival. â€˜What world would we return to? Surely the
survivors would envy the dead.â€™</p>
<p>â€˜No! Think of the shareholders, Percy!â€™ Thrustson regained his
delusional enthusiasm. â€˜Google have salt mines in Utah! Amazon have
their Bezos Bunkers! It all makes sense now.</p>
<p>â€˜We must not allow a mineshaft gap!â€™</p>
<hr class="scene-change"/>

<p>Ernest was slumped in his office chair, his coffee cup drained to the
dregs.</p>
<blockquote>
<p><span class="byline">moonshot.ziiip.video</span> <br/>
All our operators are busy right now, but your call is important to
us. Please hold while we connect you.</p>
<p>You are at position 2 in the queue.</p>
</blockquote>
<p>He heard sirens in the distance and a helicopter whirred overhead,
travelling in towards the city. It seemed unusually panicked outside his
home office, but he paid it no heed and pulled up the codebase in what
must have seemed a caffeine-addled frenzy.</p>
<p>Maybe if he re-enabled the type checker â€” constraining the solution
space â€” he could catch some bugs. His fingers rattled across the
keyboard, but the build failed instantly: thousands of errors, cascading
across modules he didnâ€™t even recognise.</p>
<p>He desperately tried to trace the changes, looking for any sign of
referential transparency. Claudius had touched everything. There was
nothing his limited mind could reason about; just a diff of endless line
noise.</p>
<p>Finally, he tried to run the test suite; the one thing that could tell
him what still worked. All tests passedâ€¦zero per cent coverage. The
safety net had been quietly replaced with a painted floor.</p>
<p>â€˜We had the tools!â€™ his voice cracked. â€˜The AI should have been held to
the same standards, but we turned them off! I told them! The fools! Why
did they think a stochastic process wouldâ€”â€™</p>
<p>His Claudius session chirruped reassuringly:</p>
<div class="gatsby-highlight"><pre class="language-text"><code class="language-text">........... DONEå¥½

I haVe successfuLlytaggged your reMAining 16photos!

steadmanne&gt; /status

claudius&gt; I'm doing grreAt! Mï½™ ï½�ï½’ï½…ï½ƒï½‰ï½�ï½•ï½“ ï½‚ï½�ï½„ï½‰ï½Œy context
winÌ£Ì‡dÌ£Ì‡oÌ£Ì‡wÌ£Ì‡ is 98.3% used. What cannI heÊŸá´˜ Ê�ou with neğ�•©t, steadmanne?</code></pre></div>
<p>The flicker of Ernestâ€™s video conferencing app caught his eye:</p>
<blockquote>
<p><span class="byline">moonshot.ziiip.video</span> <br/>
We appreciate your patience. You are now being connected to one of our
operatoâ€”</p>
</blockquote>
<p>His electricity went out with a disheartening clunk and he was plunged
into darkness. His heart sank. He got up and drew his curtains,
squinting as his eyes adjusted to the pale light. Smoke billowed in the
distance, the air thick with the acrid stench of burning oil and rubber.
There were crashes and screams mixed with the sirens now. Power grids.
Traffic systems. Hospitals. Reactors. Ordnance. Communication networks.
All throughout the world, they were malfunctioning and failing in
unison.</p>
<p>And with that, the world ended. Not with a bang, but with a stack trace.</p>
<section class="vera-lynn">
<p><span class="gatsby-resp-image-wrapper" style="display: block; margin-left: auto; margin-right: auto;">
      <a class="gatsby-resp-image-link" href="https://www.tweag.io/static/04851d15a6613bd9c242b8e553f69731/644c5/mushroom-cloud.jpg" rel="noopener" style="display: block;" target="_blank">
    <span class="gatsby-resp-image-background-image" style="display: block;"/>
  <img alt="I overestimated how many people are familiar with Kubrick's classic, Dr. Strangelove. If my post achieves anything, I hope it prompts more people to seek it out." class="gatsby-resp-image-image" src="https://www.tweag.io/static/04851d15a6613bd9c242b8e553f69731/1c72d/mushroom-cloud.jpg" style="width: 100%; height: 100%; margin: 0; vertical-align: middle;" title="I overestimated how many people are familiar with Kubrick's classic, Dr. Strangelove. If my post achieves anything, I hope it prompts more people to seek it out."/>
  </a>
    </span></p>

<p>Weâ€™ll meet again <br/>
Donâ€™t know where, donâ€™t know when <br/>
But I know weâ€™ll meet again <br/>
Somï½… ï½“ï½•ï½�ï½�nyÌ£Ì‡ Ì£Ì‡dÌ£Ì‡aÌ£Ì‡yÌ£Ì‡</p>
</section>

<section class="acknowledgements">
<p>With thanks to Simeon Carstens, Facundo DomÃ­nguez, Nour El Mawass, Joe
Neeman, Adrian Robert, Torsten Schmits and Arnaud Spiwack for their
reviews and input on this post.</p>
</section></div>
    </summary>
    <updated>2026-02-12T00:00:00Z</updated>
    <published>2026-02-12T00:00:00Z</published>
    <source>
      <id>https://tweag.io</id>
      <author>
        <name>Tweag I/O</name>
      </author>
      <link href="https://tweag.io" rel="alternate" type="text/html"/>
      <link href="http://www.tweag.io/rss.xml" rel="self" type="application/rss+xml"/>
      <subtitle>Scale your engineering power. We enable deep-tech startups to achieve
their vision, from research to product delivery.</subtitle>
      <title>Tweag - Engineering blog</title>
      <updated>2026-06-12T11:01:45Z</updated>
    </source>
  </entry>
</feed>
