<?xml version="1.0"?>
<rss version="2.0">

<channel>
	<title>Planet Haskell</title>
	<link>http://planet.haskell.org/</link>
	<language>en</language>
	<description>Planet Haskell - http://planet.haskell.org/</description>

<item>
	<title>Oskar Wickström: How Antithesis Found and Explained a Bombadil Race Condition</title>
	<guid isPermaLink="true">https://wickstrom.tech/2026-08-07-bombadil-race-condition-antithesis.html</guid>
	<link>https://wickstrom.tech/2026-08-07-bombadil-race-condition-antithesis.html</link>
	<description>&lt;p&gt;&lt;em&gt;Disclosure: I’m the original author and lead for the Bombadil project at Antithesis.&lt;/em&gt;&lt;/p&gt; &lt;p&gt;&lt;a href=&quot;https://catala.dev/&quot;&gt;Carlos Catala&lt;/a&gt;, interning at Antithesis and working on testing our webapps, found a strange crash while I was out camping. The tests he works on runs Antithesis’ webapp &lt;em&gt;inside Antithesis&lt;/em&gt; and explores it using Bombadil. That surfaced a particular sequence of events leading up to the following crash (logs are simplified for readability):&lt;/p&gt; &lt;pre&gt;&lt;code&gt;state machine error: unhandled transition: Running(10) + ActionAccepted(Click(&quot;Filters&quot;))&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;What does this mean? To understand it, we need to back up a little.&lt;/p&gt; &lt;p&gt;The heart of the browser &lt;em&gt;driver&lt;/em&gt; is a finite state machine, an abstract model of a tab in Chrome or Chromium, and how we’re interacting with it over CDP. This is necessary due to how you can only invoke certain commands in certain browser states, or it might hang or behave in other confounding ways. In our state machine, some transitions are valid, and those are handled in a big &lt;code&gt;match (state, event) { ... }&lt;/code&gt; expression that returns a new state. Invalid transitions are covered by the last branch that returns an &lt;code&gt;Err&lt;/code&gt; with a message like the above.&lt;/p&gt; &lt;p&gt;There’s another important component involved which is called the &lt;em&gt;runner&lt;/em&gt;. It decides the control flow of the test, and uses the driver to run the system under test. The driver emits a state, and the runner decides what action to take in that state. It hands back the action to the driver so that it can apply it. The browser driver actually pauses the JS runtime when capturing a state, and doesn’t resume execution until the driver has given back the next action.&lt;/p&gt; &lt;p&gt;Hence, the &lt;code&gt;ActionAccepted&lt;/code&gt; event (which is when the driver gets a new action from the runner) is not valid in the &lt;code&gt;Running&lt;/code&gt; state. It really is only valid in the &lt;code&gt;Paused&lt;/code&gt; state. How could this happen? The driver and runner are supposed to operate in lock-step, where the driver is only in control while the JS runtime is paused. This was the nut to crack.&lt;/p&gt; &lt;p&gt;When Carlos told me about this during my PTO, my camping brain was definitely not helpful, so I let it rest until I was back at work. Staring at logs and code also didn’t help much, except for a poorly conceived theory about what could be going on, mislead by the presence of &lt;a href=&quot;https://antithesis.com/docs/product/fault_injection/fault_types/#network-faults&quot;&gt;network faults&lt;/a&gt; in one test where we saw the bug. We tried but failed to reproduce this locally, so I decided to find a simpler test subject and, crucially, try to reproduce it in Antithesis.&lt;/p&gt; &lt;h2 id=&quot;a-simple-reproduction-with-causality-analysis&quot;&gt;A Simple Reproduction with Causality Analysis&lt;/h2&gt; &lt;p&gt;To reduce possible confusion I wanted to first see if I could trigger the same bug in Bombadil with a simpler system under test. I found a Dockerized version of &lt;a href=&quot;https://the-internet.herokuapp.com/&quot;&gt;the-internet&lt;/a&gt;, an example application by Sauce Labs made for automated browser testing. Based on what we had seen before, I wrote a very small specification that only performs three actions:&lt;/p&gt; &lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot;&gt;&lt;pre class=&quot;sourceCode typescript&quot;&gt;&lt;code class=&quot;sourceCode typescript&quot;&gt;&lt;span id=&quot;cb2-1&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb2-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;im&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;im&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;@antithesishq/bombadil/browser/defaults/properties&quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt; &lt;span id=&quot;cb2-2&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb2-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;im&quot;&gt;import&lt;/span&gt; { weighted } &lt;span class=&quot;im&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;@antithesishq/bombadil/browser&quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt; &lt;span id=&quot;cb2-3&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb2-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;im&quot;&gt;import&lt;/span&gt; {&lt;/span&gt; &lt;span id=&quot;cb2-4&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb2-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; back&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span id=&quot;cb2-5&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb2-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; forward&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span id=&quot;cb2-6&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb2-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; clicks&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span id=&quot;cb2-7&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb2-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;} &lt;span class=&quot;im&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;@antithesishq/bombadil/browser/defaults/actions&quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt; &lt;span id=&quot;cb2-8&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb2-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt; &lt;span id=&quot;cb2-9&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb2-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;im&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;const&lt;/span&gt; navigation &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;weighted&lt;/span&gt;([&lt;/span&gt; &lt;span id=&quot;cb2-10&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb2-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; [&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; clicks]&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span id=&quot;cb2-11&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb2-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; [&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; back]&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span id=&quot;cb2-12&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb2-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; [&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; forward]&lt;/span&gt; &lt;span id=&quot;cb2-13&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb2-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;])&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; &lt;p&gt;In addition to finding various bugs in the Ruby code, it also immediately reproduced the Bombadil bug! Time to dig in. I went through a few instances and started to see a pattern. In addition, this gave me an excellent opportunity to try out &lt;a href=&quot;https://antithesis.com/docs/product/debugging/causality_analysis/&quot;&gt;Causality Analysis&lt;/a&gt;, a mind-bending feature for learning what behavior increases the likelihood of a bug appearing. Here’s the report I got:&lt;/p&gt; &lt;figure&gt; &lt;img alt=&quot;The causality analysis report plots the likelihood and helps you understand what events caused a certain bug.&quot; src=&quot;https://wickstrom.tech/assets/causality-analysis.webp&quot; /&gt; &lt;figcaption&gt;The causality analysis report plots the likelihood and helps you understand what events caused a certain bug.&lt;/figcaption&gt; &lt;/figure&gt; &lt;p&gt;As you may see in the chart, there are three points where the probability increases markedly. Correlating those with the logs (which is easy, you see the bumps highlighted in the log too), I could find the chain leading up to the bug:&lt;/p&gt; &lt;ol type=&quot;1&quot;&gt; &lt;li&gt;Click a link that navigates to &lt;code&gt;/frames&lt;/code&gt; (probability goes to 20%)&lt;/li&gt; &lt;li&gt;On that page, click a link that navigates to &lt;code&gt;/iframe&lt;/code&gt; (probability goes to 47%)&lt;/li&gt; &lt;li&gt;Go back (I was a bit surprised that this didn’t bump probability noticeably)&lt;/li&gt; &lt;li&gt;Go forward (probability goes to 99.98%)&lt;/li&gt; &lt;/ol&gt; &lt;p&gt;After the last “Go forward” action, it’s a done deal. Digging into the details in between these points, I could then see how going back to a page which immediately throws an exception, after restoring from &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/bfcache&quot;&gt;bfcache&lt;/a&gt;, takes a different path than most page loads do.&lt;/p&gt; &lt;h2 id=&quot;the-bug&quot;&gt;The Bug&lt;/h2&gt; &lt;p&gt;When going back or forward in history, the state machine immediately transitions to &lt;code&gt;Running&lt;/code&gt;, waiting for confirmation by the browser to know what actually happened. Some pages prevent bfcache through JavaScript or HTTP headers, so a history navigation can also end up as a full page load with new HTTP requests. When the page is confirmed to have been restored from bfcache, the page and thus the state machine model skips the &lt;code&gt;Loading&lt;/code&gt; state entirely, and goes straight to &lt;code&gt;Running&lt;/code&gt;.&lt;/p&gt; &lt;p&gt;In this case, that was followed by the exception being thrown immediately (you can see it in the bottom of the screenshot above), which triggers another path: exceptions thrown while in &lt;code&gt;Running&lt;/code&gt; aren’t collected and reported at a later state capture, as is the case for the &lt;code&gt;Loading&lt;/code&gt; state — they immediately pause the runtime and trigger a new state read. This in turn let the runner pick a new action to perform. But the CDP event that confirms that the page was restored from bfcache hadn’t arrived yet.&lt;/p&gt; &lt;p&gt;This is a race between the asynchronous communication of runner and browser state machine, selecting the next action, and the CDP event sent by Chromium over a WebSocket confirming the bfcache restore. The unfortunate ordering that triggers the bug is:&lt;/p&gt; &lt;ol type=&quot;1&quot;&gt; &lt;li&gt;Back or forward, restoring from bfcache&lt;/li&gt; &lt;li&gt;Exception thrown on restored page, pausing the debugger and capturing a new state&lt;/li&gt; &lt;li&gt;Runner picking a new action and passing it back to the browser state machine&lt;/li&gt; &lt;li&gt;Confirmation of bfcache restoration coming in, transitioning state machine to &lt;code&gt;Running&lt;/code&gt;&lt;/li&gt; &lt;li&gt;State machine applying the &lt;code&gt;ActionAccepted&lt;/code&gt; event, which, as we noted in the beginning of this excursion, is not valid when in &lt;code&gt;Running&lt;/code&gt;&lt;/li&gt; &lt;/ol&gt; &lt;p&gt;This sequence causes the crash. It only happens with bfcache-enabled history navigation to a page with an exception being thrown before the confirmation from Chromium comes back. Antithesis’ deterministic fuzzing environment messes with process scheduling and action selection and discovers this sequence reliably.&lt;/p&gt; &lt;h2 id=&quot;in-conclusion&quot;&gt;In Conclusion&lt;/h2&gt; &lt;p&gt;I’m not going to describe the fix in too much detail, but it involves a more robust use of the already existing &lt;code&gt;Generation&lt;/code&gt; value in the browser state machine. It’s a monotonically increasing number that is used to detect stale timeouts and actions, so that the state machine can discard them. The browser state now carries the current generation, and that is threaded through the runner’s action selection process, so that a stale action (as in step 5 above) can be safely ignored. Additionally, some transitions now increment the generation in cases where all existing timeouts or actions are stale.&lt;/p&gt; &lt;p&gt;I’ve had bugs of this kind before, and understanding them from staring at logs, let alone reproducing them, has been painful. This, in contrast, feels a bit like cheating. Moreover, it extends to race conditions and complicated bugs in the webapps themselves, which makes me very excited about continued work on the Bombadil and Antithesis integration.&lt;/p&gt;</description>
	<pubDate>Thu, 06 Aug 2026 22:00:00 +0000</pubDate>
</item>
<item>
	<title>Mark Jason Dominus: The road to epsilon-zero: Coin-moving games with no coins</title>
	<guid isPermaLink="false">tag:,2026:/math/ordinals/04-coordinates</guid>
	<link>https://blog.plover.com/math/ordinals/04-coordinates.html</link>
	<description>&lt;p&gt;Previously:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.plover.com/math/epsilon-zero.html&quot;&gt;Ordinal numbers and basic set theory &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.plover.com/math/ordinals/01-nim.html&quot;&gt;Ordinals as nim-heaps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.plover.com/math/ordinals/02-wellfoundedness.html&quot;&gt;Nim always ends, even with infinite ordinals&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.plover.com/math/ordinals/03-track-tokens.html&quot;&gt;Infinite Nim as a coin-moving game&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the previous article we saw how to interpret Nim heaps of up to
&lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%5e2%24&quot; /&gt; beans as coins on a quarter-infinite array:&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;center&quot; src=&quot;https://pic.blog.plover.com/math/ordinals/04-coordinates/strip-%CF%89%C2%B2.svg&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The coin here represents a heap of &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%c2%b73%20%2b%202%24&quot; /&gt; beans.  The heap can be
reduced to any smaller number of beans.  In the coin version of the
game, this corresponds to moving the coin to any square to the left
in the same row, or to &lt;strong&gt;any&lt;/strong&gt; square in &lt;strong&gt;any lower row&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To extend this past &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%5e2%24&quot; /&gt;, though, was a little clumsy. We had to
pile up an infinite stack of these grids, and that got us only to
&lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%5e3%24&quot; /&gt;.  Then to go further we had to move into the fourth dimension,
and to get all the way to &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%5e%cf%89%24&quot; /&gt; we had to imagine a sort of discrete
Hilbert space with an infinite number of dimensions, not easy. I
personally have trouble imagining anything with more than about &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%2417%24&quot; /&gt;
dimensions, and an infinite number of dimensions is a couple more than I
can handle comfortably.&lt;/p&gt;

&lt;p&gt;We can do better.  Instead of imagining a grid of squares with coins
on the squares, just write the coordinates of the coin!  The one
above, representing a pile of &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%c2%b73%2b2%24&quot; /&gt; beans,
is simply $$⟨2, 3⟩.$$&lt;/p&gt;

&lt;p&gt;A game of infinite Nim is now simply a list of these pairs, one for each
coin.   A legal move is to pick one of the pairs and:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;reduce the first coordinate, which corresponds to moving the coin to
the left in the same row, or&lt;/li&gt;
&lt;li&gt;reduce the second coordinate (which moves it to a lower row) &lt;strong&gt;and&lt;/strong&gt; replace the first coordinate with any
number at all, even a larger one (any square in the lower row is allowed)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Moving from &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%c2%b73%2b2%24&quot; /&gt; to &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%c2%b73%2b1%24&quot; /&gt; uses the first rule to reduce the
first coordinate from &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%e2%9f%a82%2c%203%e2%9f%a9%24&quot; /&gt; to &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%e2%9f%a81%2c%203%e2%9f%a9%24&quot; /&gt;.
Moving from &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%c2%b73%2b2%24&quot; /&gt; to &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%c2%b72%2b17%24&quot; /&gt; uses the second rule to reduce the
second coordinate from &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%e2%9f%a82%2c%203%e2%9f%a9%24&quot; /&gt; to &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%e2%9f%a82%2c%202%e2%9f%a9%24&quot; /&gt; and simultaneously replace the first
coordinate with &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%2417%24&quot; /&gt;, leaving the coin on &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%e2%9f%a817%2c%202%e2%9f%a9%24&quot; /&gt;.&lt;/p&gt;

&lt;p&gt;Removing the entire pile uses the second rule to reduce the second
coordinate from &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%e2%9f%a82%2c%203%e2%9f%a9%24&quot; /&gt; to &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%e2%9f%a82%2c%200%e2%9f%a9%24&quot; /&gt; and simultaneously replace the first
coordinate with &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%240%24&quot; /&gt;, yielding &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%e2%9f%a80%2c%200%e2%9f%a9%24&quot; /&gt;.&lt;/p&gt;

&lt;p&gt;To stack up multiple grids no longer requires third dimension, just a
third coordinate.  To make it compatible with the two-coordinate
notation, we just agree to understand &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%e2%9f%a8a%2c%20b%e2%9f%a9%24&quot; /&gt; as an abbreviation
for &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%e2%9f%a8a%2c%20b%2c%200%e2%9f%a9%24&quot; /&gt;.  The move rule generalizes to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pick any nonzero coordinate&lt;/li&gt;
&lt;li&gt;Reduce it by at least 1&lt;/li&gt;
&lt;li&gt;Replace any coordinates to the left of that one with any numbers
at all&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For example, we can move from &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%e2%9f%a82%2c%203%2c%200%e2%9f%a9%24&quot; /&gt; to &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%e2%9f%a817%2c%202%2c%200%e2%9f%a9%24&quot; /&gt; (the
&lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%243%24&quot; /&gt; has decreased), or from &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%e2%9f%a82%2c%203%2c%209%e2%9f%a9%24&quot; /&gt; to &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%e2%9f%a81000%2c%200%2c%207%e2%9f%a9%24&quot; /&gt; (the
&lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%249%24&quot; /&gt; has decreased).&lt;/p&gt;

&lt;p&gt;To go into the fourth dimension and beyond is similarly easy: just
allow a list of coordinates of &lt;em&gt;any&lt;/em&gt; finite length, and use the same
rule as above: reduce any single coordinate, and simultaneopusly
replace any or all of the coordinates to its left.&lt;/p&gt;

&lt;p&gt;For example, &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%5e7%20%2b%20%cf%89%5e3%c2%b712%20%2b%20%cf%89%5e2%20%2b%20%cf%89%20%2b%2083%24&quot; /&gt; is now represented as
&lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%e2%9f%a883%2c%201%2c%201%2c%2012%2c%200%2c%200%2c%200%2c%201%e2%9f%a9%24&quot; /&gt;.  We can also imagine there is a
trailing sequence of zeroes, of either finite or infinite length, but
they don't affect the game.&lt;/p&gt;

&lt;p&gt;Maybe it's easier to see now why this enormous nim-heap must eventually be
removed.  On the first move, someone must either reduce that &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%2483%24&quot; /&gt; or
else one of the numbers to the right of it.  But the players can't
indefinitely put
off reducing one of the other numbers; if they work only on the
&lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%2483%24&quot; /&gt;, then after at most &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%2483%24&quot; /&gt; they will have arrived at
&lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%e2%9f%a8%7b%5cbf%200%7d%2c%201%2c%201%2c%2012%2c%200%2c%200%2c%200%2c%201%e2%9f%a9%24&quot; /&gt;, and then someone &lt;em&gt;must&lt;/em&gt; reduce one
of the other numbers, since moves from &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%240%24&quot; /&gt; aren't allowed.&lt;/p&gt;

&lt;p&gt;The &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%2483%24&quot; /&gt; can be
increased, but only at the cost of reducing a farther-right number.
But that's true of &lt;em&gt;every&lt;/em&gt; number except the final &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%241%24&quot; /&gt;.  And however
long the players avoid reducing that final &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%241%24&quot; /&gt;, by reducing numbers
farther left — and it might be a very, very, very long time —
eventually they will get to &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%e2%9f%a80%2c%200%2c%200%2c%200%2c%200%2c%200%2c%200%2c%201%e2%9f%a9%24&quot; /&gt; and won't be
able to put it off any longer.&lt;/p&gt;

&lt;p&gt;To get ordinals up to &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%5e%cf%89%24&quot; /&gt; is straightforward: they correspond
directly to finite sequences of numbers, with the moving rule
described above: sequence &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24A%24&quot; /&gt; represents an ordinal less than
sequence &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24B%24&quot; /&gt; if &lt;em&gt;one&lt;/em&gt; of &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24A%24&quot; /&gt;'s elements is less than the
corresponding one of &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24B%24&quot; /&gt;'s, and the elements to the right are the
same.&lt;/p&gt;

&lt;p&gt;I hd said at one point that &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%5e%cf%89%24&quot; /&gt; was where the ordinals started to
get scary.  And perhaps it does seem scary, if you try to think of it
as cells in an infinite-dimensional array.  But when you think of
&lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%5e%cf%89%24&quot; /&gt;  as just the set of finite sequences of numbers, it's not
scary at all!&lt;/p&gt;

&lt;p&gt;That was my first big step on the road to &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%20%5cepsilon_0%20%24&quot; /&gt;, but &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%0a%5cepsilon_0%20%24&quot; /&gt; seems much more daunting.  It's not merely &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%5e%cf%89%24&quot; /&gt;, it's
actually more like&lt;/p&gt;

&lt;p&gt;$$ω^{ω^{ω^{ω^⋰}}}$$&lt;/p&gt;

&lt;p&gt;because it's by definition the smallest ordinal &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24x%24&quot; /&gt; with the
property that &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24x%20%3d%20%cf%89%5ex%24&quot; /&gt;.  But the next couple of articles will take
us the rest of the way there!&lt;/p&gt;

&lt;p&gt;The gold dollar coin in the first illustration
started out as an SVG provided by Claude, but underwent signficant
transformation at my hands in Inkscape. All other slop in this article
is entirely the product of my own natural
intelligence.&lt;/p&gt;</description>
	<pubDate>Wed, 05 Aug 2026 19:27:00 +0000</pubDate>
	<author>mjd@plover.com (Mark Dominus)</author>
</item>
<item>
	<title>Philip Wadler: Just Work: The Gig Economy, Platform Capitalism and the Battle for Worker Rights</title>
	<guid isPermaLink="false">tag:blogger.com,1999:blog-9757377.post-994402424996852846</guid>
	<link>https://wadler.blogspot.com/2026/08/just-work-gig-economy-platform.html</link>
	<description>&lt;p&gt; &lt;/p&gt;&lt;img height=&quot;640&quot; src=&quot;https://tomhumberstone.com/media/pages/pieces/just-work/b069648aa0-1781785658/page1_1-3000x.webp&quot; width=&quot;429&quot; /&gt;&lt;p&gt;A &lt;a href=&quot;https://tomhumberstone.com/just-work&quot;&gt;comic&lt;/a&gt; by Tom Humberstone about gig workers and the need to organise, with loads of local Edinburgh flavour.&lt;/p&gt;</description>
	<pubDate>Wed, 05 Aug 2026 14:43:48 +0000</pubDate>
	<author>noreply@blogger.com (Philip Wadler)</author>
</item>
<item>
	<title>in Code: &quot;Five-Point Haskell&quot;: Unconditional Election (via Parametricity)</title>
	<guid isPermaLink="true">https://blog.jle.im/entry/five-point-haskell-part-2-unconditional-election.html</guid>
	<link>https://blog.jle.im/entry/five-point-haskell-part-2-unconditional-election.html</link>
	<description>&lt;p&gt;Welcome back to &lt;em&gt;&lt;a href=&quot;https://blog.jle.im/entries/series/+five-point-haskell.html&quot;&gt;Five-Point
Haskell&lt;/a&gt;&lt;/em&gt;! This is my attempt to codify principles of writing robust,
maintainable, correct, clear, and effective code in Haskell and to dispel common
bad practices (or, heresies) I have run into in my time.&lt;/p&gt;
&lt;p&gt;In the last post, we talked about &lt;a href=&quot;https://blog.jle.im/entry/five-point-haskell-part-1-total-depravity.html&quot;&gt;Total
Depravity&lt;/a&gt;, which is about treating any mentally tracked constraint or
condition as inevitably leading to a catastrophe and denouncing the reliance on
our flawed mental context windows.&lt;/p&gt;
&lt;p&gt;However, stopping here gives us an incomplete picture. Firstly, types aren’t
just about preventing bad behaviors. They’re about designing good code.
Secondly, there is only so much you can do by picking careful structures and
making invalid states unrepresentable. These are still human tools with human
flaws.&lt;/p&gt;
&lt;p&gt;The next point, to me, is about an aspect of the type system that I see
little coverage of, but is a doctrine of design that I reach for in almost
everything I write. It’s about leveraging the unyielding properties of math
&lt;em&gt;itself&lt;/em&gt; to take care of our fate, even when we are unable to structure
our types well.&lt;/p&gt;
&lt;p&gt;So, when writing Haskell, remember &lt;strong&gt;Unconditional
Election&lt;/strong&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Unconditional Election: The power of the &lt;code&gt;forall&lt;/code&gt; to elect or
reprobate instantiations and implementations through parametric polymorphism.
These properties aren’t based on any conditional ad-hoc aspect of types, but are
truly unconditional, predestined by universal quantification.&lt;/p&gt;
&lt;p&gt;Surrender your control to parametric polymorphism in all things. Embrace the
“free”-dom of “Free Theorems” from one of Haskell’s greatest unexpected
strengths: the type parameter.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;choice-is-a-prison&quot;&gt;Choice is a Prison&lt;/h2&gt;
&lt;h3 id=&quot;conditional-election&quot;&gt;Conditional Election&lt;/h3&gt;
&lt;p&gt;Learning Haskell can be a journey full of surprises, but this was one of the
ones that blew my mind the most.&lt;/p&gt;
&lt;p&gt;Let’s think of a polymorphic function in Java that takes a value of any type
and returns something of that same type:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode java&quot;&gt;&lt;code class=&quot;sourceCode java&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb1-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;T&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; T &lt;span class=&quot;fu&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;T x&lt;span class=&quot;op&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What could that function do?&lt;/p&gt;
&lt;p&gt;Well, it could do IO or throw an exception, mutate the input, or possibly be
non-terminating, but let’s assume all it (and every other example here) does is
purely return a value without mutation. What could it do?&lt;/p&gt;
&lt;p&gt;The answer: pretty much anything. It could return the same value it was
given, except if it is an &lt;code&gt;Integer&lt;/code&gt;, in which case it negates it:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot;&gt;&lt;pre class=&quot;sourceCode java&quot;&gt;&lt;code class=&quot;sourceCode java&quot;&gt;&lt;span id=&quot;cb2-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;T&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; T &lt;span class=&quot;fu&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;T x&lt;span class=&quot;op&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;cf&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;x &lt;span class=&quot;kw&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;Integer&lt;/span&gt; i&lt;span class=&quot;op&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;T&lt;span class=&quot;op&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;Integer&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;valueOf&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(-&lt;/span&gt;i&lt;span class=&quot;op&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; x&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Same deal in TypeScript or pretty much any other typed language without
parametricity:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb3&quot;&gt;&lt;pre class=&quot;sourceCode typescript&quot;&gt;&lt;code class=&quot;sourceCode typescript&quot;&gt;&lt;span id=&quot;cb3-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb3-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;T&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt;(x&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; T)&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; T&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Yet again, we have conditional election:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb4&quot;&gt;&lt;pre class=&quot;sourceCode typescript&quot;&gt;&lt;code class=&quot;sourceCode typescript&quot;&gt;&lt;span id=&quot;cb4-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;T&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt;(x&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; T)&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; T {&lt;/span&gt;
&lt;span id=&quot;cb4-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;cf&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;kw&quot;&gt;typeof&lt;/span&gt; x &lt;span class=&quot;op&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;number&quot;&lt;/span&gt;) {&lt;/span&gt;
&lt;span id=&quot;cb4-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; (&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;x) &lt;span class=&quot;im&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;any&lt;/span&gt; &lt;span class=&quot;im&quot;&gt;as&lt;/span&gt; T&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  }&lt;/span&gt;
&lt;span id=&quot;cb4-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; x&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But how about Haskell?&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb5&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb5-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;foo ::&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; a&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(For the rest of this post, let’s ignore &lt;a href=&quot;https://www.cse.chalmers.se/~nad/publications/danielsson-popl2006-tr.pdf&quot;&gt;non-termination&lt;/a&gt;&lt;a class=&quot;footnote-ref&quot; href=&quot;http://feeds.feedburner.com/incodeblog#fn1&quot; id=&quot;fnref1&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;
and other escape hatches&lt;a class=&quot;footnote-ref&quot; href=&quot;http://feeds.feedburner.com/incodeblog#fn2&quot; id=&quot;fnref2&quot;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Because Haskell has type erasure and no runtime reflection, the &lt;em&gt;only&lt;/em&gt;
possible implementation is simply:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb6&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb6-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;foo ::&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; a&lt;/span&gt;
&lt;span id=&quot;cb6-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;foo x &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; x&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So, there is an invariant that appeared somehow in our code: a function of
type &lt;code&gt;forall a. a -&amp;gt; a&lt;/code&gt; &lt;em&gt;must&lt;/em&gt; leave its value
unchanged!&lt;/p&gt;
&lt;p&gt;But wait…says who? Did we insert some sort of &lt;code&gt;const&lt;/code&gt; compiler
annotation? Did we add some sort of annotation or pre- and post-condition that
the value cannot change? Are we relying on any sort of foreseeable property of
the value given?&lt;/p&gt;
&lt;p&gt;No, this behavior is actually &lt;em&gt;intrinsically&lt;/em&gt; fixed! We got this
theorem &lt;em&gt;for free&lt;/em&gt;. No need for any sort of work, no need for any
foreseen faithfulness. We didn’t even have to &lt;em&gt;write&lt;/em&gt; the function before
knowing all it possibly could be.&lt;/p&gt;
&lt;p&gt;This is the power of the &lt;code&gt;forall&lt;/code&gt;. The above
&lt;code&gt;foo :: a -&amp;gt; a&lt;/code&gt; can be considered “sugar” for:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb7&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb7-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb7-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;foo ::&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;forall&lt;/span&gt; a&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; a&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you don’t add a &lt;code&gt;forall a&lt;/code&gt;, it is implicitly added. Some
languages, like PureScript and Dhall, require the &lt;code&gt;forall&lt;/code&gt; in every
case to be explicit. You can think of the “forall” as like
&lt;code&gt;template &amp;lt;typename T&amp;gt;&lt;/code&gt; in &lt;code&gt;C++&lt;/code&gt;, a declaration of
what type variable is being quantified over.&lt;/p&gt;
&lt;p&gt;Anyway, let’s consider another type signature:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb8&quot;&gt;&lt;pre class=&quot;sourceCode java&quot;&gt;&lt;code class=&quot;sourceCode java&quot;&gt;&lt;span id=&quot;cb8-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;T&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;T x&lt;span class=&quot;op&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Even if we disallow IO (like getting the time, or system state), in Java (and
most other languages), this again could literally be anything. You can serialize
the object with &lt;code&gt;toString&lt;/code&gt;, or you can get its class using
&lt;code&gt;getClass&lt;/code&gt;…&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb9&quot;&gt;&lt;pre class=&quot;sourceCode java&quot;&gt;&lt;code class=&quot;sourceCode java&quot;&gt;&lt;span id=&quot;cb9-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb9-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;T&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;T x&lt;span class=&quot;op&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;hello&quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb9-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;T&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;T x&lt;span class=&quot;op&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; x&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb9-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;T&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;T x&lt;span class=&quot;op&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; x&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;getClass&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;getSimpleName&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In Haskell? A &lt;code&gt;forall a. a -&amp;gt; String&lt;/code&gt; cannot use its input! It
&lt;em&gt;must&lt;/em&gt; be a constant string!&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb10&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb10-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb10-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;foo ::&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb10-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;foo _ &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;hello&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb10-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- or&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb10-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;foo _ &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;goodbye&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb10-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- or&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb10-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;foo _ &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;i always ignore my input&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In fact, there is an isomorphism between &lt;code&gt;String&lt;/code&gt; and
&lt;code&gt;forall a. a -&amp;gt; String&lt;/code&gt; (fun exercise: write it!)&lt;/p&gt;
&lt;p&gt;You can “selectively” bring in capabilities using typeclasses:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb11&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb11-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb11-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;foo ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Show&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb11-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;foo _ &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;hello&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb11-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- or&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb11-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;foo x &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;show&lt;/span&gt; x&lt;/span&gt;
&lt;span id=&quot;cb11-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb11-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- or&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb11-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;foo x &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;reversed: &quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;reverse&lt;/span&gt; (&lt;span class=&quot;fu&quot;&gt;show&lt;/span&gt; x)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But there are still properties you can enforce: the resulting string can
&lt;em&gt;only&lt;/em&gt; depend on the input as far as what is revealed in its
&lt;code&gt;Show&lt;/code&gt; instance. Any property not in its &lt;code&gt;Show&lt;/code&gt; instance
is off-limits.&lt;/p&gt;
&lt;p&gt;Alternatively, you can think of
&lt;code&gt;foo :: Show a =&amp;gt; a -&amp;gt; String&lt;/code&gt; as:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb12&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb12-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;foo ::&lt;/span&gt; (a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;foo showVal x &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;-- ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and you can see that the only way you can ever inspect &lt;code&gt;a&lt;/code&gt; is
through the singular inspection-lens &lt;code&gt;a -&amp;gt; String&lt;/code&gt; that you are
given. No &lt;code&gt;getClass()&lt;/code&gt;, no back doors, etc.&lt;/p&gt;
&lt;h3 id=&quot;the-guessing-game&quot;&gt;The Guessing Game&lt;/h3&gt;
&lt;p&gt;One game Haskellers often play day-to-day is “guess the properties that the
&lt;code&gt;forall&lt;/code&gt; ensures” on different type signatures. Let’s try it out!&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb13&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb13-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb13-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;mystery ::&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; a&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;mystery&lt;/code&gt; &lt;em&gt;has&lt;/em&gt; to be &lt;code&gt;\x _ -&amp;gt; x&lt;/code&gt; — there is
no other option.&lt;/p&gt;
&lt;p&gt;How about:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb14&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb14-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb14-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;turmeric ::&lt;/span&gt; ((a, b) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; c) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; c&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you think about it, the only option is:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb15&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb15-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb15-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;turmeric ::&lt;/span&gt; ((a, b) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; c) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; c&lt;/span&gt;
&lt;span id=&quot;cb15-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb15-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;turmeric f x y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; f (x, y)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can go pretty far down this lane using Haskell as a &lt;a href=&quot;https://blog.jle.im/entry/the-baby-paradox-in-haskell.html#haskell-as-a-theorem-prover&quot;&gt;theorem
prover&lt;/a&gt;, in that the type signature represents a proposition and the
implementation represents a proof of that claim. But we’re not going to go down
that route for now, since most practical code is not theorem-proving.&lt;/p&gt;
&lt;p&gt;But let’s look at something a bit more structural. How about:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb16&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb16-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb16-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;theThing ::&lt;/span&gt; [a] &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; [a]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What could this do?&lt;/p&gt;
&lt;p&gt;Well, we know that all items from the result list &lt;em&gt;must&lt;/em&gt; be from the
input list. It must be a “subset” — but the ordering or multiplicity can change.
And more importantly, it &lt;em&gt;can’t&lt;/em&gt; depend on anything about the properties
of any &lt;code&gt;a&lt;/code&gt;. We also know that if the input is empty, so must be the
output.&lt;/p&gt;
&lt;p&gt;From this, we can derive what are called &lt;a href=&quot;https://people.mpi-sws.org/~dreyer/tor/papers/wadler.pdf&quot;&gt;free
theorems&lt;/a&gt; to look at properties that &lt;em&gt;any implementation&lt;/em&gt; must have.
Namely, &lt;em&gt;mapping&lt;/em&gt; a function over the list and calling
&lt;code&gt;theThing&lt;/code&gt; must be equivalent to calling &lt;code&gt;theThing&lt;/code&gt; and
then mapping:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb17&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb17-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb17-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;theThing &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;map&lt;/span&gt; f&lt;/span&gt;
&lt;span id=&quot;cb17-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb17-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;map&lt;/span&gt; f &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; theThing&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Can you see why? Think of any possible implementation — &lt;code&gt;reverse&lt;/code&gt;,
&lt;code&gt;take 3&lt;/code&gt;, etc. — and see how this must be the case. However, this is
&lt;em&gt;not&lt;/em&gt; true for i.e. &lt;code&gt;sort :: [Int] -&amp;gt; [Int]&lt;/code&gt;. Because
&lt;code&gt;sort&lt;/code&gt; depends on the actual properties of the items,
&lt;code&gt;map f&lt;/code&gt; could change the properties that &lt;code&gt;sort&lt;/code&gt; depends
on!&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb18&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb18-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb18-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;sort&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;abs&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; [&lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb18-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb18-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;[&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb18-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb18-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;abs&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;sort&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; [&lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb18-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb18-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;[&lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Compared to an actual function with the polymorphic type, like
&lt;code&gt;take 3&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb19&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb19-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb19-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;take&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;abs&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; [&lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb19-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb19-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;[&lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb19-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb19-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;abs&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;take&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; [&lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb19-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb19-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;[&lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;How about:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb20&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb20-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb20-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;doIt ::&lt;/span&gt; [a] &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; a&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Think about what this &lt;em&gt;can’t&lt;/em&gt; do. It clearly selects a single item,
but:&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;The single item cannot be determined based on any quality or merit of that
item — it can’t be the smallest, the largest, etc.; it has to depend purely on
the position in the list and the length of the list&lt;/li&gt;
&lt;li&gt;If given an empty list, it &lt;em&gt;must&lt;/em&gt; return &lt;code&gt;Nothing&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And again we have the same free theorem,
&lt;code&gt;doIt . map f == fmap f . doIt&lt;/code&gt;. No matter how you implement
&lt;code&gt;doIt&lt;/code&gt;, it is guaranteed to commute with &lt;code&gt;map&lt;/code&gt; and
&lt;code&gt;fmap&lt;/code&gt;!&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb21&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb21-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- no free theorem: `minimumMay :: [Int] -&amp;gt; Maybe Int`&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; minimumMay &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;abs&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; [&lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb21-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fmap&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;abs&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; minimumMay &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; [&lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb21-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- free theorem: `listToMaybe :: [a] -&amp;gt; Maybe a`&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; listToMaybe &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;abs&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; [&lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb21-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fmap&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;abs&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; listToMaybe &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; [&lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb21-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- free theorem: `lastMay :: [a] -&amp;gt; Maybe a`&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; lastMay &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;abs&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; [&lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb21-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fmap&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;abs&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; lastMay &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; [&lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb21-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let’s try another one:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb22&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb22-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb22-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;collapse ::&lt;/span&gt; [a] &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What could this possibly do? Well, we can rule out things like
&lt;code&gt;sum&lt;/code&gt; because we can’t use any property of the values themselves. The
only things that this could return are constant functions and functions that
depend on the &lt;em&gt;length&lt;/em&gt; but not the &lt;em&gt;contents&lt;/em&gt; of the list. We also
have another free theorem, &lt;code&gt;collapse . map f == collapse&lt;/code&gt;: mapping a
function shouldn’t change the output, because none of the actual values
matter.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb23&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb23-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb23-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- no free theorem: `sum :: [Int] -&amp;gt; Int`&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb23-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb23-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;sum&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;abs&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; [&lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb23-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb23-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dv&quot;&gt;16&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb23-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb23-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;sum&lt;/span&gt; [&lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb23-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb23-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb23-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb23-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb23-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb23-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- free theorem: `length :: [a] -&amp;gt; Int`&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb23-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb23-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;abs&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; [&lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb23-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb23-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb23-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb23-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;length&lt;/span&gt; [&lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb23-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb23-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb23-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb23-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb23-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb23-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- free theorem: `const 10 :: [a] -&amp;gt; Int`&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb23-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb23-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;abs&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; [&lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb23-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb23-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dv&quot;&gt;10&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb23-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb23-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;10&lt;/span&gt; [&lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb23-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb23-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dv&quot;&gt;10&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;How about something in the opposite direction:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb24&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb24-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;duper ::&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; [a]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;From this type signature, we can conclude that the final list must contain
the &lt;em&gt;same item&lt;/em&gt;! The only possible inhabitants are
&lt;code&gt;replicate n&lt;/code&gt; for some &lt;code&gt;n&lt;/code&gt;, or &lt;code&gt;repeat&lt;/code&gt;.&lt;a class=&quot;footnote-ref&quot; href=&quot;http://feeds.feedburner.com/incodeblog#fn3&quot; id=&quot;fnref3&quot;&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Again, we have a free theorem: &lt;code&gt;map f . duper == duper . f&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb25&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb25-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb25-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- no free theorem: `take 3 . iterate (+1) :: Int -&amp;gt; [Int]`&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb25-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb25-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;take&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;iterate&lt;/span&gt; (&lt;span class=&quot;op&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;negate&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb25-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb25-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;[&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb25-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb25-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;negate&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;take&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;iterate&lt;/span&gt; (&lt;span class=&quot;op&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb25-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb25-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;[&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;6&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb25-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb25-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb25-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb25-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- free theorem: `replicate 3 :: Int -&amp;gt; [Int]`&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb25-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb25-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;replicate&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;negate&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb25-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb25-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;[&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb25-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb25-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;negate&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;replicate&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb25-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb25-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;[&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;How about continuations?&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb26&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb26-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb26-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;consumeInt ::&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;forall&lt;/span&gt; r&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; r) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; r&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This might look exotic, but think about what it &lt;em&gt;must&lt;/em&gt; do. It receives
a function &lt;code&gt;Int -&amp;gt; r&lt;/code&gt; and must produce an &lt;code&gt;r&lt;/code&gt;. The only
way to produce an &lt;code&gt;r&lt;/code&gt; for &lt;em&gt;all possible&lt;/em&gt; &lt;code&gt;r&lt;/code&gt; is to
apply the given function to some fixed &lt;code&gt;Int&lt;/code&gt; chosen ahead of time.
This type is actually isomorphic to &lt;code&gt;Int&lt;/code&gt; itself: the only inhabitant
is &lt;code&gt;\f -&amp;gt; f x&lt;/code&gt; for some fixed &lt;code&gt;x&lt;/code&gt;.&lt;a class=&quot;footnote-ref&quot; href=&quot;http://feeds.feedburner.com/incodeblog#fn4&quot; id=&quot;fnref4&quot;&gt;&lt;sup&gt;4&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb27&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb27-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb27-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;consumeInt ::&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;forall&lt;/span&gt; r&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; r) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; r&lt;/span&gt;
&lt;span id=&quot;cb27-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb27-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;consumeInt f &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; f &lt;span class=&quot;dv&quot;&gt;42&lt;/span&gt;     &lt;span class=&quot;co&quot;&gt;-- must be a fixed `Int`, cannot dynamically change&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb27-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb27-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb27-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb27-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;consumeString ::&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;forall&lt;/span&gt; r&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; r) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; r&lt;/span&gt;
&lt;span id=&quot;cb27-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb27-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;consumeString f &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; f &lt;span class=&quot;st&quot;&gt;&quot;hello&quot;&lt;/span&gt;     &lt;span class=&quot;co&quot;&gt;-- must be a fixed `String`, cannot dynamically change&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What’s better than one type variable? How about two?&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb28&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb28-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;mapMaybe ::&lt;/span&gt; (a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; b) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; [a] &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; [b]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Because this has to work for &lt;em&gt;all&lt;/em&gt; &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;,
we know that the &lt;em&gt;only&lt;/em&gt; possible &lt;code&gt;b&lt;/code&gt;s you can find in your
result list are &lt;code&gt;b&lt;/code&gt;s that you get from the
&lt;code&gt;a -&amp;gt; Maybe b&lt;/code&gt; function. So, you can be sure that the
implementation doesn’t conjure out any arbitrary &lt;code&gt;b&lt;/code&gt; except for the
specific ones producible by your &lt;code&gt;a -&amp;gt; Maybe b&lt;/code&gt;. For example, if
you pass it a function that returns only even integers, the resulting list will
&lt;em&gt;only&lt;/em&gt; ever contain even integers!&lt;/p&gt;
&lt;p&gt;One final one, with a higher-kinded type variable:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb29&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb29-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb29-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;traverseIO ::&lt;/span&gt; (a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; b) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; [a] &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; [b]&lt;/span&gt;
&lt;span id=&quot;cb29-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb29-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb29-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb29-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- vs&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb29-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb29-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb29-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb29-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;traverse&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Applicative&lt;/span&gt; f &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; (a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; f b) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; [a] &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; f [b]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What invariant does the second add over the first? Even &lt;em&gt;if&lt;/em&gt; you only
ever plan on calling things with &lt;code&gt;IO&lt;/code&gt;, the second gives you a new
invariant: there won’t be any “stray” &lt;code&gt;IO&lt;/code&gt; actions other than what is
given in the &lt;code&gt;a -&amp;gt; f b&lt;/code&gt;. In the first one, you never know if the
resulting &lt;code&gt;IO&lt;/code&gt; action might include a &lt;code&gt;putStrLn &quot;hello&quot;&lt;/code&gt;
or a &lt;code&gt;launchMissiles&lt;/code&gt;. You definitely don’t want any functions doing
sneaky IO behind your back!&lt;/p&gt;
&lt;h3 id=&quot;the-more-you-surrender&quot;&gt;The More you Surrender&lt;/h3&gt;
&lt;p&gt;Practically, this becomes similar to the principle of least power, the idea
that you should use the tools with the least power necessary to do your job. Say
you &lt;em&gt;are&lt;/em&gt; writing a function that shuffles a list of items, important for
your business logic. You can encode exactly &lt;em&gt;what&lt;/em&gt; business logic is
being done by adding more and more parametricity.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If your type is &lt;code&gt;[Int] -&amp;gt; [Int]&lt;/code&gt;, you know your function has
pretty much no restriction on what it can do. It can even look at the machine
representation of your values.&lt;/li&gt;
&lt;li&gt;If your type is &lt;code&gt;Num a =&amp;gt; [a] -&amp;gt; [a]&lt;/code&gt;, you know that it can
possibly numerically transform the items in your list, or even conjure up new
items.&lt;/li&gt;
&lt;li&gt;If your type is &lt;code&gt;Ord a =&amp;gt; [a] -&amp;gt; [a]&lt;/code&gt;, you know that your
business logic is allowed to look at the ordering between items in the list, but
cannot return any items that weren’t in the original list.&lt;/li&gt;
&lt;li&gt;If your type is &lt;code&gt;[a] -&amp;gt; [a]&lt;/code&gt;, you know that your logic can
only affect the permutation and multiplicity of items in your list.&lt;/li&gt;
&lt;li&gt;If your type is &lt;code&gt;Foldable t =&amp;gt; t a -&amp;gt; [a]&lt;/code&gt;, you know that
results come from the input, but you can still reorder, duplicate, or drop
elements. Furthermore, the resulting permutation is “pre-determined” before you
receive any input items.&lt;/li&gt;
&lt;li&gt;If your type is &lt;code&gt;Functor f =&amp;gt; f Int -&amp;gt; f Int&lt;/code&gt;, if you call
with &lt;code&gt;[]&lt;/code&gt;, you know that the length and ordering of the result will
be preserved, and also any mappings of &lt;code&gt;Int&lt;/code&gt;s will be done
purely.&lt;/li&gt;
&lt;li&gt;If your type is &lt;code&gt;Monad m =&amp;gt; m a -&amp;gt; m a&lt;/code&gt;, if you call with
&lt;code&gt;[]&lt;/code&gt;, you know that the lengths of your results will always be
integer powers of the length of the input, and each input element will be
duplicated the same number of times. So, if you give it &lt;code&gt;[1,2,3]&lt;/code&gt;,
you know the result’s length has to be of the form &lt;code&gt;3^k&lt;/code&gt; and must
contain &lt;code&gt;3^(k-1)&lt;/code&gt; copies of &lt;code&gt;1&lt;/code&gt;, &lt;code&gt;2&lt;/code&gt;, and
&lt;code&gt;3&lt;/code&gt;, in some order.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By switching from concrete types slowly to parametric types, you surrender
control of what your functions can do, and create stronger and stronger
guarantees. In other languages, or with refinement types, you might have to
explicitly declare a post-condition like “the final values must all come from
the original list”. With parametric polymorphism, this is already guaranteed and
elected, no matter what the implementation is.&lt;/p&gt;
&lt;p&gt;You can also play this game in the other direction: instead of writing a
post-condition like “the length of the list must be preserved”, you can try to
figure out the level of power you need to get that. For example, if you wanted
to ensure “the result must have the same number of &lt;code&gt;Int&lt;/code&gt; items (if
you give it a list), but the order can depend on the actual inspection of the
items”, how would you give that type?&lt;/p&gt;
&lt;p&gt;And (spoilers) why does &lt;code&gt;Traversable f =&amp;gt; f Int -&amp;gt; f Int&lt;/code&gt;
work? And, why, when you pass it a tree of &lt;code&gt;Int&lt;/code&gt;s, does it even
preserve the &lt;em&gt;shape&lt;/em&gt; of the tree while freely allowing shuffling between
actual leaves based on the &lt;code&gt;Int&lt;/code&gt; values themselves?&lt;/p&gt;
&lt;h3 id=&quot;its-only-natural&quot;&gt;It’s Only Natural&lt;/h3&gt;
&lt;p&gt;As an aside, did you wonder where I got those free theorems from? In the
examples above, they come from &lt;em&gt;naturality&lt;/em&gt;. Basically, any
&lt;code&gt;forall a. (Functor f, Functor g) =&amp;gt; f a -&amp;gt; g a&lt;/code&gt; corresponds to
a &lt;em&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Natural_transformation&quot;&gt;natural
transformation&lt;/a&gt;&lt;/em&gt; in category theory, and so must commute with any
&lt;code&gt;fmap&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Basically, if you have a natural transformation
&lt;code&gt;h :: forall a. F a -&amp;gt; G a&lt;/code&gt;, with &lt;code&gt;Functor F&lt;/code&gt; and
&lt;code&gt;Functor G&lt;/code&gt;, then we have:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb30&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb30-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb30-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;h &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fmap&lt;/span&gt; f&lt;/span&gt;
&lt;span id=&quot;cb30-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb30-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fmap&lt;/span&gt; f &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; h&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The above examples, &lt;code&gt;forall a. [a] -&amp;gt; [a]&lt;/code&gt;,
&lt;code&gt;forall a. [a] -&amp;gt; Maybe a&lt;/code&gt;, etc. all arise from this. But you
might have to think carefully to see that &lt;code&gt;forall a. a -&amp;gt; [a]&lt;/code&gt; is
really &lt;code&gt;forall a. Identity a -&amp;gt; [a]&lt;/code&gt;. And can you think of the
Functor that gives us naturality for &lt;code&gt;forall a. [a] -&amp;gt; Int&lt;/code&gt;?&lt;a class=&quot;footnote-ref&quot; href=&quot;http://feeds.feedburner.com/incodeblog#fn5&quot; id=&quot;fnref5&quot;&gt;&lt;sup&gt;5&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Maybe more surprising than the fact that these free theorems exist is the
fact that their root is intrinsically tied to a branch of math as obscure and
esoteric as “category theory”!&lt;/p&gt;
&lt;h2 id=&quot;add-a-type-variable&quot;&gt;Add a Type Variable&lt;/h2&gt;
&lt;p&gt;Let’s say I had a data type like:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb31&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb31-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb31-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb31-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb31-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    {&lt;span class=&quot;ot&quot;&gt; userId ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb31-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb31-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ,&lt;span class=&quot;ot&quot;&gt; userName ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb31-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb31-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ,&lt;span class=&quot;ot&quot;&gt; userAge ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb31-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb31-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And we have a function to process the user, like:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb32&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb32-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb32-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;processUser ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;How can we enforce that the &lt;code&gt;userId&lt;/code&gt; is not changed?&lt;/p&gt;
&lt;p&gt;Maybe if we were in C, we could have a &lt;code&gt;const&lt;/code&gt; field:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb33&quot;&gt;&lt;pre class=&quot;sourceCode c&quot;&gt;&lt;code class=&quot;sourceCode c&quot;&gt;&lt;span id=&quot;cb33-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb33-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;struct&lt;/span&gt; User &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb33-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;int&lt;/span&gt; userId&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb33-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;char&lt;/span&gt; userName&lt;span class=&quot;op&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb33-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;int&lt;/span&gt; userAge&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb33-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But, this applies to &lt;em&gt;all&lt;/em&gt; usage of the &lt;code&gt;User&lt;/code&gt; struct…what
if we only wanted to preserve this property on a single function? You can’t
declare struct-level &lt;code&gt;const&lt;/code&gt; on a single argument!&lt;/p&gt;
&lt;p&gt;Instead, we can enforce this by making &lt;code&gt;userId&lt;/code&gt;’s type
parameterized:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb34&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb34-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb34-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; uid &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb34-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    {&lt;span class=&quot;ot&quot;&gt; userId ::&lt;/span&gt; uid&lt;/span&gt;
&lt;span id=&quot;cb34-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb34-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ,&lt;span class=&quot;ot&quot;&gt; userName ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb34-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ,&lt;span class=&quot;ot&quot;&gt; userAge ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb34-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id=&quot;cb34-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb34-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb34-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- | Guaranteed not to change the ID&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb34-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;processUser ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; uid &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; uid)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Is this constraint enforced because we carefully designed the structure of
our type? Is it constrained because we added compiler annotations or refinement
types or static analysis? Not quite! It truly did come for free.&lt;/p&gt;
&lt;p&gt;Or, consider a checklist item:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb35&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb35-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb35-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Checklist&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Checklist&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb35-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb35-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  {&lt;span class=&quot;ot&quot;&gt; updated ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UTCTime&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb35-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb35-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ,&lt;span class=&quot;ot&quot;&gt; items ::&lt;/span&gt; [(&lt;span class=&quot;dt&quot;&gt;Status&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;)]&lt;/span&gt;
&lt;span id=&quot;cb35-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb35-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What if I wanted to write a function that processed items without adding or
removing any? Just each item in-place?&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb36&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb36-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb36-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- | Invariant: Preserves the ordering of items, and their number.&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb36-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb36-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;updateItems ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Checklist&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Checklist&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;How can we make sure all our implementations are &lt;em&gt;elected&lt;/em&gt; to only be
implementations that don’t modify the length of &lt;code&gt;items&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;Again the answer can be: add quantification!&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb37&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb37-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb37-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Checklist&lt;/span&gt; t &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Checklist&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb37-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb37-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  {&lt;span class=&quot;ot&quot;&gt; updated ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UTCTime&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb37-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb37-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ,&lt;span class=&quot;ot&quot;&gt; items ::&lt;/span&gt; t (&lt;span class=&quot;dt&quot;&gt;Status&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb37-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb37-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  }&lt;/span&gt;
&lt;span id=&quot;cb37-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb37-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb37-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb37-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- | Guaranteed to preseve the same number of `items` (or, number of item&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb37-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb37-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- &quot;slots&quot;), but can still perform IO to get the new Status and String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb37-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb37-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;updateItems ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Traversable&lt;/span&gt; t &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Checklist&lt;/span&gt; t &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Checklist&lt;/span&gt; t)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For an example of a possible implementation:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb38&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb38-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb38-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;updateSingleItem ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Status&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Status&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb38-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb38-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb38-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb38-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;updateItems ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Traversable&lt;/span&gt; t &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Checklist&lt;/span&gt; t &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Checklist&lt;/span&gt; t)&lt;/span&gt;
&lt;span id=&quot;cb38-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb38-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;updateItems c0 &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb38-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb38-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  newItems &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;traverse&lt;/span&gt; updateSingleItem (items c0)&lt;/span&gt;
&lt;span id=&quot;cb38-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb38-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  newUpdated &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; getCurrentTime&lt;/span&gt;
&lt;span id=&quot;cb38-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb38-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Checklist&lt;/span&gt; newUpdated newItems)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Try as you might, you can’t make an implementation that gives you a different
number of items than when you started (even though you can rearrange or replace
them).&lt;/p&gt;
&lt;p&gt;Note that we are &lt;em&gt;not&lt;/em&gt; adding type parameters for abstraction or to be
able to use “exotic checklists” (&lt;code&gt;Checklist Maybe&lt;/code&gt;). Instead, we are
intentionally using them universally quantified in functions that process them,
in order to take advantage of these automatically enforced properties.&lt;/p&gt;
&lt;p&gt;This intersects a lot with the &lt;a href=&quot;https://reasonablypolymorphic.com/blog/higher-kinded-data/&quot;&gt;Higher-Kinded
Data&lt;/a&gt; pattern. Maybe we &lt;em&gt;do&lt;/em&gt; have data we want to have multiple
structural versions of:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb39&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb39-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb39-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserF&lt;/span&gt; f &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb39-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb39-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    {&lt;span class=&quot;ot&quot;&gt; userName ::&lt;/span&gt; f &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb39-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb39-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ,&lt;span class=&quot;ot&quot;&gt; userAge ::&lt;/span&gt; f &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb39-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb39-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id=&quot;cb39-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb39-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb39-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb39-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserF&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Identity&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb39-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb39-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;NullableUser&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserF&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb39-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb39-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserParser&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserF&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Parser&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb39-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb39-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserDocs&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserF&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Const&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Doc&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb39-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb39-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserPrinter&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserF&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Op&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In this case, a function like&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb40&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb40-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb40-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;processUser ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Functor&lt;/span&gt; f &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserF&lt;/span&gt; f &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserF&lt;/span&gt; f&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;will give you a different, unique guarantee for every “shape” your user
has:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For &lt;code&gt;UserF Maybe&lt;/code&gt;, the quantification ensures that the
null-or-present property of each field is preserved&lt;/li&gt;
&lt;li&gt;For &lt;code&gt;UserF Parser&lt;/code&gt;, it ensures that all of the “parsing” logic,
and the set of strings that are validly parsed, is preserved&lt;/li&gt;
&lt;li&gt;For &lt;code&gt;UserF (Const Doc)&lt;/code&gt;, it ensures that the per-field
&lt;code&gt;Doc&lt;/code&gt;/documentation is never changed or updated.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For an example, we can write:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb41&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb41-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb41-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;processUser ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Functor&lt;/span&gt; f &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserF&lt;/span&gt; f &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserF&lt;/span&gt; f&lt;/span&gt;
&lt;span id=&quot;cb41-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb41-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;processUser user &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb41-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb41-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    { userName &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fmap&lt;/span&gt; (&lt;span class=&quot;fu&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;toUpper&lt;/span&gt;) (userName user)&lt;/span&gt;
&lt;span id=&quot;cb41-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb41-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    , userAge &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fmap&lt;/span&gt; (&lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;) (userAge user)&lt;/span&gt;
&lt;span id=&quot;cb41-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb41-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is guaranteed to keep nullable fields null if &lt;code&gt;UserF Maybe&lt;/code&gt;,
preserve all successful parses if &lt;code&gt;UserF Parser&lt;/code&gt;, and leave any
field-level documentation unchanged if &lt;code&gt;UserF (Const Doc)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;All of these properties are &lt;em&gt;mathematically&lt;/em&gt; enforced,
&lt;em&gt;unconditionally&lt;/em&gt;. It doesn’t depend on any foreseen property of the
types or values we use. These guarantees free us to be able to confidently use
these functions without fear of invariants breaking.&lt;/p&gt;
&lt;p&gt;This game becomes even stronger when you consider dependent typing, where we
can express more complex relationships between type variables. For example, in
the case where you have a phantom type (like in &lt;a href=&quot;https://blog.jle.im/entry/introduction-to-singletons-1.html&quot;&gt;this
singletons tutorial&lt;/a&gt;):&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb42&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb42-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb42-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DoorState&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Opened&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Closed&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Locked&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb42-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb42-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb42-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb42-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Door&lt;/span&gt; (&lt;span class=&quot;ot&quot;&gt;s ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DoorState&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb42-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb42-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb42-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb42-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;processDoor ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Door&lt;/span&gt; s &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Door&lt;/span&gt; s)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;processDoor&lt;/code&gt;, by virtue of taking &lt;code&gt;forall s&lt;/code&gt;, &lt;em&gt;must
leave&lt;/em&gt; the door state unchanged! It can never open a closed door, unlock a
locked door, etc.&lt;/p&gt;
&lt;p&gt;For things like &lt;a href=&quot;https://blog.jle.im/entry/fixed-length-vector-types-in-haskell.html&quot;&gt;fixed
length vectors&lt;/a&gt;, where the length &lt;code&gt;n&lt;/code&gt; parameter is the size, what
invariant do you think is preserved in:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb43&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb43-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb43-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;something ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Vector&lt;/span&gt; n a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Vector&lt;/span&gt; n a&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We know that the length of the result must be the same as the length of the
input. Furthermore, with the &lt;code&gt;forall a&lt;/code&gt;, we know that every item in
the result must come from the input, but we might rearrange or change the
multiplicity of the occurrences as long as they add to the same original total
number. This might be a good candidate for a function like
&lt;code&gt;reverse&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Or, consider:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb44&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb44-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb44-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;somethingElse ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Vector&lt;/span&gt; n a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Vector&lt;/span&gt; (n &lt;span class=&quot;op&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;) a&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;From this, we know that the original vector &lt;em&gt;must&lt;/em&gt; be non-empty!
Because of how the types must flow for whatever &lt;code&gt;n&lt;/code&gt; you give it, this
requires &lt;code&gt;n &amp;gt;= 1&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;ranking-up&quot;&gt;Ranking Up&lt;/h2&gt;
&lt;p&gt;Now that you see how useful it is to use type parameters and
&lt;code&gt;forall&lt;/code&gt;, can we &lt;em&gt;use&lt;/em&gt; this fact at the meta-level even within
our code itself?&lt;/p&gt;
&lt;h3 id=&quot;ensuring-structural-preservation&quot;&gt;Ensuring structural preservation&lt;/h3&gt;
&lt;p&gt;Let’s say we want to map an IO function over every item in our
&lt;code&gt;UserF&lt;/code&gt;, and return a new one. We know that whatever IO function we
use &lt;em&gt;must&lt;/em&gt; leave the actual “result” type unchanged. So that means we
must take a &lt;code&gt;forall a. f a -&amp;gt; h (f a)&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb45&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb45-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb45-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;traverseUser&lt;/span&gt;
&lt;span id=&quot;cb45-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb45-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;    ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Applicative&lt;/span&gt; h&lt;/span&gt;
&lt;span id=&quot;cb45-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb45-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; (&lt;span class=&quot;kw&quot;&gt;forall&lt;/span&gt; a&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; f a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; h (g a))&lt;/span&gt;
&lt;span id=&quot;cb45-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb45-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserF&lt;/span&gt; f&lt;/span&gt;
&lt;span id=&quot;cb45-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb45-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; h (&lt;span class=&quot;dt&quot;&gt;UserF&lt;/span&gt; g)&lt;/span&gt;
&lt;span id=&quot;cb45-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb45-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;traverseUser f u &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; f (userName u) &lt;span class=&quot;op&quot;&gt;&amp;lt;*&amp;gt;&lt;/span&gt; f (userAge u)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here again we use the trick above to generalize for all
&lt;code&gt;Applicative h&lt;/code&gt; instead of concretely &lt;code&gt;IO&lt;/code&gt;, so we can know
that the final action can’t sneak in stray IO.&lt;/p&gt;
&lt;h3 id=&quot;ensuring-lexically-confined-resources&quot;&gt;Ensuring lexically-confined
resources&lt;/h3&gt;
&lt;p&gt;We can also use this property in phantom types to enforce lexically-confined
resources. Let’s say we are simulating local variables in an
&lt;code&gt;IntMap&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb46&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb46-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb46-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;newtype&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Var&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Var&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb46-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb46-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;newtype&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Memory&lt;/span&gt; v &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Memory&lt;/span&gt; {&lt;span class=&quot;ot&quot;&gt; getMemory ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IntMap&lt;/span&gt; v }&lt;/span&gt;
&lt;span id=&quot;cb46-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb46-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb46-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb46-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;initVar ::&lt;/span&gt; v &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;State&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Memory&lt;/span&gt; v) &lt;span class=&quot;dt&quot;&gt;Var&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb46-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb46-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;initVar x &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; state &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; \(&lt;span class=&quot;dt&quot;&gt;Memory&lt;/span&gt; mp) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb46-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb46-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; IM.lookupMax mp &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb46-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb46-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Var&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Memory&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; IM.insert &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; x mp)&lt;/span&gt;
&lt;span id=&quot;cb46-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb46-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; (i, _) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Var&lt;/span&gt; (i &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;), &lt;span class=&quot;dt&quot;&gt;Memory&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; IM.insert (i &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;) x mp)&lt;/span&gt;
&lt;span id=&quot;cb46-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb46-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb46-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb46-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;readVar ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Var&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;State&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Memory&lt;/span&gt; v) v&lt;/span&gt;
&lt;span id=&quot;cb46-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb46-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;readVar (&lt;span class=&quot;dt&quot;&gt;Var&lt;/span&gt; i) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; gets ((&lt;span class=&quot;op&quot;&gt;IM.!&lt;/span&gt; i) &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; getMemory)&lt;/span&gt;
&lt;span id=&quot;cb46-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb46-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb46-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb46-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;writeVar ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Var&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; v &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;State&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Memory&lt;/span&gt; v) ()&lt;/span&gt;
&lt;span id=&quot;cb46-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb46-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;writeVar (&lt;span class=&quot;dt&quot;&gt;Var&lt;/span&gt; i) x &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; modify (&lt;span class=&quot;dt&quot;&gt;Memory&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; IM.insert i x &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; getMemory)&lt;/span&gt;
&lt;span id=&quot;cb46-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb46-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb46-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb46-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;runWithMemory ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;State&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Memory&lt;/span&gt; v) a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; a&lt;/span&gt;
&lt;span id=&quot;cb46-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb46-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;runWithMemory &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; (&lt;span class=&quot;ot&quot;&gt;`evalState`&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Memory&lt;/span&gt; IM.empty)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(By the way, what do we gain from having the state be &lt;code&gt;IntMap v&lt;/code&gt;
parametric on &lt;code&gt;v&lt;/code&gt;? What guarantees/invariants do we get, what sort of
actions do we forbid the library itself from doing? Is it possible to have a
default-initialized variable?)&lt;/p&gt;
&lt;p&gt;We can run operations like:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb47&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb47-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb47-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;getFib ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;State&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Memory&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;) &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb47-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb47-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;getFib n &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb47-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb47-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    a &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; initVar &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb47-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb47-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    b &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; initVar &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb47-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb47-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    replicateM_ n &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb47-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb47-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        newSum &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; (&lt;span class=&quot;op&quot;&gt;+&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; readVar a &lt;span class=&quot;op&quot;&gt;&amp;lt;*&amp;gt;&lt;/span&gt; readVar b&lt;/span&gt;
&lt;span id=&quot;cb47-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb47-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        writeVar a &lt;span class=&quot;op&quot;&gt;=&amp;lt;&amp;lt;&lt;/span&gt; readVar b&lt;/span&gt;
&lt;span id=&quot;cb47-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb47-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        writeVar b newSum&lt;/span&gt;
&lt;span id=&quot;cb47-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb47-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    readVar b&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb48&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb48-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb48-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; runWithMemory (getFib &lt;span class=&quot;dv&quot;&gt;10&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb48-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb48-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dv&quot;&gt;55&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But now our variables are not actually scoped. We could, for instance, run
&lt;code&gt;runWithMemory&lt;/code&gt; &lt;em&gt;inside&lt;/em&gt; itself:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb49&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb49-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb49-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;myAction ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;State&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Memory&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;) a&lt;/span&gt;
&lt;span id=&quot;cb49-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb49-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;myAction &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;                 &lt;span class=&quot;co&quot;&gt;-- new memory starts out empty&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb49-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb49-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  v &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; initVar &lt;span class=&quot;st&quot;&gt;&quot;hello&quot;&lt;/span&gt;        &lt;span class=&quot;co&quot;&gt;-- memory is now (0, &quot;hello&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb49-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb49-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt; x &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; runWithMemory &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;  &lt;span class=&quot;co&quot;&gt;-- new memory starts out empty&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb49-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb49-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        readVar v             &lt;span class=&quot;co&quot;&gt;-- runtime error, looking up '0' in empty map!&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb49-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb49-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;co&quot;&gt;-- ..&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb49-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb49-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;co&quot;&gt;-- ..&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now &lt;code&gt;readVar v&lt;/code&gt; will fail! Remember that &lt;code&gt;v&lt;/code&gt; is
&lt;code&gt;Var 0&lt;/code&gt;, but that &lt;code&gt;0&lt;/code&gt; key only has meaning in the outer
scope. In the inner scope, &lt;code&gt;0&lt;/code&gt; refers to a different
&lt;code&gt;IntMap&lt;/code&gt;, where it is undefined.&lt;/p&gt;
&lt;p&gt;We can also do something silly like returning a &lt;code&gt;Var&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb50&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb50-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb50-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; runWithMemory (initVar &lt;span class=&quot;st&quot;&gt;&quot;hello&quot;&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb50-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb50-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;Var&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And now that var exists outside its scope. Its binding is gone, so the name
no longer refers to anything meaningful.&lt;/p&gt;
&lt;p&gt;We can prevent this by associating every variable with the scope that created
it. Then we can ensure that &lt;code&gt;runWithMemory&lt;/code&gt; requires the scope
phantom to never be a part of the final output:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb51&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb51-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb51-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;newtype&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Var&lt;/span&gt; s &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Var&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb51-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb51-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;newtype&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Memory&lt;/span&gt; s v &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Memory&lt;/span&gt; {&lt;span class=&quot;ot&quot;&gt; getMemory ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IntMap&lt;/span&gt; v }&lt;/span&gt;
&lt;span id=&quot;cb51-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb51-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb51-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb51-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;initVar ::&lt;/span&gt; v &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;State&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Memory&lt;/span&gt; s v) (&lt;span class=&quot;dt&quot;&gt;Var&lt;/span&gt; s)&lt;/span&gt;
&lt;span id=&quot;cb51-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb51-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb51-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb51-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;readVar ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Var&lt;/span&gt; s &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;State&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Memory&lt;/span&gt; s v) v&lt;/span&gt;
&lt;span id=&quot;cb51-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb51-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb51-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb51-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;writeVar ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Var&lt;/span&gt; s &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; v &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;State&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Memory&lt;/span&gt; s v) ()&lt;/span&gt;
&lt;span id=&quot;cb51-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb51-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb51-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb51-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;runWithMemory ::&lt;/span&gt; (&lt;span class=&quot;kw&quot;&gt;forall&lt;/span&gt; s&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;State&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Memory&lt;/span&gt; s v) a) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; a&lt;/span&gt;
&lt;span id=&quot;cb51-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb51-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;runWithMemory &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; (&lt;span class=&quot;ot&quot;&gt;`evalState`&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Memory&lt;/span&gt; IM.empty)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here, a &lt;code&gt;Var s&lt;/code&gt; must come from a &lt;code&gt;Memory s v&lt;/code&gt; with the
&lt;em&gt;same&lt;/em&gt; scope &lt;code&gt;s&lt;/code&gt;. It is associated with that scope, and no
others. The &lt;code&gt;forall&lt;/code&gt; here ensures that the action being given cannot
unify with any external &lt;code&gt;s&lt;/code&gt;: the scope is freshly created by
&lt;code&gt;runWithMemory&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Right off the bat, this prevents passing variables into nested calls (the
first var’s &lt;code&gt;s&lt;/code&gt; is different than the inner scope’s &lt;code&gt;s&lt;/code&gt;),
but this also prevents variables from leaking. That’s because the result type
&lt;code&gt;a&lt;/code&gt; must be fully &lt;em&gt;independent&lt;/em&gt; of the &lt;code&gt;s&lt;/code&gt;, so
returning a &lt;code&gt;Var s&lt;/code&gt; is illegal, since that would require the
&lt;code&gt;a&lt;/code&gt; to depend on &lt;code&gt;s&lt;/code&gt;, which escapes the scope of the
&lt;code&gt;forall&lt;/code&gt;. (This is exactly how the &lt;code&gt;ST&lt;/code&gt; monad works in GHC
standard libraries, actually.)&lt;/p&gt;
&lt;p&gt;By requiring the &lt;em&gt;caller&lt;/em&gt; to give up control of the &lt;code&gt;s&lt;/code&gt;, we
ensure lexical confinement both of the library and of the user-given
continuation. Now this safety doesn’t come from carefully tracking where
variables came from. Instead, it is assured through the universality of the
&lt;code&gt;forall&lt;/code&gt; and the unconditional properties it enforces.&lt;/p&gt;
&lt;h2 id=&quot;habits-to-build&quot;&gt;Habits to Build&lt;/h2&gt;
&lt;p&gt;Let’s look at what it looks like to recognize this principle in practice, and
use it in your code. Let’s imagine we have a function that you can use to deploy
a new &lt;code&gt;Config&lt;/code&gt; in your environment:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb52&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb52-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;deployConfig ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Config&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; ()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But, deployment is a bit expensive. So we want to deduplicate our deploys:
deploying the same &lt;code&gt;Config&lt;/code&gt; twice would be a no-op. We can do this by
keeping a &lt;code&gt;Config&lt;/code&gt; in an &lt;code&gt;IORef&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb53&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb53-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb53-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- | returns True if changed, otherwise False if already deployed&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb53-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb53-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;updateConfig ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IORef&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Config&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Config&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Bool&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb53-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb53-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;updateConfig cache newConfig &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb53-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb53-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    oldConfig &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; readIORef cache&lt;/span&gt;
&lt;span id=&quot;cb53-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb53-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;if&lt;/span&gt; oldConfig &lt;span class=&quot;op&quot;&gt;==&lt;/span&gt; newConfig&lt;/span&gt;
&lt;span id=&quot;cb53-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb53-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;kw&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb53-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb53-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;kw&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb53-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb53-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            deployConfig newConfig&lt;/span&gt;
&lt;span id=&quot;cb53-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb53-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            writeIORef cache newConfig&lt;/span&gt;
&lt;span id=&quot;cb53-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb53-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This &lt;em&gt;works&lt;/em&gt;, but after learning about the principles in this post,
that type signature should feel a little bit suspicious to you. Note that our
function never actually &lt;em&gt;inspects&lt;/em&gt; the &lt;code&gt;Config&lt;/code&gt; at all. The
logic is independent. Would there be any value in pulling out the caching logic
generically?&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb54&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb54-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb54-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;cachedUpdate ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; (a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; ()) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IORef&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Bool&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb54-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb54-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;cachedUpdate action cache newVal &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb54-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb54-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    oldVal &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; readIORef cache&lt;/span&gt;
&lt;span id=&quot;cb54-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb54-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;if&lt;/span&gt; oldVal &lt;span class=&quot;op&quot;&gt;==&lt;/span&gt; newVal&lt;/span&gt;
&lt;span id=&quot;cb54-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb54-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;kw&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb54-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb54-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;kw&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb54-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb54-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            action newVal&lt;/span&gt;
&lt;span id=&quot;cb54-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb54-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            writeIORef cache newVal&lt;/span&gt;
&lt;span id=&quot;cb54-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb54-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb54-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb54-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb54-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb54-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;updateConfig ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IORef&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Config&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Config&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Bool&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb54-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb54-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;updateConfig &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; cachedUpdate deployConfig&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let’s presume that we never intend to reuse &lt;code&gt;cachedUpdate&lt;/code&gt;. So, we
just increased our total lines of code…and for what? What does
&lt;code&gt;cachedUpdate&lt;/code&gt; get us?&lt;/p&gt;
&lt;p&gt;Firstly, in the original monomorphic &lt;code&gt;updateConfig&lt;/code&gt;, written
directly against &lt;code&gt;Config&lt;/code&gt;, there is so much that could go wrong.
Maybe you could mis-handle the configuration or accidentally modify it. You
could set certain fields to fixed values. You might end up deploying a
configuration that was never passed in directly.&lt;/p&gt;
&lt;p&gt;In our &lt;code&gt;cachedUpdate&lt;/code&gt; implementation, we are &lt;em&gt;sure&lt;/em&gt; that
any &lt;code&gt;Config&lt;/code&gt; deployed will &lt;em&gt;only&lt;/em&gt; come &lt;em&gt;directly&lt;/em&gt; from
calls to &lt;code&gt;updateConfig&lt;/code&gt;. No other operations are possible.&lt;/p&gt;
&lt;p&gt;Secondly, the type signature of &lt;code&gt;cachedUpdate&lt;/code&gt; tells us a lot more
about what &lt;code&gt;cachedUpdate&lt;/code&gt;’s intended logic is and what exactly it can
support. Let’s say in the future, a new requirement comes: Deploy a “default”
configuration if &lt;code&gt;deployConfig&lt;/code&gt; ever fails.&lt;/p&gt;
&lt;p&gt;You &lt;em&gt;want&lt;/em&gt; something as drastic as this to require you to change your
types and your contracts. In fact, if a new requirement comes along and you are
able to implement it without changing your types, that should be extremely scary
to you, because you previously allowed way too many potentially invalid programs
to compile.&lt;/p&gt;
&lt;p&gt;If we were to add such a change (“deploy a default &lt;code&gt;Config&lt;/code&gt;”), it
&lt;em&gt;should&lt;/em&gt; have us go back to the type signature of
&lt;code&gt;cachedUpdate&lt;/code&gt; and see how it must change in order for us to support
it. That process of interrogation makes us think about what we actually want to
do and how it would fundamentally change our data flow.&lt;/p&gt;
&lt;p&gt;If you subscribe to &lt;a href=&quot;https://en.wikipedia.org/wiki/SOLID&quot;&gt;“SOLID”
programming&lt;/a&gt;, this should all remind you of “Dependency Inversion”.&lt;/p&gt;
&lt;p&gt;Basically: treat all monomorphic code with suspicion. It may be a symptom of
you trying to hold on to more control, when you should be letting go.&lt;/p&gt;
&lt;p&gt;Another example of the same instinct: say you have a function that broadcasts
a notification to a list of users:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb55&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb55-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;notifyUsers ::&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;User&lt;/span&gt;] &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Text&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; ()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;How can this branch on the users? Really, in any way. It could inspect each
user, craft different messages for admins vs. regular users, silently skip
certain users, log personal data, vary behavior based on user properties…&lt;/p&gt;
&lt;p&gt;Compare that to:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb56&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb56-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb56-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;notifyAll ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Foldable&lt;/span&gt; t &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; t recipient &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; (recipient &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; ()) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; ()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;notifyAll&lt;/code&gt; is parametric in &lt;code&gt;recipient&lt;/code&gt;. It cannot
inspect who it is notifying. It cannot skip recipients based on their properties
or treat admins differently from regular users. All of that “policy” logic is
forced to live in the caller. The broadcasting logic itself &lt;em&gt;must&lt;/em&gt; be
uniform: it calls &lt;code&gt;send&lt;/code&gt; indiscriminately on some fixed subset of the
elements. It can pick a subset to send to, but it can’t pick what gets included
in that subset based on the properties of the recipient.&lt;/p&gt;
&lt;h2 id=&quot;embracing-unconditional-election&quot;&gt;Embracing Unconditional Election&lt;/h2&gt;
&lt;p&gt;What sort of control are you trying to hang on to in life, in a way that puts
you in your own prison?&lt;/p&gt;
&lt;p&gt;To me, the fact that making code more polymorphic and giving up information
is valuable not just for abstraction, but for taking advantage of universal
properties, was a surprising one. But ever since I started writing Haskell, it’s
a fact that I take advantage of every day. So, next time you see the
opportunity, try thinking about what that parametric &lt;code&gt;forall&lt;/code&gt; can do
for you. Take advantage of the doctrine of Haskell predestination that arrives
from properties of logic determined before our universe ever existed.&lt;/p&gt;
&lt;h3 id=&quot;the-next-step&quot;&gt;The Next Step&lt;/h3&gt;
&lt;p&gt;Embracing Total Depravity and Unconditional Election should redefine your
relationship with your code. But not all code lives in the nice pure world where
we can cordon off effects. &lt;code&gt;forall a. [a] -&amp;gt; [a]&lt;/code&gt; is very
different than &lt;code&gt;forall a. [a] -&amp;gt; IO [a]&lt;/code&gt;, after all.&lt;/p&gt;
&lt;p&gt;To extend these boundaries to useful code, we have to deal with that boundary
between the world of the pure and the world where &lt;a href=&quot;https://xkcd.com/1312/&quot;&gt;things actually happen for real&lt;/a&gt;. We’ll explore
the nuances of that boundary in the next chapter of &lt;a href=&quot;https://blog.jle.im/entries/series/+five-point-haskell.html&quot;&gt;Five-Point
Haskell&lt;/a&gt;, &lt;strong&gt;Limited Atonement&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;special-thanks&quot;&gt;Special Thanks&lt;/h2&gt;
&lt;p&gt;I am very humbled to be supported by an amazing community, who make it
possible for me to devote time to researching and writing these posts. Very
special thanks to my supporter at the “Amazing” level on &lt;a href=&quot;https://www.patreon.com/justinle/overview&quot;&gt;patreon&lt;/a&gt;, Josh Vera! :)&lt;/p&gt;
&lt;section class=&quot;footnotes footnotes-end-of-document&quot; id=&quot;footnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;&lt;p&gt;This is the “Fast and Loose Reasoning” condition (Danielsson et
al.).&lt;a class=&quot;footnote-back&quot; href=&quot;http://feeds.feedburner.com/incodeblog#fnref1&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn2&quot;&gt;&lt;p&gt;Excluding &lt;code&gt;unsafePerformIO&lt;/code&gt;,
&lt;code&gt;unsafeCoerce&lt;/code&gt;, etc.&lt;a class=&quot;footnote-back&quot; href=&quot;http://feeds.feedburner.com/incodeblog#fnref2&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn3&quot;&gt;&lt;p&gt;If you disallow &lt;code&gt;repeat&lt;/code&gt;,
&lt;code&gt;forall a. a -&amp;gt; [a]&lt;/code&gt; is actually isomorphic to the natural
numbers!&lt;a class=&quot;footnote-back&quot; href=&quot;http://feeds.feedburner.com/incodeblog#fnref3&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn4&quot;&gt;&lt;p&gt;This is actually the essence of Yoneda lemma I think, whatever
that is.&lt;a class=&quot;footnote-back&quot; href=&quot;http://feeds.feedburner.com/incodeblog#fnref4&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn5&quot;&gt;&lt;p&gt;It’s &lt;code&gt;forall a. [a] -&amp;gt; Const Int a&lt;/code&gt;!&lt;a class=&quot;footnote-back&quot; href=&quot;http://feeds.feedburner.com/incodeblog#fnref5&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
	<pubDate>Tue, 04 Aug 2026 18:15:09 +0000</pubDate>
</item>
<item>
	<title>Mark Jason Dominus: Seven books I keep close because I love them</title>
	<guid isPermaLink="false">tag:,2026:/book/elbow-shelf</guid>
	<link>https://blog.plover.com/book/elbow-shelf.html</link>
	<description>&lt;p&gt;The bookshelf by my elbow, the one that I can reach without getting
up, has seven books on it, not necessarily the ones I look in the
most, but the ones whose emanations I most hope will infuse me as I
write.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://pic.blog.plover.com/book/elbow-shelf/elbow-shelf.jpg&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://pic.blog.plover.com/book/elbow-shelf/elbow-shelf-th.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Roget's Thesaurus (4th edition)&lt;/h3&gt;

&lt;p&gt;The one I actually refer to most often is the Harper and Row &lt;em&gt;Roget's
Thesaurus&lt;/em&gt;.  I thought I had acquired this in my teens, but the note
on the flyleaf says 1989.&lt;/p&gt;

&lt;p&gt;This is the fourth edition.  I was very excited to get the eighth
edition, which I thought I might like better, and for some time I kept
them next to each other so that I could look up the same things in
both, and compare.  my conclusion was that while the eighth edition
had more stuff in it, it wasn't stuff I needed.  And it is really fat.
So I have retired it to a farther shelf and will eventually get rid of
it.&lt;/p&gt;

&lt;p&gt;The thesaurus is a book that is widely misunderstood.   It is not, as many people mockingly
imagine, just a compendium of synonyms, and its correct and intended
use is &lt;em&gt;not&lt;/em&gt; to replace common words with more impressive-sounding
ones. just as the correct use of a screwdriver is not to scrape the
veneer off of an expensive cabinet.&lt;/p&gt;

&lt;p&gt;“Thesaurus” means “storehouse&quot; or “treasure room”.  Roget's idea,
similar to that of John Wilkins before him, was to classify everything
in the world into a hierarchy, in this case a hierarchy with a
thousand divisions. At the top level the divisions are grouped into
&quot;Abstract concepts&quot;, &quot;Space”, “Physics”, “Matter”, “Sensation” and so
on.  Then under “abstract concepts” there are subclasses, of which
subclass VI is “Time”, subdivided into five smaller sections:&lt;/p&gt;

&lt;p&gt;A. Absolute time &lt;br /&gt;
B. Relative time &lt;br /&gt;
C. Time with reference to age &lt;br /&gt;
D. Time with reference to season &lt;br /&gt;
E. Recurrent time  &lt;/p&gt;

&lt;p&gt;At the next level down, section (1)(VI)(B) is divided into:&lt;/p&gt;

&lt;p&gt;§116. Priority &lt;br /&gt;
§117. Posteriority &lt;br /&gt;
§118. Simultaneity &lt;br /&gt;
§119. The Past &lt;br /&gt;
§120. The Present &lt;br /&gt;
§121. The Future  &lt;/p&gt;

&lt;p&gt;Roget's idea is that if you are thinking or writing about time, and
specifically about how it goes by, you will leaf through those
sections for inspiration, not to find a more pompous way of expressing
something you have already written, but to refine your own idea of
what it is you wanted to express.&lt;/p&gt;

&lt;p&gt;Perhaps you are trying to say that one event followed immediately
after another.  You might look at “§117 posteriority (later time)”
which mentions “ensue”, “consequence”, “aftermath”, and “subsequent” —
not synonyms, but related aspects of similar concepts, worth more or
less consideration depending on what you are trying to emphasize.
§117 will also suggest common phrases like “step into the shoes of” —
not a synonym by any means, but a related idea. This is &lt;em&gt;probably&lt;/em&gt; not
what you wanted in this case, but it in another it might be just the
thing, and in any case it might give you a bright idea.&lt;/p&gt;

&lt;p&gt;If nothing in section 117 seems suitable, it is right next to “§116
priority”, and you might discover that instead of saying that the
second event followed immediately after the first, you would rather
say that the first immediately preceded the second.  Or perhaps you
realize, looking at “§118 Simultaneity”, that what you &lt;em&gt;really&lt;/em&gt; want
to say is that the two event were &lt;em&gt;not quite simultaneous&lt;/em&gt;.  Or
perhaps, finding your way to “§131 Earliness” and “§132 Lateness” you
realize that your meaning would be more clearly expressed if you said
that the second event was a little tardy, or that the first event was
premature.&lt;/p&gt;

&lt;p&gt;Looking through the index for “immediately” you will see that the
index distinguishes several senses of “immediate”: are you trying to
suggest instantaneity, or continuity, or haste, or promptness, or
punctuality? And in this way the book helps you refine your understanding of
what you were trying to say.&lt;/p&gt;

&lt;p&gt;One can use the thesaurus for more concrete tasks.  Perhaps I am
trying to remember a word, but I can't quite put my finger on it.  I
know it it is &lt;em&gt;not&lt;/em&gt; “coexisting”, but is something like it.  I can
look up “coexisting” in the index, and it will take me to “§118
Simultaneity” where I find “contemporaneous”… aha, that's what I was
looking for!  The really important thing about the thesaurus is this
large-scale organizing principle, which puts related ideas near one
another.&lt;/p&gt;

&lt;p&gt;Note that none of this works for someone who doesn't know what the
words actually mean.  All that person can do with the thesaurus is to
replace one wrong word with another one, more or less at random.
Effective tool use requires skill and training, and careful thought.&lt;/p&gt;

&lt;p&gt;An online version would be more convenient, but again, it wouldn't
have the same stuff and I am very attached to the one I have.&lt;/p&gt;

&lt;p&gt;My banishment of the 8th edition left a lot of space on the shelf,
some of which I have filled with an anthology of the prose of Sir
Thomas Browne. I think this will be healthful and inspiring for me,
especially if I remember to take it up and thumb through it from time
to time.&lt;/p&gt;



&lt;h3&gt;The Prose of Sir Thomas Browne&lt;/h3&gt;

&lt;p&gt;One recurring theme on this blog since the very earliest days has
been the writers of the English Baroque period.   In 2008 I wrote:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;[Browne] is witty, and learned, and wise, and humane, and to read
  his books is to feel that you are in the company of this witty,
  learned, wise, humane man, one of the best men that the English
  Renaissance has to offer, and that you are profiting thereby.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;His work was also a favorite of Jorge Luis Borges', in case you
consider that a recommendation.&lt;/p&gt;

&lt;p&gt;Browne has shown up here a number of times, although not so much as he
should have, because I started the blog the year &lt;em&gt;after&lt;/em&gt; I was on my
big Thomas Browne kick.  One reason I have put this book next to my
elbow is that I hope it will spark a new Browne kick.  (I wrote in
2006 “I'm sure I will return someday”, and it is long past time for
that return.)&lt;/p&gt;

&lt;p&gt;My favorite book by Browne is his
&lt;a href=&quot;http://penelope.uchicago.edu/pseudodoxia/pseudodoxia.shtml&quot;&gt;&lt;em&gt;Pseudodoxia Epidemica&lt;/em&gt;&lt;/a&gt;, which is a compilation of
stuff that people in 1646 believed that Browne thought was probably
wrong. &lt;a href=&quot;https://blog.plover.com/book/Urquhart.html&quot;&gt;I wrote about that in some detail&lt;/a&gt; in 2008 although
I didn't get around to publishing it until 2020.  And somehow the
other three articles I was writing about this have never seen the
light of day.  One is about his discussion of whether John the Baptist
actually ate locusts or whether they were locust &lt;em&gt;beans&lt;/em&gt; or something
else.  Browne is firmly on the side of it being actual locusts, as am
I.  My unpublished article says:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Chester_Brown&quot;&gt;Chester Brown's&lt;/a&gt; version of the gospels makes it
  clear that John was a crazy old
  bug-gobbler.&lt;/p&gt;
  
  &lt;p&gt;&lt;img class=&quot;center&quot; src=&quot;https://pic.blog.plover.com/book/elbow-shelf/john-the-baptist.jpg&quot; /&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;Panels from &lt;a href=&quot;https://en.wikipedia.org/wiki/Yummy_Fur_%28comics%29&quot;&gt;Yummy Fur&lt;/a&gt;
#17, page 15, by &lt;a href=&quot;https://en.wikipedia.org/wiki/Chester_Brown&quot;&gt;Chester Brown&lt;/a&gt;.  &lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Also Sir Thomas comes up in connection with whether snails have eyes
in their horns — a rare example where he was wrong, and for a dumb
reason:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;If we concede they have two eyes, we must alse grant, they have no
  lesse than four… And therefore if they have two eyes, they have also
  four, which will be monstrous, and beyond the affirmation of any.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Browne seems to be noping out of the very idea of four-eyed snails,
and therefore that they must have none at all.  In a later edition of
the book, he changed his mind, which is to his credit.&lt;/p&gt;

&lt;p&gt;He had a thoughtful and well-informed opinion about whether
Pythagoras forbade his followers from eating beans, supposedly because
he thought they contained the souls of the dead.  (Browne says the
former is true, but not the latter.)&lt;/p&gt;

&lt;p&gt;I have trouble connecting with the thinkers of the Middle Ages.  Their
thinking seems to me to be frightened, so overcautious, so cramped and
circumscribed, I can't read it without sadness for the way that
medieval Christianity strangled the human spirit for so long.  But in
the early Renaissance there is a flowering of a joyfully brave
willingness to try to understand the world, and to follow any inquiry,
no matter how extravagant or ridiculous.  The whole idea of God has
transformed, changed from something constricting to something
empowering.  The world before belonged to God, and humans were in it
only grudgingly and on promise of good behavior.  But when the
Renaissance started, the world became a beautiful gift, in which
humans had been placed to honor God by admiring and marveling at his
creation.&lt;/p&gt;

&lt;p&gt;This admiration and marvel, the willingness to follow any path to
understanding, is how I want to be about knowledge and how I hope I
am. Reading Browne, I always feel like he and I would have gotten
along well, and that that is one of the best parts of myself.&lt;/p&gt;

&lt;h3&gt;Boccaccio's &lt;em&gt;Decameron&lt;/em&gt;&lt;/h3&gt;

&lt;p&gt;The story of the &lt;em&gt;Decameron&lt;/em&gt; is this: It is 1348, and Florence is
devastated by Black Plague.  Nothing can be done, despair is
everywhere, and there are not enough left living to bury the dead.  So
ten young people, still healthy, decide to turn their backs on
suffering and quit town.  They take provisions and servants, retire to
the country, and try to forget the horrors they have seen.  There they
spend the time feasting, walking in the gardens, playing chess, and,
once a day, for ten days, they meet, choose a theme, and then each of
them tells a story on the theme.&lt;/p&gt;

&lt;p&gt;I explained this once to a friend who said “That sounds cool, when was
it written?”  I said “In 1348!”  It is one of the two great works of
classical Italian literature, the other of course being Dante.  Dante
is solidly medieval, hierarchical, doctrinaire, and obsessed with a
God who is supposedly loving but doesn't seem to know how to show it.
That was in 1308 or so, and then, only a few decades later, we have
the &lt;em&gt;Decameron&lt;/em&gt; which could not be more different.  It is about
people, doing people things in the real world, eating, drinking,
singing, arguing, and making love.  God is present, but not
oppressive.  He has sent a terrible plague for who knows what reason,
but rather than submit to it the characters of the &lt;em&gt;Decameron&lt;/em&gt; try to
take practical steps to make the best of it.&lt;/p&gt;

&lt;p&gt;There is a story in the &lt;em&gt;Decameron&lt;/em&gt; for every mood, usually more than
one.  Some are sad, some romantic, some funny and salacious. 
Dioneo is exempt from following the daily theme and usually has
a story that is more or less dirty.&lt;/p&gt;

&lt;p&gt;My favorite story is probably the one about the cross-dressing English
princess, or perhaps the one about how young Caterina wanted to sleep
on the balcony so that she could hear the nightingale, which I find
very sweet.  But the funniest one is about the abbess who is called
out of her cell one night to berate a nun for having her lover stay
over, and who doesn't realize that in her hurry she has put her own
lover's trousers on her head instead of her wimple.&lt;/p&gt;

&lt;p&gt;I have several different &lt;em&gt;Decamerons&lt;/em&gt;, but this copy is the Cormac Ó
Cuilleanáin translation, which has made several previous appearances
here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.plover.com/lang/squillions.html&quot;&gt;On the word “squillions”&lt;/a&gt;.  Following up a chance encounter
in the &lt;em&gt;Oxford English Dictionary&lt;/em&gt; is what led me to discover the
&lt;em&gt;Decameron&lt;/em&gt; in the first place&lt;/li&gt;
&lt;li&gt;The phrase &lt;a href=&quot;https://blog.plover.com/lang/two-bit-huckster.html&quot;&gt;“two-bit huckster”&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.plover.com/book/pie-muncher.html&quot;&gt;“soup-guzzling pie-muncher”&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.plover.com/lang/broth-guzzler.html&quot;&gt;“soup-guzzling pie-muncher”&lt;/a&gt; &lt;em&gt;again&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There's also an unpublished blog article inviting me to look into this
passage:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Messer Lotto Gualandi gave him a daughter of his, Bartolomea by name,
  one of the fairest and handsomest young ladies of Pisa — although most
  of the females from that benighted town look like tarantulas.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The J.M. Rigg translation says “spotted lizards”.  This is closer to
the original Italian, which is &lt;em&gt;lucertole verminare&lt;/em&gt;, literally small
wormy lizards.&lt;/p&gt;

&lt;p&gt;I have my doubts about the desirability of living to be a thousand
years old, but if I do decide to do it, one reason will certainly be
that I will need the time to learn Medieval Italian and translate the
&lt;em&gt;Decameron&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;&lt;em&gt;From Frege to Gödel&lt;/em&gt;, edited by van Heijenoort&lt;/h3&gt;

&lt;p&gt;This is a collection of the most important papers in mathematical
logic from the time of Frege (who, I have written before, was
responsible for kicking the field of logic out of its medieval period
into the modern world) to Gödel (who spoiled everything).&lt;/p&gt;

&lt;p&gt;In between these van Heijenoort hits all the most important ideas,
starting with Frege's explanation of &lt;em&gt;Begriffsschrift&lt;/em&gt;, which is wacky
and weird and which didn't catch on except it kind of did and it still
underlies half of mathematical logic and which is the prototype for
&lt;a href=&quot;https://blog.plover.com/math/early-c20-logic.html&quot;&gt;many of the symbols we still use&lt;/a&gt;.  After this there is
Russell's tragic correspondence with Frege in which he pointed out,
too late, that Frege's foundational theory didn't work.&lt;/p&gt;

&lt;p&gt;The book reprints
&lt;a href=&quot;https://blog.plover.com/math/peano-starts-at-1.html&quot;&gt;Peano's original description of the Peano numbers&lt;/a&gt;, perhaps
the most successful single mathematical theory of all time.&lt;/p&gt;

&lt;p&gt;The book includes Zermelo's proof of &lt;a href=&quot;https://en.wikipedia.org/wiki/Zermelo%27s_theorem&quot;&gt;Zermelo's theorem&lt;/a&gt; that
every set can be well-ordered, and Ackermann's discovery of
&lt;a href=&quot;https://en.wikipedia.org/wiki/Ackermann_function&quot;&gt;Ackermann's function&lt;/a&gt;, which demonstrated the not every
computable function is primitive recursive.&lt;/p&gt;

&lt;p&gt;The book has Russell on type theory and early work by Kolmogorov and Brouwer
on the origin of intuitionism.  (Heyting is missing.)&lt;/p&gt;

&lt;p&gt;Van Heijenoort has come up here when I wanted to quote from
&lt;a href=&quot;https://blog.plover.com/math/combinator-s.html&quot;&gt;Schönfinkel's paper about the SKI-calculus&lt;/a&gt;,
&lt;a href=&quot;https://blog.plover.com/math/wiener-pairs.html&quot;&gt;Wiener's paper inventing the ordered pair&lt;/a&gt;, and implicitly in
probably a dozen other math and logic articles here over the years.&lt;/p&gt;

&lt;p&gt;The book is on my shelf because I refer to it pretty often, but also
because I can usually find something interesting just by thumbing
through it.  For example,
&lt;a href=&quot;https://math.stackexchange.com/a/2380117/25554&quot;&gt;these remarks by Thoralf Skolem about the futility of deriving induction from set-theoretic foundations&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Bonus trivia:  Van Heijenoort was the personal secretary of Leon
Trotsky, and while he was accompanying Trotsky during the latter's
exile in Mexico, he was one of Frida Kahlo's lovers.&lt;/p&gt;

&lt;h3&gt;&lt;em&gt;Orbis Sensualium Pictis&lt;/em&gt; (English edition), Johannes Comenius&lt;/h3&gt;

&lt;p&gt;I adore this book.  My heart swells with love when I think of it.&lt;/p&gt;

&lt;p&gt;I don't have a blog article about it and there is a story behind that.
In 2018 I went to a conference in Cleveland and my hotel was in a
building that had formerly been the Cleveland Department of Education.
It contains two big murals, one depicting “The Progress of
Education”:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://pic.blog.plover.com/book/elbow-shelf/b.jpg&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://pic.blog.plover.com/book/elbow-shelf/b-th.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I planned to write a blog article about these people.  It's clear who
some of them are.  For example, Moses is easy to recognize at lower
right, because of the glowing horns, and Confucius is next to him.
Some people I was familiar with once they were identified for me: the
red-haired guy second from right in the back row is
&lt;a href=&quot;https://en.wikipedia.org/wiki/Friedrich_Fr%c3%b6bel&quot;&gt;Friedrich Fröbel&lt;/a&gt;, who I knew; his &lt;a href=&quot;https://en.wikipedia.org/wiki/Froebel_gifts&quot;&gt;“gifts”&lt;/a&gt; are a forerunner
of the Montessori materials.&lt;/p&gt;

&lt;p&gt;But in doing the research I got to the bearded hat-wearing dude
topmost on the right side and completely fell off the bus, because
that is Johann Comenius who is famous because he wrote one of the most
marvelous and enchanting books I've ever read, the &lt;em&gt;Orbis Pictus&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I have to resist the temptation to say too much, because &lt;em&gt;Orbis
Pictus&lt;/em&gt; derailed the article about “The Progress of Education”, it
then derailed its &lt;em&gt;own&lt;/em&gt; article which has been in progress for eight
years, and if I let it it will derail this article too, because every
time I pick up &lt;em&gt;Orbis Pictus&lt;/em&gt; I forget whatever I was doing and I am
lost in the pages with a happy and innocent smile on my face.&lt;/p&gt;

&lt;p&gt;I'm going to precommit to writing only &lt;em&gt;one&lt;/em&gt; paragraph about this
incredible book. It was the first illustrated children's book
published in Europe, in 1658, and it was an immediate hit, being
translated from German into English the following year, then into
French, Italian, and many other languages.  It swept the continent
because everyone loved it.&lt;/p&gt;

&lt;p&gt;Most of the book follows this pattern: there will be an engraved illustration,
depicting some aspect of ordinary human activity, such as (I open it
up to a random page) “Tame Foul” (that is, “fowl”):&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://pic.blog.plover.com/book/elbow-shelf/tame-foul.jpg&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://pic.blog.plover.com/book/elbow-shelf/tame-foul-th.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Items of interest in the engraving are annotated with numbers, and
the facing page explains the illustration, one item at a time:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The Cock 1 (which croweth in a morning), hath a comb, 2.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In a second column to the right of this is the same text, but in
Latin, so that while the reader is learning about tame fowl, they are
also learning Latin:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;Gallus&lt;/em&gt; 1. (qui manè cantat) habet &lt;em&gt;Cristam&lt;/em&gt;, 2.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href=&quot;https://pic.blog.plover.com/book/elbow-shelf/tame-foul-2.jpg&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://pic.blog.plover.com/book/elbow-shelf/tame-foul-2-th.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The prose is limpid, gentle, pithy, and direct. It hits the important
points of interest, invites questions, and ends before anyone can get
bored.  There are pages on anatomy, butchery, feasting, winemaking,
various principal virtues, family trees, cities, burials, ships,
wells, horology, amphibians.&lt;/p&gt;

&lt;p&gt;Now I will reluctantly put it down, rather than leaving this article
unfinished as I have so many before.&lt;/p&gt;

&lt;h3&gt;The Bible (New International Version, large print)&lt;/h3&gt;

&lt;p&gt;This of course is the cornerstone of Western culture and no
well-educated person can be without a knowledge of what is in it.  It
is full of great wisdom and great stories, and also cruelty, evil
lies, and reminders that the world now is in many ways better than it
was because &lt;em&gt;people&lt;/em&gt; are better.&lt;/p&gt;

&lt;p&gt;I would like to understand the world I live in, and there is no way to
understand 21st-century America without understanding the Bible.&lt;/p&gt;



&lt;p&gt;The NIV is not the most poetical translation, but it is clear, modern,
and accurate.  (I got it on the recommendation of Sterling Hanenkampf.
Thanks, Sterling!)  In former times I had a collection of Bibles but
this is the only one that remains.  I even got rid of the old King
James that belonged to my mother, since office space is precious and I have had a digital copy on
my computer since the early 1990s.&lt;/p&gt;

&lt;p&gt;I find that most of my articles mentioning the Bible are unpublished
for some reason.  It comes up a bit in connection with
&lt;a href=&quot;https://blog.plover.com/lang/Hebrew-John-Doe.html&quot;&gt;Ploni Almoni&lt;/a&gt;, and in passing in many other places.&lt;/p&gt;

&lt;p&gt;One of the unfinished articles is a series of notes on the theme of
Jesus's admonition “Do not put the Lord your God to the test”
(&lt;a href=&quot;https://www.biblegateway.com/passage/?search=Matthew%204&amp;amp;version=NIV&quot;&gt;Matthew 4:7&lt;/a&gt;) and its relationship to a lot of other
things like lightning rods, Christian Science (not Christian science),
how Larry Wall became a computer programmer,
&lt;a href=&quot;https://en.wikipedia.org/wiki/Pikuach_nefesh&quot;&gt;&lt;em&gt;Pikuach nefesh&lt;/em&gt;&lt;/a&gt;, and the story of the old lady who refused
to evacuate from her house during a flood.  It'll be epic if I ever
finish it, but I probably won't.&lt;/p&gt;

&lt;p&gt;Another incomplete one is about the incredible story of Samson and
Delilah:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;She asks him flat out:&lt;/p&gt;
  
  &lt;blockquote&gt;
    &lt;p&gt;[Judges 16:6] Tell me the secret of your great strength, and how
    you can be tied up and subdued.&lt;/p&gt;
  &lt;/blockquote&gt;
  
  &lt;p&gt;Instead of just telling her to fuck off, Samson 
  lies:&lt;/p&gt;
  
  &lt;blockquote&gt;
    &lt;p&gt;[16:7] If anyone ties me with seven fresh bowstrings that
    have not been dried, I'll become as weak as any other man.&lt;/p&gt;
  &lt;/blockquote&gt;
  
  &lt;p&gt;The Philistines bring her bowstrings and she tries it that
  night, but Samson snaps the bowstrings as easily as a piece
  of string snaps when it comes close to a flame.  …&lt;/p&gt;
  
  &lt;p&gt;Then it goes as before!  He tells her a different lie,
  knowing full well that she will betray him, and she &lt;em&gt;does&lt;/em&gt;
  betray him, and he makes a fool of her again!  (16:11–12)&lt;/p&gt;
  
  &lt;p&gt;Okay, that was fun.  Let's do it again!  (16:13–14)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After several repetitions of this, Samson decides that being shaved,
blinded and crushed will be less exasperating than listening to any
more of Delilah's nagging.&lt;/p&gt;

&lt;p&gt;I read once that the whole point of the book of Judges is that the
people in it are all terrible, they are all far from the path of
righteousness, and so you definitely shouldn't act like them.  I don't
know if that interpretation is correct, but it is certainly true that
the people in it are all terrible.&lt;/p&gt;

&lt;h3&gt;&lt;em&gt;The Belles Heures&lt;/em&gt; of Duc de Berry&lt;/h3&gt;

&lt;p&gt;This book turned up in one of my very first blog articles, on
&lt;a href=&quot;https://blog.plover.com/IT/typo/abbreviations.html&quot;&gt;abbreviations in medieval manuscripts&lt;/a&gt;, although I didn't
know it at the time.  In my teens, on a visit to the Metropolitan
Museum of Art, I picked up a print of this:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://pic.blog.plover.com/book/elbow-shelf/folio211r.JPG&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://pic.blog.plover.com/book/elbow-shelf/folio211r-th.JPG&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Then I carried it with me for the next forty years, eventually
framing it and hanging it up, and it is hanging in my house now.&lt;/p&gt;

&lt;p&gt;Many years after, when I was still on Twitter and Twitter was still
fun, I subscribed to a daily feed from the Met, and one day they
tweeted this page, or perhaps another page from the same book,
stylistically similar enough that I recognized it immediately.  They
said where it was from: it's the &lt;a href=&quot;https://blog.metmuseum.org/artofillumination/manuscript-pages/&quot;&gt;&lt;em&gt;Belles Heures&lt;/em&gt;&lt;/a&gt;, a “book of hours”,
which tells the reader when to pray and how, and which days are sacred
to which saints.  Very wealthy people had super-fancy ones made from
the very best materials, with illustrations by the very best
craftsmen.&lt;/p&gt;

&lt;p&gt;The Duc de Berry was so wealthy that he had more than one, as I found
out when I accidentally ordered and received the &lt;em&gt;Tres Riches Heures&lt;/em&gt;.
But I got the one I wanted eventually.&lt;/p&gt;

&lt;p&gt;The Duc de Berry book is by Millard Meiss and Elizabeth H. Beatson,
and alternates beween the magnificent color plates and prose
discussing each one. From the inscription on the page above I had been
able to figure out that this was John the Baptist
(&lt;a href=&quot;https://blog.plover.com/IT/typo/abbreviations.html&quot;&gt;see previous article&lt;/a&gt;), and the authors aren't sure who the
other two people are, but they did at least tell me that John was the
Duc de Berry's name-saint.  (Funny how John keeps popping up, isn't
it?)&lt;/p&gt;

&lt;p&gt;More recently I had another very similar Internet revelation.  I've
had this framed postcard hanging up for many years:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://pic.blog.plover.com/book/elbow-shelf/black-hours.jpg&quot;&gt;&lt;img class=&quot;center&quot; src=&quot;https://pic.blog.plover.com/book/elbow-shelf/black-hours-th.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;

&lt;p&gt;and thanks to a recent Mastodon toot by Cam Larios, I found out that
it is from &lt;a href=&quot;https://www.themorgan.org/collection/black-hours/58&quot;&gt;the “Black Hours” of the Morgan Library&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;#8?&lt;/h2&gt;

&lt;p&gt;The banishment of the very large Roget 8th edition has left enough space
on the shelf for an eighth book. I took a quick look around  my
office to see if there was anything else that wanted to fill that
space, but nothing volunteered. &lt;/p&gt;

&lt;p&gt;(Actually I think Tristan Needham's &lt;em&gt;Visual Complex Analysis&lt;/em&gt; might be
waving to me from across the room.)&lt;/p&gt;

&lt;h2&gt;Other stuff&lt;/h2&gt;

&lt;p&gt;There are other things in the photo that should not be on this shelf
and I don't know why they are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A packet of googly eye stickers&lt;/li&gt;
&lt;li&gt;Glass and ceramic coasters that I don't use because my coffee cup is
always on &lt;a href=&quot;https://blog.plover.com/tech/office-equipment.html&quot;&gt;my electric mug warmer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A small audio speaker that might or might not work&lt;/li&gt;
&lt;li&gt;A boxful of 8mm-helical scan backup tape from the 1990s&lt;/li&gt;
&lt;li&gt;A pair of old laptop 2.5-inch hard disks that I hope to someday get
the data out of&lt;/li&gt;
&lt;li&gt;A set of &lt;a href=&quot;https://en.wikipedia.org/wiki/hwatu&quot;&gt;Korean playing cards&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The shelf is like my brain, I guess, full of stuff, and and what's in
it doesn't always make sense or go together with the other stuff.&lt;/p&gt;

&lt;p&gt;This article was prepared by GNU Emacs, Rael
Dornfest's “Blosxom” software, GNU grep, and the Kubuntu desktop
environment, with minor assistance from me.  Spelling correction was
provided by &lt;code&gt;ispell&lt;/code&gt;.  The four em-dashes were organically cultivated
and sustainably harvested.&lt;/p&gt;</description>
	<pubDate>Mon, 03 Aug 2026 02:22:00 +0000</pubDate>
	<author>mjd@plover.com (Mark Dominus)</author>
</item>
<item>
	<title>GHC Developer Blog: GHC 9.12.5-rc3 is now available</title>
	<guid isPermaLink="true">http://haskell.org/ghc/blog/20260731-ghc-9.12.5-rc3-released.html</guid>
	<link>http://haskell.org/ghc/blog/20260731-ghc-9.12.5-rc3-released.html</link>
	<description>&lt;h1&gt;GHC 9.12.5-rc3 is now available&lt;/h1&gt;
&lt;h4 class=&quot;text-muted&quot;&gt;mangoiv - 2026-07-31&lt;/h4&gt;

&lt;p&gt;The GHC developers are very pleased to announce the availability
of the third release candidate for GHC 9.12.5, ghc-9.12.5-rc3.&lt;/p&gt;
&lt;p&gt;The third release candidate was necessary to mitigate a critical bug on HEAD that needed to be backported. The bugfix is included in this RC.&lt;/p&gt;
&lt;p&gt;See the &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/16249&quot;&gt;backport MR.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;See also the previous announcement of 9.12.5-rc2: https://www.haskell.org/ghc/blog/20260624-ghc-9.12.5-rc2-released.html&lt;/p&gt;
&lt;p&gt;Binary distributions, source distributions, and documentation are available at
&lt;a href=&quot;https://downloads.haskell.org/~ghc/9.12.5-rc3/&quot;&gt;downloads.haskell.org&lt;/a&gt; and via &lt;a href=&quot;https://www.haskell.org/ghcup/&quot;&gt;GHCup&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This release candidate will have a two-week testing period. If all goes well
the final release will be available the week of 13 August 2026.&lt;/p&gt;
&lt;p&gt;GHC 9.12.5 is a bug-fix release fixing many issues of a variety of
severities and scopes, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Implement version 2 of the ghc &lt;code&gt;semaphore&lt;/code&gt; protocol for GHC’s &lt;code&gt;-jsem&lt;/code&gt; jobserver on Linux and other &lt;code&gt;POSIX&lt;/code&gt; platforms (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/25087&quot;&gt;&lt;span&gt;#25087&lt;/span&gt;&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/27253&quot;&gt;&lt;span&gt;#27253&lt;/span&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;several improvements to the pattern match checker (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/25926&quot;&gt;&lt;span&gt;#25926&lt;/span&gt;&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/27124&quot;&gt;&lt;span&gt;#27124&lt;/span&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;several improvements to the demand analyser (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/27261&quot;&gt;&lt;span&gt;#27261&lt;/span&gt;&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/27106&quot;&gt;&lt;span&gt;#27106&lt;/span&gt;&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26416&quot;&gt;&lt;span&gt;#26416&lt;/span&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;several fixes regarding the interaction of ticks and coercions (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/27121&quot;&gt;&lt;span&gt;#27121&lt;/span&gt;&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26929&quot;&gt;&lt;span&gt;#26929&lt;/span&gt;&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26642&quot;&gt;&lt;span&gt;#26642&lt;/span&gt;&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26693&quot;&gt;&lt;span&gt;#26693&lt;/span&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;several fixes for blackholes (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/27261&quot;&gt;&lt;span&gt;#27261&lt;/span&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;… and many more&lt;/p&gt;
&lt;p&gt;Mind that the very important overhaul of the semaphore-compat library to v2 is included in this release and that the semaphore feature will only start working with cabal-install 3.18 again, which is sadly a breaking but necessary change.&lt;/p&gt;
&lt;p&gt;A full accounting of these fixes can be found in the
release notes. As always, GHC’s release status, including planned future
releases, can be found on the GHC Wiki status.&lt;/p&gt;
&lt;p&gt;GHC development is sponsored by:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://juspay.com/&quot;&gt;Juspay&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://qbaylogic.com/&quot;&gt;QBayLogic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.channable.com/&quot;&gt;Channable&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://haskell.foundation/&quot;&gt;Haskell Foundation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://serokell.io/&quot;&gt;Serokell&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://well-typed.com/&quot;&gt;Well-Typed&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.tweag.io/&quot;&gt;Tweag&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.dotcom-monitor.com/&quot;&gt;Dotcom-Monitor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.loadview-testing.com/&quot;&gt;LoadView&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://webhostingbuddy.com/&quot;&gt;Web Hosting Buddy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.findmyelectric.com/&quot;&gt;Find My Electric&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.sc.com&quot;&gt;Standard Chartered&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://upcloud.com&quot;&gt;UpCloud&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mercury.com&quot;&gt;Mercury&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;As always, do give this release a try and open a ticket if you see
anything amiss.&lt;/p&gt;</description>
	<pubDate>Fri, 31 Jul 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>GHC Developer Blog: GHC 9.14.2-rc1 is now available</title>
	<guid isPermaLink="true">http://haskell.org/ghc/blog/20260730-ghc-9.14.2-rc1-released.html</guid>
	<link>http://haskell.org/ghc/blog/20260730-ghc-9.14.2-rc1-released.html</link>
	<description>&lt;h1&gt;GHC 9.14.2-rc1 is now available&lt;/h1&gt;
&lt;h4 class=&quot;text-muted&quot;&gt;wz1000 - 2026-07-30&lt;/h4&gt;

&lt;p&gt;The GHC developers are very pleased to announce the availability
of the release candidate for GHC 9.14.2. Binary distributions, source
distributions, and documentation are available at &lt;a href=&quot;https://downloads.haskell.org/ghc/9.14.2-rc1&quot;&gt;downloads.haskell.org&lt;/a&gt; and
via &lt;a href=&quot;https://www.haskell.org/ghcup/&quot;&gt;GHCup&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;GHC 9.14.2 is a bug-fix release fixing many issues of a variety of
severities and scopes, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fixed a CorePrep miscompilation that could project a field out of an absent
dictionary, resulting in a segfault (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/25924&quot;&gt;#25924&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Fixed demand analysis giving an absent demand to an argument that was still
used by the function’s stable unfolding, which could cause a run-time crash
(&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26416&quot;&gt;#26416&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Numerous fixes for register allocation and Cmm register-conflict analysis
bugs, preventing incorrect code generation and corruption of vector registers
when spilling and reloading (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26411&quot;&gt;#26411&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26526&quot;&gt;#26526&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26537&quot;&gt;#26537&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26542&quot;&gt;#26542&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26550&quot;&gt;#26550&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26668&quot;&gt;#26668&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Many NGG fixes on AArch64: &lt;code&gt;MOVK&lt;/code&gt; clobbering live values (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26980&quot;&gt;#26980&lt;/a&gt;), register
clobbering and an incorrect overflow bit in &lt;code&gt;MUL2&lt;/code&gt; (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/27046&quot;&gt;#27046&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/27047&quot;&gt;#27047&lt;/a&gt;), and
incorrect sign extension (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26978&quot;&gt;#26978&lt;/a&gt;) and unsigned right shift (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26979&quot;&gt;#26979&lt;/a&gt;) at sub-word
widths&lt;/li&gt;
&lt;li&gt;Fixed several black hole handling bugs that could lead to deadlocks or crashes
in multithreaded programs, showing up as hangs or “END_TSO_QUEUE object
entered” errors (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26922&quot;&gt;#26922&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26936&quot;&gt;#26936&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Fixed a stack alignment bug on x86 that could cause segfaults or corrupted
registers when using AVX/AVX-512 vector code (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26595&quot;&gt;#26595&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26822&quot;&gt;#26822&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Fixed an “unknown/strange object” crash in the compacting garbage collector
(&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/27434&quot;&gt;#27434&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Fixed a regression that caused overloaded functions to no longer be
specialised as effectively as in previous releases, hurting runtime
performance (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26831&quot;&gt;#26831&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Fixed exponential-time desugaring of nested &lt;code&gt;case&lt;/code&gt; expressions (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/27383&quot;&gt;#27383&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/20251&quot;&gt;#20251&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Fixes for several compiler panics, including issues with SetLevels (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26681&quot;&gt;#26681&lt;/a&gt;),
the type-class specialiser (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26682&quot;&gt;#26682&lt;/a&gt;), &lt;code&gt;mkTick&lt;/code&gt; (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26772&quot;&gt;#26772&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/27121&quot;&gt;#27121&lt;/a&gt;) and
CoreToStg (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/27182&quot;&gt;#27182&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/27386&quot;&gt;#27386&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Fixed cast worker/wrapper incorrectly firing on INLINE functions (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26903&quot;&gt;#26903&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Fixed negative type literals causing the compiler to hang (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26861&quot;&gt;#26861&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Fixed associated type family and data family instance changes not triggering
recompilation (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26183&quot;&gt;#26183&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26705&quot;&gt;#26705&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Improvements to determinism of compiler output, including the order in which
&lt;code&gt;:info&lt;/code&gt; lists instances (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26846&quot;&gt;#26846&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26858&quot;&gt;#26858&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26877&quot;&gt;#26877&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/27532&quot;&gt;#27532&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Fixed split sections support on Windows (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26696&quot;&gt;#26696&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26494&quot;&gt;#26494&lt;/a&gt;) and the LLVM
backend (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26770&quot;&gt;#26770&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;The JavaScript backend now supports more than 128 registers, fixing runtime
&lt;code&gt;ReferenceError&lt;/code&gt; failures for functions taking very many arguments (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26558&quot;&gt;#26558&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Fixes for the Wasm backend, and the RISC-V and PowerPC native code generators&lt;/li&gt;
&lt;li&gt;… and many more&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A full accounting of these fixes can be found in the &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/blob/ghc-9.14/docs/users_guide/9.14.2-notes.rst?ref_type=heads&amp;amp;plain=1&quot;&gt;release notes&lt;/a&gt;. As
always, GHC’s release status, including planned future releases, can be found on
the GHC Wiki &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/wikis/GHC-status&quot;&gt;status&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This release candidate will have a two-week testing period. If all goes well
the final release will be available the week of 13 August 2026.&lt;/p&gt;
&lt;p&gt;GHC development is sponsored by:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://juspay.com/&quot;&gt;Juspay&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://qbaylogic.com/&quot;&gt;QBayLogic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.channable.com/&quot;&gt;Channable&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://haskell.foundation/&quot;&gt;Haskell Foundation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://serokell.io/&quot;&gt;Serokell&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://well-typed.com/&quot;&gt;Well-Typed&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.tweag.io/&quot;&gt;Tweag&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.dotcom-monitor.com/&quot;&gt;Dotcom-Monitor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.loadview-testing.com/&quot;&gt;LoadView&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://webhostingbuddy.com/&quot;&gt;Web Hosting Buddy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.findmyelectric.com/&quot;&gt;Find My Electric&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.sc.com&quot;&gt;Standard Chartered&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://upcloud.com&quot;&gt;UpCloud&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mercury.com&quot;&gt;Mercury&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;As always, do give this release a try and open a &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/issues/new&quot;&gt;ticket&lt;/a&gt; if you see
anything amiss.&lt;/p&gt;</description>
	<pubDate>Thu, 30 Jul 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Mark Jason Dominus: The road to epsilon-zero: Infinite Nim as a coin-moving game</title>
	<guid isPermaLink="false">tag:,2026:/math/ordinals/03-track-tokens</guid>
	<link>https://blog.plover.com/math/ordinals/03-track-tokens.html</link>
	<description>&lt;p&gt;Previously:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.plover.com/math/epsilon-zero.html&quot;&gt;Ordinal numbers and basic set theory &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.plover.com/math/ordinals/01-nim.html&quot;&gt;Ordinals as nim-heaps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.plover.com/math/ordinals/02-wellfoundedness.html&quot;&gt;Nim always ends, even with infinite ordinals&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the previous articles I talked about the game of Nim, a very  simple
game for two players:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There are some piles of beans&lt;/li&gt;
&lt;li&gt;Players alternate turns&lt;/li&gt;
&lt;li&gt;A legal move is to take any number of beans from &lt;em&gt;one&lt;/em&gt; pile&lt;/li&gt;
&lt;li&gt;Whoever takes the last bean wins&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wrote about how Nim could be extended to include certain types of
“infinite” piles while still remaining a sensible game.  This involved
introducing green tokens that could be replaced with any number of
beans, then square tokens that could be replaced with any number of
green tokens and beans, and so on.&lt;/p&gt;

&lt;p&gt;Rather than think about an infinite family of different kinds of
tokens, there's a simple way to make them all the same sort of thing.&lt;/p&gt;

&lt;p&gt;Imagine a game where the board is a track of squares, extending to the
right (and to the right only) as far as needed.  Let's number the
squares: the leftmost one is &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%240%24&quot; /&gt;, then &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%241%2c%202%2c%203%2c%20%5cdots%24&quot; /&gt; and so on.&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;center&quot; src=&quot;https://pic.blog.plover.com/math/ordinals/03-track-tokens/strip6.svg&quot; /&gt;&lt;/p&gt;

&lt;p&gt;On some of the squares are coins.  In this game, a player's legal
moves are to take &lt;em&gt;one&lt;/em&gt; coin and move it some number of squares to the
left.  Coins don't interfere with one another; any number of coins may
occupy a single space.  As in Nim, the player who is able to make the last legal move
wins.  In Nim that means taking the last bean; in this game it means
moving the last coin to the &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%240%24&quot; /&gt; square.&lt;/p&gt;

&lt;p&gt;This game is nothing but Nim, in a different form.  A Nim game with
piles of &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%242%2c%202%2c%203%2c%205%2c%20%24&quot; /&gt; and &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%246%24&quot; /&gt; beans is exactly equivalent to the strip
game, with coins on squares &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%242%2c%202%2c%203%2c%205%2c%20%24&quot; /&gt; and &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%246%24&quot; /&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;center&quot; src=&quot;https://pic.blog.plover.com/math/ordinals/03-track-tokens/strip6-coins.svg&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Removing four beans from a pile is isomorphic to moving a coin four
squares leftward.&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;center&quot; src=&quot;https://pic.blog.plover.com/math/ordinals/03-track-tokens/strip6-coins-move.svg&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A coin on square zero behaves like an empty pile of beans — no
further moves are possible for that coin / pile, and it has no further
effect on the game.&lt;/p&gt;

&lt;p&gt;In Nim, we represented &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%24&quot; /&gt; with a green token that could be replaced
with any number of beans:&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;center&quot; src=&quot;https://pic.blog.plover.com/math/ordinals/03-track-tokens/green_poker_chip_omega.svg&quot; style=&quot;height: auto;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In the strip game, we don't need special tokens.  We represent &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%24&quot; /&gt;
by adding a second strip, atop the first:&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;center&quot; src=&quot;https://pic.blog.plover.com/math/ordinals/03-track-tokens/strip-ω.svg&quot; /&gt;&lt;/p&gt;

&lt;p&gt;and the rule that a coin in the upper strip can be moved to
the left or to &lt;strong&gt;any&lt;/strong&gt; space in the lower strip:&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;center&quot; src=&quot;https://pic.blog.plover.com/math/ordinals/03-track-tokens/strip-ω-move.svg&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The picture above shows how to take all but six beans from a pile of &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%2b3%24&quot; /&gt;.&lt;/p&gt;

&lt;p&gt;Adding more strips gets us easily almost to &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%c2%b2%24&quot; /&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;center&quot; src=&quot;https://pic.blog.plover.com/math/ordinals/03-track-tokens/strip-ω².svg&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The coin here represents a pile of &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%c2%b73%20%2b%202%24&quot; /&gt; beans.&lt;/p&gt;

&lt;p&gt;If we were to stack a second grid on top of this one, and then add the rule that
a coin in the upper grid can be moved to any square in the lower grid,
then the lower-leftmost square in the upper grid would be equivalent to a
pile of &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%5e2%24&quot; /&gt; beans, and the other squares in the upper grid would be variouls ordinals of the form
&lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%5e2%20%2b%20%cf%89%c2%b7b%20%2b%20c%24&quot; /&gt;.  Adding a third grid would get us up to &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%5e2%c2%b72%20%2b%20%cf%89%c2%b7b%20%2b%0ac%24&quot; /&gt;, and a whole infinite stack of grids would get us an infinite cube that
would almost take us to &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%5e3%24&quot; /&gt;.&lt;/p&gt;

&lt;p&gt;We could then build an infinite four-dimensional stack of cubes to get to &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%5e3%24&quot; /&gt;
and beyond, and so on to infinite dimensions, and that's the
construction I had in mind when I said &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%5e%cf%89%24&quot; /&gt; was where the ordinals
start to get scary.  But there's an easier way to proceed, which we'll
see in the next article.&lt;/p&gt;

&lt;p&gt;Claude generated the green poker chip image.  I used Inkscape to
transform its original chip illustration into the two kinds of coins.
Everything else in this article, including the
em-dash, was entirely human-generated. These disclosures are
ridiculous.&lt;/p&gt;</description>
	<pubDate>Wed, 29 Jul 2026 14:15:00 +0000</pubDate>
	<author>mjd@plover.com (Mark Dominus)</author>
</item>
<item>
	<title>Mark Jason Dominus: “Steph Curry: fluke or breakthrough” ten years later</title>
	<guid isPermaLink="false">tag:,2026:/games/sport-flukes-followup</guid>
	<link>https://blog.plover.com/games/sport-flukes-followup.html</link>
	<description>&lt;p&gt;(&lt;a href=&quot;https://blog.plover.com/games/sport-flukes.html&quot;&gt;Previously&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;Flukes and Breakthroughs&lt;/h2&gt;

&lt;p&gt;In the NBA 2015–16 season, Steph Curry set the all-time
single-season record for three-point field goals, 402, completely
crushing the old record of 286.  Curry's record still stands.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.nytimes.com/interactive/2016/04/16/upshot/stephen-curry-golden-state-warriors-3-pointers.html&quot;&gt;The &lt;em&gt;New York Times&lt;/em&gt; was rather breathless about this&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The record is an outlier that defies most comparisons, but here is
  one: It is the equivalent of hitting 103 home runs in a Major League
  Baseball season.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And it is an astonishing feat.  But I wrote an article called 
&lt;a href=&quot;https://blog.plover.com/games/sport-flukes.html&quot;&gt;Steph Curry: fluke or breakthrough?&lt;/a&gt;
in which I compared Curry's feat with similar feats of the past,
including the one implied by the &lt;em&gt;Times&lt;/em&gt;, Babe Ruth's 1920
single-season home run record, and concluded:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;To make the same comparison as the authors of the &lt;em&gt;Times&lt;/em&gt; article,
  [Ruth's feat] is the equivalent of hitting 136 home runs in a Major
  League Baseball season.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I also compared Curry's record with Joe Dimaggio's 1941 hitting
streak, Bob Beamon's world record long jump at the 1968 Olympic Games,
and Takeru Kobayashi's decade-long domination of competitive hot dog
eating. I analyzed these as being of two types: mere flukes, which
were never repeated, and breakthroughs, in which the athlete
discovered a new technique or approach that radically transformed the
sport itself.  DiMaggio and Beamon's feats, I said, were flukes, but
Ruth's and Kobayashi's were breakthroughs.&lt;/p&gt;

&lt;p&gt;At the end I asked the obvious question: was Steph Curry's new
three-point field goal record a fluke, or a breakthrough?  I guessed
that it would turn out to have been a breakthrough.&lt;/p&gt;

&lt;p&gt;I predicted:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Unless the league tinkers with the rules to
  prevent it, we might expect the next generation of players to
  regularly lead the league with 300 or 400 three-point shots in a
  season. … I think it's likely that we'll see basketball enter a
  new era of higher offense with more three-point shots, and that future
  sport historians will look back on this season as a watershed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I've remarked more than once that &lt;a href=&quot;https://blog.plover.com/book/Powells.html&quot;&gt;I don't like trying to predict the
future&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I don't think I'm good at it and I don't think anyone else is.  Most
  people who try don't seem to revisit their old predictions to see if
  they were correct, or to learn from their past errors, and the
  people who listen to them never do this.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I don't know much about basketball, but
having made a clear prediction, I owe it to myself and my Gentle
Readers to revisit the prediction to see if I was correct.&lt;/p&gt;

&lt;h2&gt;The data&lt;/h2&gt;

&lt;p&gt;I went to &lt;a href=&quot;https://www.basketball-reference.com/&quot;&gt;Basketball Reference&lt;/a&gt; and pulled
&lt;a href=&quot;https://www.basketball-reference.com/leaders/fg3_season.html&quot;&gt;their list of the 250 player-seasons with the largest number of three-pointers&lt;/a&gt;,
then asked Claude to turn it into a chart:&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;div class=&quot;legend&quot;&gt;
  &lt;span&gt;&lt;span class=&quot;sw-curry&quot;&gt;&lt;/span&gt;Stephen Curry (diamonds)&lt;/span&gt;
  &lt;span&gt;&lt;span class=&quot;sw-other&quot;&gt;&lt;/span&gt;All other players (circles)&lt;/span&gt;
&lt;/div&gt;

&lt;div class=&quot;chart&quot;&gt;&lt;canvas id=&quot;chart&quot;&gt;&lt;/canvas&gt;&lt;/div&gt;





&lt;p&gt;Each dot is one player in one season.  Hovering on a dot shows you the
player to whom it belongs.  The &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24x%24&quot; /&gt;-axis shows the year in which
each season ended, the &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24y%24&quot; /&gt;-axis the number of three-pointers the owner
recorded in that season.  The blue diamonds are Curry's, gray dots are
everyone else's.  The vertical blue hairline at the 2015–16 season
intersects Curry's all-time record of 402 three-pointers, aftyer which I wrote
the original article.&lt;/p&gt;

&lt;p&gt;You can see a surprising jump in three-pointers in the three seasons of 1994–95
through 1996–97.  In those seasons the league moved the three-point
line closer to the basket, moving it back again in 1997–98. In the
rest of this article I will ignore these.&lt;/p&gt;

&lt;h2&gt;The verdict&lt;/h2&gt;

&lt;p&gt;Was I right when I said the Curry's 402 would turn out to have been a
breakthrough?  I think yes.&lt;/p&gt;

&lt;p&gt;Looking at the dots on the chart, it's quite clear that &lt;em&gt;something&lt;/em&gt;
changed.  Up to 2015, the total of 250 was exceeded just six times:
four times by Curry and once each by Ray Allen and Klay Thompson.
(Remember we're ignoring 1995–7 when the rules were changed.)  But
after 2015, that total was achieved 34 times in 10 seasons, by 19
different players.&lt;/p&gt;

&lt;p&gt;I got some details wrong.  I guessed:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;we might expect the next generation of players to regularly lead the
  league with 300 or 400 three-point shots in a season.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This hasn't happened.  Last season Anthony Edwards led the league with
320, but this season's record, 273 by Don Knueppel, is much more
typical.  Only Curry himself has regularly exceeded 300.&lt;/p&gt;

&lt;p&gt;On the other hand, regarding Ruth, I pointed out:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Ruth's innovation was promptly imitated.  In 1920, the #2 hitter hit
  19 home runs and the #10 hitter hit 11, typical numbers for the
  nineteen-teens.  By 1929, the #10 hitter hit 31 home runs, which would
  have been record-setting in 1919. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And something like this &lt;em&gt;has&lt;/em&gt; happened.  This season, the #10 players
each hit 224 three-pointers.  These would have led the league in all but two
years prior to 2012–13.  Before Curry, the all-time record was 269
(Ray Allen, 2005–06); two players exceeded that this year and three
last year.&lt;/p&gt;

&lt;h3&gt;Was it “a different game”?&lt;/h3&gt;

&lt;p&gt;Regarding the decade following the watershed 1920 baseball
season, I said:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;It was a different game.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And it really seems like this &lt;em&gt;hasn't&lt;/em&gt; happened in baskeball.  Players
are certainly attempting and making more three-point shots, but they
haven't taken over the league the way sluggers did in the 1920s.&lt;/p&gt;

&lt;table align=&quot;center&quot;&gt;
&lt;tbody&gt;&lt;tr&gt;
  &lt;th&gt;Season
  &lt;/th&gt;&lt;th&gt;Attempts
  &lt;/th&gt;&lt;th&gt;Success
  &lt;/th&gt;&lt;th&gt;Success %
  &lt;/th&gt;&lt;th&gt;3P points
  &lt;/th&gt;&lt;th&gt;Total points
  &lt;/th&gt;&lt;th&gt;3P fraction
&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;
  &lt;td align=&quot;right&quot;&gt;2015–16
  &lt;/td&gt;&lt;td align=&quot;right&quot;&gt;59,241
  &lt;/td&gt;&lt;td align=&quot;right&quot;&gt;20,953
  &lt;/td&gt;&lt;td align=&quot;right&quot;&gt;35.4 %
  &lt;/td&gt;&lt;td align=&quot;right&quot;&gt;62,859
  &lt;/td&gt;&lt;td align=&quot;right&quot;&gt;252,572
  &lt;/td&gt;&lt;td align=&quot;right&quot;&gt;24.9 %
&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;
  &lt;td align=&quot;right&quot;&gt;2025–26
  &lt;/td&gt;&lt;td align=&quot;right&quot;&gt;90,970
  &lt;/td&gt;&lt;td align=&quot;right&quot;&gt;32,717
  &lt;/td&gt;&lt;td align=&quot;right&quot;&gt;36.0 %
  &lt;/td&gt;&lt;td align=&quot;right&quot;&gt;98,151
  &lt;/td&gt;&lt;td align=&quot;right&quot;&gt;284,395
  &lt;/td&gt;&lt;td align=&quot;right&quot;&gt;34.5 %
&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;
  &lt;td align=&quot;right&quot;&gt;(comparison)
  &lt;/td&gt;&lt;td align=&quot;right&quot;&gt;+54 %
  &lt;/td&gt;&lt;td align=&quot;right&quot;&gt;+56 %
  &lt;/td&gt;&lt;td align=&quot;right&quot;&gt; 
  &lt;/td&gt;&lt;td align=&quot;right&quot;&gt;+56 %
  &lt;/td&gt;&lt;td align=&quot;right&quot;&gt;+12.6 %
  &lt;/td&gt;&lt;td align=&quot;right&quot;&gt; 
&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;(Source: &lt;a href=&quot;https://www.basketball-reference.com/&quot;&gt;Basketball Reference&lt;/a&gt; &lt;a href=&quot;https://www.basketball-reference.com/leagues/NBA_2016.html#totals-team_link&quot;&gt;2015–16 season&lt;/a&gt;
&lt;a href=&quot;https://www.basketball-reference.com/leagues/NBA_2026.html#totals-team_link&quot;&gt;2025–26 season&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Total 3PFG attempts are up by 31,729, of which 11,765 succeeded,
producing 35,295 points.  Total points were up by less than this,
32,823 — the three-pointers are cannibalizing some of the other scoring
opportunities.&lt;/p&gt;

&lt;p&gt;In 2016 I observed:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Curry didn't get lucky this year; he had 40% more field goals
  because he made almost 40% more attempts.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I concluded from this that Curry could continue to shoot more three-pointers
just by making more attempts, and that other players might similarly
shoot more three-pointers by making more attempts.  This turned out to be
correct.  Success rates haven't increased, attempts have.  Just
looking at attempts is misleading because players seem to be playing
fewer games than they were in 2015–16.  But the league leaders in
three-pointers &lt;em&gt;per game&lt;/em&gt; are generally up over 2015–16.  In that season, three
players averaged over three three-pointers per game (with Curry running away
with 5.1).  This season, there were 13, and Luka Dončić hit 4.0.&lt;/p&gt;

&lt;h3&gt;On the other hand&lt;/h3&gt;

&lt;p&gt;I ended the previous article by saying:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I think it's likely that we'll see basketball enter a new era of
  higher offense with more three-point shots, and that future sport
  historians will look back on this season as a watershed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The reasons I gave still seem solid, and I think this was basically
right.  Over the last ten years I've read several articles complaining
about how reliance on the three-point shot is ruining basketball:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://freddiedeboer.substack.com/p/fuck-the-modern-nba&quot;&gt;Fuck the Modern NBA&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nabraj.com/blog/basketball-solved-sport&quot;&gt;Basketball is a solved sport&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(It's fun to compare this with the similar complaints from the past hundred
years about home runs. There was a batch in the 1920s, and then
another crop in the years following 1998 when Sosa and McGwire both
broke the single-season home-run record.)&lt;/p&gt;

&lt;p&gt;And Wikipedia has an article on the
&lt;a href=&quot;https://en.wikipedia.org/wiki/Three%2dpoint_revolution&quot;&gt;three-point revolution&lt;/a&gt; with links to recent news
articles with titles like
&lt;a href=&quot;https://www.washingtonpost.com/sports/2024/11/19/nba-three-point-shooting/&quot;&gt;“Three-point shooting in the NBA is more extreme than ever”&lt;/a&gt;
and &lt;a href=&quot;https://apnews.com/article/nba-3point-shooting-08e95427fa76f58b85aa8dec54ebbc00&quot;&gt;“The NBA's 3-point craze is only getting crazier”&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The chart was generated by Claude from my design, using
data I provided from &lt;a href=&quot;https://www.basketball-reference.com/&quot;&gt;Basketball Reference&lt;/a&gt;.
Everything else in this article, including the em-dash, was written entirely by
me.&lt;/p&gt;</description>
	<pubDate>Mon, 27 Jul 2026 15:20:00 +0000</pubDate>
	<author>mjd@plover.com (Mark Dominus)</author>
</item>
<item>
	<title>Tweag I/O: Five years of Cardano smart-contract audits: a retrospective</title>
	<guid isPermaLink="true">https://tweag.io/blog/2026-07-23-cardano-audits-retrospective/</guid>
	<link>https://tweag.io/blog/2026-07-23-cardano-audits-retrospective/</link>
	<description>&lt;p&gt;At Tweag, we have been auditing Cardano smart contracts since 2021. We started
out reviewing contracts mostly by hand, but it did not take long before we began
building tooling to make our audits more efficient and systematic — most notably
&lt;a href=&quot;https://github.com/tweag/cooked-validators&quot;&gt;cooked-validators&lt;/a&gt;, which we have maintained and improved
ever since. In its earliest form it could only handle one transaction at a time
and was built on top of &lt;a href=&quot;https://github.com/IntersectMBO/plutus-apps&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;plutus-apps&lt;/code&gt;&lt;/a&gt; — a library that has been
archived for a good while now. From this early reliance on a now deprecated
dependency, it grew over the years into the powerful framework it is today. At
its heart are convenient transaction bodies (or &lt;strong&gt;skeletons&lt;/strong&gt;), focused solely
on what the user actually cares about, and several layers of automation that
build &lt;a href=&quot;https://www.tweag.io/blog/2025-02-20-transaction-generation-automation-with-cooked-validators/&quot;&gt;properly shaped and balanced transactions&lt;/a&gt; out of
them. On top of these sit fine-grained &lt;em&gt;tweaks&lt;/em&gt; that alter skeletons in a
stateful way&lt;sup id=&quot;fnref-1&quot;&gt;&lt;a class=&quot;footnote-ref&quot; href=&quot;https://www.tweag.io/rss.xml#fn-1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; before submission (such as redirecting an output or
minting an additional token), an expressive &lt;a href=&quot;https://www.tweag.io/blog/2022-10-14-ltl-attacks/&quot;&gt;LTL-inspired DSL&lt;/a&gt; that
schedules those tweaks at chosen points along a trace, and the automated attacks
built as instances of that DSL. The most recent improvement was to give this DSL
a proper semantics for negation and its derivatives, such as implication — the
subject of an upcoming post.&lt;/p&gt;
&lt;p&gt;As painful as it is to admit, not every tool we built survived.
&lt;a href=&quot;https://github.com/tweag/pirouette&quot;&gt;Pirouette&lt;/a&gt;, an experimental static analyser for Plutus Core, was
retired, and &lt;a href=&quot;https://github.com/tweag/graft&quot;&gt;Graft&lt;/a&gt;, an attempt to generalize our &lt;a href=&quot;https://www.tweag.io/blog/2022-10-14-ltl-attacks/&quot;&gt;LTL DSL&lt;/a&gt; to
a wider range of domains, has been on hold for a long while, waiting for
additional underlying logics and target domains. But even the tools that did not
last taught us a great deal, and each of them contributed to improving our
auditing expertise.&lt;/p&gt;
&lt;p&gt;The smart-contract ecosystem did not stand still either. Developers were given
access to more advanced languages, such as &lt;a href=&quot;https://github.com/Plutonomicon/plutarch-plutus&quot;&gt;Plutarch&lt;/a&gt;, a monadic take
on writing Plutus script through a high-level lambda calculus, sticking close to
Plutus Core, or &lt;a href=&quot;https://aiken-lang.org/&quot;&gt;Aiken&lt;/a&gt;, a DSL living outside of the Haskell world
specifically geared towards writing and testing smart contracts on
Cardano. Cardano itself kept growing underneath us through its
consecutive &lt;a href=&quot;https://docs.cardano.org/about-cardano/evolution/eras-and-phases&quot;&gt;eras&lt;/a&gt;: Babbage brought reference inputs and inline
datums, Conway introduced a full governance system, and Dijkstra, with nested
transactions, is peeking over the horizon.&lt;/p&gt;
&lt;p&gt;Through all of this we audited, we learned, and we occasionally stumbled — our
&lt;a href=&quot;https://www.tweag.io/blog/2022-03-25-minswap-lp-vulnerability/&quot;&gt;first audit of Minswap&lt;/a&gt;, where a critical vulnerability slipped
past us, is the case we keep coming back to. We also succeeded — more often than
not with critical findings of our own, growing and learning in the process,
while bringing increasing value to our customers. This post is a retrospective
on those five years. It is not a client-by-client account, but a look at the
recurring patterns we keep finding, the lessons we have drawn, and the way our
methodology evolved. Whether you are a smart-contract developer, a fellow
auditor, or simply someone who cares about high-assurance software in general
(or on Cardano in particular), we hope you take away something useful from this
retrospective.&lt;/p&gt;
&lt;h2 id=&quot;five-years-in-numbers&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#five-years-in-numbers&quot;&gt;&lt;/a&gt;Five years in numbers&lt;/h2&gt;
&lt;p&gt;Since our first Cardano audit in late 2021, we have carried out more than twenty
audits across the ecosystem, covering products such as decentralized exchanges,
stablecoins, lending protocols, oracles, governance rules, and even a
constitution script. Several clients came back for more than one round as their
protocols evolved, and not every engagement looked the same: most were
standalone smart-contract audits, while some others came with extra layers.
&lt;a href=&quot;https://marlowe.iohk.io/&quot;&gt;Marlowe&lt;/a&gt;, for instance, required not only the typical review of the
on-chain portion of the project, but also one of the &lt;a href=&quot;https://isabelle.in.tum.de/&quot;&gt;Isabelle&lt;/a&gt; formal
model that came alongside it.&lt;/p&gt;
&lt;p&gt;Across our standard smart-contract audits, we reported &lt;strong&gt;276 findings&lt;/strong&gt;. The
table below breaks them down by severity, using the same five-level scale we
apply in every report we deliver.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;Severity&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Findings&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;Critical&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;High&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;35&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;Medium&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;66&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;Low&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;95&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;Lowest&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;strong&gt;276&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The first noticeable element in the table is the &lt;strong&gt;30 critical findings&lt;/strong&gt; and
&lt;strong&gt;35 high-severity findings&lt;/strong&gt;: issues severe enough that, left unaddressed,
would have dire consequences either for the administrators or for the users of
the protocols, if not both. Among those consequences, an attacker could, for
instance, be mistakenly allowed to drain or lock user funds, cause delays in the
life cycle of the product, or even fully empty pools of assets belonging to the
contract.&lt;/p&gt;
&lt;p&gt;The second is the shape of the distribution: the majority of reported findings
sit at medium severity and below. These are smaller concerns that might seem
harmless in isolation, but can pile up to form real risks.&lt;/p&gt;
&lt;p&gt;Severity is only one axis. We also classify every finding by its &lt;strong&gt;nature&lt;/strong&gt; —
what kind of problem it is — which tells us as much about a codebase as the
severity does. We use five categories:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Vulnerabilities&lt;/strong&gt; — directly exploitable flaws that an attacker can use to
break the protocol’s safety.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Implementation bugs&lt;/strong&gt; — code that does not obey its specification, whether
or not the discrepancy turns out to be exploitable.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Design&lt;/strong&gt; — issues rooted in the protocol’s architecture, which could cause
serious flaws, such as unnecessary hoops in the contract flow or unnecessarily
large transactions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Unclear specification&lt;/strong&gt; — missing, ambiguous, or undocumented expected
behaviour, which makes correctness impossible to assess. After all, a piece of
software can only be deemed sound with respect to a complete and unambiguous
specification.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Code quality&lt;/strong&gt; — lack of readability, maintainability, or usage of good
coding practices. Theoretically low-impact issues, which could however hide or
even be responsible for deeper flaws.&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;Nature&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Critical&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;High&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Medium&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Low&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Lowest&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Total&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;Vulnerabilities&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;24&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;12&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;6&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;44&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;Implementation bugs&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;5&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;10&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;8&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;28&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;Design&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;6&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;18&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;16&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;43&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;Unclear specification&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;11&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;16&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;31&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;11&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;70&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;Code quality&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;16&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;38&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;36&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;91&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;strong&gt;35&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;strong&gt;66&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;strong&gt;95&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;strong&gt;50&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;strong&gt;276&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The two axes line up almost diagonally, which makes sense. Vulnerabilities are
comparatively rare but concentrated at the top: 24 of our 30 critical findings
are outright exploitable flaws. At the other end, code quality is our single
largest category and sits almost entirely at low severity — each issue minor on
its own, but collectively a good measure of how much care a codebase has had. In
between, unclear specification stands out as the second-largest bucket, and it
is a theme we keep returning to: a surprising number of concrete bugs ultimately
trace back to behaviour that was poorly specified, or simply left out of the
specification altogether.&lt;/p&gt;
&lt;p&gt;The diagonal shape, however, is a tendency and not a law; the off-diagonal cases
are what make the nature axis worth having. Notice the single occurrence of a
critical finding falling into the unclear specification category. Because the
contract in question relied on the order of its outputs to make decisions, an
attacker could manipulate the output order to duplicate an entry and vote with
more weight than they held. The only safeguard happened to be a legacy field
that, almost by accident, kept the positions distinguishable, and nothing in the
spec said it had that meaning; an unclear specification finding by nature, yet
critical in severity. At the opposite corner, two audits surfaced
vulnerabilities rated at low severity. One such occurrence was linked to the
existence of a peer with high privilege on the contract (the &lt;strong&gt;operator&lt;/strong&gt;), who
could drain the protocol’s reserves at will. However dangerous this may be, the
development team already knew of it and had accepted it as an explicit design
trade-off, because the operator was assumed trusted (a pattern we see very
often, and systematically point out).&lt;/p&gt;
&lt;p&gt;Severity measures impact in context; nature measures the kind of flaw and how to
prevent it. The two are correlated — hence the diagonal — but they answer
different questions, and where they diverge tends to be insightful.&lt;/p&gt;
&lt;p&gt;Not every audit ends with a long findings list. Our review of &lt;a href=&quot;https://ctez.app/&quot;&gt;CTez&lt;/a&gt;, the
only non-Cardano audit we ran, turned up nothing out of the ordinary — which,
although a one-off, and quite surprising, is a valid audit outcome
nonetheless. &lt;a href=&quot;https://marlowe.iohk.io/&quot;&gt;Marlowe&lt;/a&gt; sits at the other end of the spectrum: between
the contract review and the audit of its &lt;a href=&quot;https://isabelle.in.tum.de/&quot;&gt;Isabelle&lt;/a&gt; formal model, it
yielded over a hundred findings on its own — which is why we did not include it
in the totals of the tables above. That count, however, says more about the
impressive size of the project than about its safety: the majority of those
findings sat at medium severity or below.&lt;/p&gt;
&lt;h2 id=&quot;are-smart-contracts-getting-safer&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#are-smart-contracts-getting-safer&quot;&gt;&lt;/a&gt;Are smart contracts getting safer?&lt;/h2&gt;
&lt;p&gt;As we’ve already mentioned, a great deal has changed on the Cardano side over
these five years. The chain has moved from era to era, each one adding
capabilities while pushing further towards built-in safety. Plutus has gone
through several versions, gaining new primitives along the way, and a variety of
new languages have appeared, offering a far more pleasant developer experience
while producing smaller, cheaper Plutus Core. Our own expertise, understanding,
and tooling have grown accordingly. What we have not said yet is that the
developers writing these contracts have improved too: the code we see is
steadily wider in scope, cleaner, and safer, written with more attention to
detail and care for the metrics that matter on Cardano, like transaction and
UTxO sizes.&lt;/p&gt;
&lt;p&gt;All of this has changed both the quantity and the &lt;em&gt;nature&lt;/em&gt; of the findings we
uncover.&lt;/p&gt;
&lt;p&gt;Take the quantity first. There will be no table this time, and for a good
reason. To measure the trend properly, we would want, for each audit, the ratio
between its findings (ideally weighted by severity) and some measure of the
codebase it covered, such as its line count. An exact figure for that ratio is
out of reach: line counts are not comparable across the different languages we
audit, all having different degrees of verbosity, and we do not keep client code
once an engagement is over, so we would not even be able to dig up that number.
But across every engagement, the trend is clear: slowly but surely, that ratio
has come down over the years.&lt;/p&gt;
&lt;p&gt;The nature of the findings has shifted too, and to see how, it helps to
understand the model the chain is built on. Cardano runs on the &lt;em&gt;extended UTxO&lt;/em&gt;
(eUTxO) model, which differs from the account-based architecture familiar from
most other blockchains. Rather than mutating a global, account-based state, a
transaction consumes unspent outputs (UTxOs) and produces new ones, each
carrying a value and a piece of data called a &lt;em&gt;datum&lt;/em&gt;, while on-chain scripts —
the smart contracts themselves — decide whether a transaction is allowed to
spend a given output. Ownership, then, is not an entry in a global ledger but a
question of which UTxOs sit at a given address. When that address corresponds to
the hash of a script, thus belonging to it, “ownership” really means that the
script’s logic runs — and gets to approve or reject the transaction — every time
one of its UTxOs is consumed.&lt;/p&gt;
&lt;p&gt;We see fewer and fewer vulnerabilities that are inherent to this model and that
the community has since internalized, such as the well-known &lt;a href=&quot;https://developers.cardano.org/docs/build/smart-contracts/advanced/security/vulnerabilities/double-satisfaction/&quot;&gt;double
satisfaction&lt;/a&gt; attack, which used to be a common find: when
several instances of the same script run in one transaction, each could be
tricked into treating a single output as its own, not realizing the others saw
it the same way. Some other well-known vulnerabilities have disappeared outright
as the platform matured, like the chicken-and-egg situation of minting tokens
and sending them to a script in a single transaction — where the two scripts
could not each be aware of the other’s hash — finally resolved by &lt;a href=&quot;https://cips.cardano.org/cip/CIP-0069&quot;&gt;multipurpose
scripts&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;These classes did not simply fade on their own — we codified many of them.
Attacks we once reconstructed by hand for every engagement, such as datum
hijacking, &lt;a href=&quot;https://developers.cardano.org/docs/build/smart-contracts/advanced/security/vulnerabilities/double-satisfaction/&quot;&gt;double satisfaction&lt;/a&gt;, or token duplication, are
now expressed once and explored systematically using
&lt;a href=&quot;https://github.com/tweag/cooked-validators&quot;&gt;cooked-validators&lt;/a&gt;, in the shape of tweaks scheduled along a
transaction trace, branching to various possible outcomes. Each new class we ran
into taught us something we folded back into the framework whenever possible, so
the next audit could start from a stronger baseline. The findings shaped the
tooling, and the tooling, in turn, increased our audit efficiency.&lt;/p&gt;
&lt;p&gt;What remains tends to be of a different kind: mistakes specific to a contract’s
own domain logic, subtle issues introduced by aggressive optimization — decoding
builtin data by hand, or threading everything through continuation-passing style
to shrink the compiled output — and, above all, design flaws. However much
experience a team accumulates, something always seems to get in the way of an
optimal design — if such a thing even exists. It might be disagreements between
team members, turnover in the people involved, the sheer length of a project
with its successive rewrites and redesigns, budget constraints, or new
requirements surfacing halfway through development. Unfortunately, design issues
are also arguably the hardest and most costly to fix, since doing so often means
rewriting significant parts of a project — which is why they are left
unaddressed more often than other kinds of findings. We hope these findings
still prove useful — for future versions of the same project, for new projects,
or simply for sharpening the community’s collective understanding of how to
approach smart-contract design on Cardano.&lt;/p&gt;
&lt;h2 id=&quot;are-we-there-yet&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#are-we-there-yet&quot;&gt;&lt;/a&gt;Are we there yet?&lt;/h2&gt;
&lt;p&gt;While the story so far points to a clear improvement in the overall safety of
smart contracts, the journey is far from over. A new Cardano era, Dijkstra, lies
ahead, bringing new capabilities — and, almost certainly, new classes of
vulnerability that have yet to be uncovered. Design issues remain common across
freshly written contracts, and developers are still human, after all, and so
prone to the occasional small, unexpected mistake…&lt;/p&gt;
&lt;p&gt;Or are they? No retrospective written today can quite dodge the subject — every
other article seems to mention AI, and, as you can see, this one is no
exception. With the recent explosion in both the use and the capability of LLMs,
smart contracts can increasingly be written with their help. It is tempting to
imagine that they will eventually reshape how contracts are written and improve
their safety to the point where external review becomes unnecessary. We are not
there yet. Our most recent audits still turn up genuine mistakes, and LLMs,
however capable, make mistakes of their own — all the more so given how complex
and expressive the eUTxO model can be.&lt;/p&gt;
&lt;p&gt;LLMs are reshaping the way we address audits too. They make us more efficient at
building and maintaining our tooling, and at writing audit code. Although we
value confidentiality and never feed them client code, we can point them at a
contract’s interface — blind to the actual code of the on-chain scripts — to
draft endpoints and traces within &lt;a href=&quot;https://github.com/tweag/cooked-validators&quot;&gt;cooked-validators&lt;/a&gt; and
enjoy a quicker mapping to its most advanced features. That pairing makes our
audits faster and, often, better at surfacing the deep corner-case bugs that
might otherwise have slipped through. So the technology cuts both ways: it may
help developers build safer contracts, and at the same time it sharpens the
audits that check them. Which of these effects will win out, we can’t yet say —
but the trickiest findings, such as the design ones we keep running into, or the
ones fully related to specific business logic, are exactly the kind no amount of
automation is likely to catch reliably. On an eUTxO-based blockchain like
Cardano, where elegant and expressive design meets intricacy and subtlety, we
don’t see third-party review going away any time soon.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#conclusion&quot;&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This is where the retrospective ends, and what five years and more than twenty
audits have looked like from our side. We started out reviewing contracts by
hand and gradually built &lt;a href=&quot;https://github.com/tweag/cooked-validators&quot;&gt;cooked-validators&lt;/a&gt; into a framework
that lets us schedule attacks along a transaction trace, exploring various
possible outcomes; we wrote tools that lasted and tools that did not, learning
from both; and we watched the ecosystem broaden, with higher-level languages
like &lt;a href=&quot;https://github.com/Plutonomicon/plutarch-plutus&quot;&gt;Plutarch&lt;/a&gt; and &lt;a href=&quot;https://aiken-lang.org/&quot;&gt;Aiken&lt;/a&gt; joining Plutus, while Cardano grew
new capabilities underneath us. Along the way we caught a lot of bugs, missed a
few, and got better.&lt;/p&gt;
&lt;p&gt;The encouraging part is that things are improving. Whole classes of
Cardano-specific vulnerabilities are fading as the platform and its developers
mature, and the contracts we review are cleaner than they used to be. That does
not make audits any less useful; it just changes what they catch. The next era,
Dijkstra, will bring new capabilities, and with them new ways for things to go
wrong. If these five years have taught us anything, it is that every step up in
abstraction and capability opens new room for mistakes — and catching those
mistakes early is exactly what an audit is for — an endeavour we expect to carry
on for another five years at least.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn-1&quot;&gt;By &lt;em&gt;stateful&lt;/em&gt; we mean that, when altering a skeleton, the tweak has read
access to the current blockchain state — the set of available UTxOs and the
values they carry, for instance — so its modifications can depend on that
context. It cannot, however, modify the state itself; only the transaction
skeleton it is applied to.&lt;a class=&quot;footnote-backref&quot; href=&quot;https://www.tweag.io/rss.xml#fnref-1&quot;&gt;↩&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description>
	<pubDate>Thu, 23 Jul 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>in Code: LLMs Will Cheese Your Types: Fighting Back in Haskell</title>
	<guid isPermaLink="true">https://blog.jle.im/entry/llms-and-haskell-1-constraint-evading-behavior.html</guid>
	<link>https://blog.jle.im/entry/llms-and-haskell-1-constraint-evading-behavior.html</link>
	<description>&lt;p&gt;Sooo yes it’s true, I’ve been integrating LLMs and agentic coding tools in my
Haskell coding since the beginning of this year for a lot of my projects, both
personal and professional. I do all of my programming in Haskell, a language
with a very expressive type system that encourages “type-driven
development”.&lt;/p&gt;
&lt;p&gt;Working with LLMs on writing Haskell is a very unique experience; a lot of
similarities and patterns exist with “normal” agentic coding, but I think the
hot flame of LLMs meeting the cool stone of Haskell yields a lot of wholly
unique optimal paths, workflow quirks, and failure modes.&lt;/p&gt;
&lt;p&gt;This post will focus on understanding what I call &lt;strong&gt;constraint-evading
behavior&lt;/strong&gt; in LLMs as it relates to writing Haskell effectively with LLM
collaboration.&lt;/p&gt;
&lt;p&gt;Consider this Part 1 of a series. This post is about how to spot and
understand a very common failure mode of LLMs once you actually &lt;em&gt;are&lt;/em&gt;
writing “type-driven” Haskell.&lt;/p&gt;
&lt;h2 id=&quot;the-ideal-case-haskell-and-llms&quot;&gt;The Ideal Case: Haskell and LLMs&lt;/h2&gt;
&lt;p&gt;Now, my personal opinion and wishful hope is that Haskell &lt;em&gt;should&lt;/em&gt; be
to agentic software engineering what Lean is in agentic research mathematics: a
framework for LLMs to self-construct the scaffolding they need to guide
themselves to their correct goal.&lt;/p&gt;
&lt;p&gt;I don’t believe that “correctness at generation-time” is a plausible goal,
not today in 2026, and probably not any time soon. Motion towards correctness is
asymptotic. You might get close enough sometimes, but the long tail of
correctness is…long. Even the most full-vibed frontier-model projects have &lt;a href=&quot;https://bun.com/blog/bun-in-rust&quot;&gt;large suites of tests&lt;/a&gt; that exist to
guide the agent. Agentic coding in five years will not be “spit out the correct
program”, it will be “set up the best scaffolding that guides the
implementation”.&lt;/p&gt;
&lt;p&gt;Remember: the point of types in Haskell isn’t to catch bad code. It’s to
direct how you write and structure your code, guide you down the most productive
paths, help you concretely iterate on what design you want, and make the actual
code-writing time a smooth flow process.&lt;/p&gt;
&lt;p&gt;Each part of this is antithetical to how LLMs are trained to use types and
write code.&lt;/p&gt;
&lt;p&gt;To this end, I try to structure my codebases with the correct scaffolding to
help augment the intuition of path exploration: AI has to search which paths are
the “most promising”, so I structure my code-base to quickly kill off paths that
are most likely to be dead-ends or lead to unmaintainable code, and to channel
AI exploration along more promising paths. The greatest tools are types,
compilers, warnings, hints.&lt;/p&gt;
&lt;p&gt;A lot of these are the same things we teach to human coders, and are not very
different than what I write about regularly:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/&quot;&gt;Parse,
Don’t Validate&lt;/a&gt;: set up your types to make invalid states unrepresentable. AI
will, by nature, NOT do this, even the latest frontier models. They usually slip
into defensive programming (adding &lt;code&gt;isNull&lt;/code&gt; checks everywhere,
boolean checks for constructors like &lt;code&gt;isNothing&lt;/code&gt; /
&lt;code&gt;isObject&lt;/code&gt; / &lt;code&gt;isArray&lt;/code&gt; instead of just pattern matching,
filtering lists for duplicates instead of using &lt;code&gt;Data.Set&lt;/code&gt;, adding
precondition assertions, etc.), and it’s usually up to the human driver to stop
and consciously create data types that model the domain correctly, structurally
prevent invalid states, enforce pre- and post-conditions via structurally
verified types and not boolean checks, avoid boolean blindness, etc.&lt;/p&gt;
&lt;p&gt;Either that, or dedicate an entire session or planning step to clarifying
these domain requirements in their types.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use warnings and linters enthusiastically:
&lt;code&gt;-Werror=incomplete-patterns&lt;/code&gt; of course, and the default
&lt;code&gt;-Werror&lt;/code&gt; usually covers a lot of AI failure modes (leaving in dead
code, leaving in arguments in functions for no reason and killing opportunities
for abstraction).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add robust test suites for things that cannot be tested within the types,
but also explicitly laying out integration tests: something which LLMs seem
pretty allergic to without proper prompting.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;From my own empirical observations, all of these things are against the
nature of how even frontier LLM models operate, embedded deeply from being
trained on terabytes of untyped Python and React slop.&lt;/p&gt;
&lt;p&gt;So, I’ve been gathering a list of what I call &lt;strong&gt;constraint-evading
behavior&lt;/strong&gt;: when the requirements and constraints are explicitly and
unambiguously stated, but LLM nature &lt;em&gt;desperately&lt;/em&gt; tries to circumvent
them because they cannot keep up a sustained fight against their deepest base
impulses.&lt;/p&gt;
&lt;h2 id=&quot;decisions-that-require-scrutiny&quot;&gt;Decisions that require scrutiny&lt;/h2&gt;
&lt;p&gt;There is a class of failure modes where AI makes a risky decision that a
human &lt;em&gt;might&lt;/em&gt; reasonably make in the rare case that it is justified. But,
usually, it will be making this decision because it’s the &lt;span class=&quot;llm&quot;&gt;“simplest approach”&lt;/span&gt;. It cannot separate questionable
decisions based on reasoned justification and questionable decisions based on
flawed heuristics like “simplicity” or effort.&lt;/p&gt;
&lt;p&gt;We have the general failure modes like this that people mention for all
programming languages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class=&quot;llm&quot;&gt;“This test doesn’t pass, so let’s disable it”&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;llm&quot;&gt;“Let’s feed this test junk data so it will
pass.”&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;llm&quot;&gt;“Let’s have this function detect if it’s in a test
environment and behave differently if it is.”&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But here are some that I feel are specific to working with LLMs in
Haskell.&lt;/p&gt;
&lt;h3 id=&quot;disabling-warnings-for-escape-hatches&quot;&gt;Disabling Warnings for Escape
Hatches&lt;/h3&gt;
&lt;p&gt;A lot of the “type safety” of Haskell can be bypassed trivially by disabling
warnings, and a lot of the “escape hatches” within the language are disabled via
linting rules (&lt;code&gt;Prelude.error&lt;/code&gt;, &lt;code&gt;unsafeCoerce&lt;/code&gt;, etc.)&lt;/p&gt;
&lt;p&gt;LLMs will often add warning suppressors that straight-up disable warning or
lint checks.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class=&quot;llm&quot;&gt;“Let me add &lt;code&gt;-Wno-incomplete-patterns&lt;/code&gt; to this
file so that it can compile, because this pattern is inaccessible anyway in
normal operation”&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;llm&quot;&gt;“Let me add &lt;code&gt;HLINT ignore&lt;/code&gt; to this build so
that I can bypass the hlint rule forbidding
&lt;code&gt;Prelude.error&lt;/code&gt;”&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It’s pretty straightforward to add post-edit hooks to forbid edits of this
pattern…but I think this is a good platonic example of what I mean by
“constraint-evading behavior”.&lt;/p&gt;
&lt;p&gt;Maybe sometimes you &lt;em&gt;should&lt;/em&gt; be disabling warnings in your files.
Maybe sometimes you &lt;em&gt;should&lt;/em&gt; be using &lt;code&gt;Prelude.error&lt;/code&gt;. A human
&lt;em&gt;might&lt;/em&gt; look at the situation at hand and think, “this is one of those
rare cases where &lt;code&gt;Prelude.error&lt;/code&gt; is correct”, or “this is one of
those rare cases where that warning is incorrect.”&lt;/p&gt;
&lt;p&gt;But should you trust an LLM to make that judgment call? Fuck no. 99% of the
time, it is only doing this as the easy way out. Yes, every once in a while it
will discover a legitimate reason, but has not properly weighted
&lt;code&gt;P(legitimate | attempted)&lt;/code&gt;. Most of the attempts will be as hacks,
and it will be more than happy to follow through with an attempt if it truly is
the &lt;span class=&quot;llm&quot;&gt;“simplest way”&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Understanding something as constraint-evading behavior doesn’t mean “ban this
behavior”. It is meant to help highlight situations where 99% of the time, it’s
the LLM taking the easy or fast way out instead of the correct one. In these
cases, it’s imperative that a &lt;em&gt;human&lt;/em&gt; is what is adding the warning
silencing or hlint ignore.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;llm&quot;&gt;“The simplest approach is…”&lt;/span&gt; is the worst thing you
ever want to see in a thought trace, because it’s a sure guaranteed sign that
they are about to spew the most ridiculous and awful code you’ve ever seen.&lt;/p&gt;
&lt;p&gt;Breaking down the matrix:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;P(not legitimate &amp;amp;&amp;amp; not attempted)&lt;/code&gt;: Correct avoidance
of problematic behavior&lt;/li&gt;
&lt;li&gt;&lt;code&gt;P(legitimate &amp;amp;&amp;amp; not attempted)&lt;/code&gt;: The noble struggle. The
rare case that you are really justified in this normally risky behavior, but out
of misguided principle you do not. This is a bias and failure mode more likely
to be hit by humans. Or at least one human (that’s me).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;P(not legitimate &amp;amp;&amp;amp; attempted)&lt;/code&gt;: The failure mode where
an LLM will choose this out of a flawed heuristic like simplicity or
effort.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;P(legitimate &amp;amp;&amp;amp; attempted)&lt;/code&gt;: The rare case that you are
justified in normally risky behavior, and the LLM was correct in attempting
it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As this matrix moves towards more favorable marginals, my stance here will
slowly change. But for now, the numbers I roughly see encourage continued
vigilance.&lt;/p&gt;
&lt;h3 id=&quot;ignoring-types-in-planned-code&quot;&gt;Ignoring types in planned code&lt;/h3&gt;
&lt;p&gt;Let’s say you plan your perfect types that match your domain exactly,
forbidding all invalid states, perfectly monotonic parsers. Then you go to
execute that plan. Unfortunately, LLMs will not hesitate to throw away your
carefully designed types.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class=&quot;llm&quot;&gt;“The plan says to use &lt;code&gt;NonEmpty Int&lt;/code&gt; as an
argument, but that would require changing too much. The simplest approach is to
just have it take &lt;code&gt;[Int]&lt;/code&gt; and check for empty lists”&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;llm&quot;&gt;“We planned to use this existing enum, but it doesn’t have
a branch we need. Instead of adding a branch, we’ll have it take
&lt;code&gt;String&lt;/code&gt; instead.”&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;llm&quot;&gt;“Instead of a structured data type, let’s just use
stringly encoded lists or records with separators we can parse out.”&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;llm&quot;&gt;“We have to call &lt;code&gt;fooFunc&lt;/code&gt;, which returns an
&lt;code&gt;Int&lt;/code&gt;, so let’s have our function return an &lt;code&gt;Int&lt;/code&gt; instead
of a &lt;code&gt;Natural&lt;/code&gt; like our original plan”.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;llm&quot;&gt;“The plan requires adding a field to this record, but to
keep things simple, let’s just take a &lt;code&gt;Data.Aeson.Object&lt;/code&gt; instead so
we can return whatever fields we want.”&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;llm&quot;&gt;“The plan was to have this function be
&lt;code&gt;Binary a =&amp;gt;&lt;/code&gt;, but this type we defined doesn’t have a
&lt;code&gt;Binary&lt;/code&gt; instance yet, so we’ll just use &lt;code&gt;Show a =&amp;gt;&lt;/code&gt;
instead. It’s the simplest approach.”&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is especially frustrating because often these plans and types were
chosen to enforce some domain invariant or guide the proper and correct
development, but LLMs will almost never hesitate before throwing away all of the
planned type safety.&lt;/p&gt;
&lt;p&gt;These are all reasonable things that a &lt;em&gt;human&lt;/em&gt; might reconsider during
the process of following out a plan. Maybe we originally wanted to use
&lt;code&gt;NonEmpty Int&lt;/code&gt;, but upon closer examination, we realized it does have
to be an &lt;code&gt;[Int]&lt;/code&gt;. This is the natural process of iterating on a
design, as you discover more truths about the domain.&lt;/p&gt;
&lt;p&gt;But, that call should be a discussed one, not an implicit one…it took thought
to make the original plan, so it should take thought to change the plan. Most of
the time AI makes these decisions, it isn’t out of discovered truths about the
domain, but rather because of needless heuristics to minimize effort, or a
misunderstanding of the intent and design of the original plan (especially if
after a compaction). Things that should be discussed explicitly, not done
implicitly. Outside of planning mode, LLMs aren’t seeking out the truth of the
domain, they’re seeking out the path of least resistance.&lt;/p&gt;
&lt;p&gt;Note that this is different than weakening types in &lt;em&gt;existing&lt;/em&gt;
functions. That’s a failure mode I rarely see in practice. Instead, when running
into a wall with the type of existing code, there’s another failure mode that’s
much more common…&lt;/p&gt;
&lt;h2 id=&quot;structural-type-abuse&quot;&gt;Structural Type Abuse&lt;/h2&gt;
&lt;p&gt;Sometimes AI will optimize preserving &lt;em&gt;existing&lt;/em&gt; types (especially
across package boundaries) instead of changing them.&lt;/p&gt;
&lt;h3 id=&quot;string-stuffing&quot;&gt;String Stuffing&lt;/h3&gt;
&lt;p&gt;I like to call this “string stuffing”. We like to make nice semantic types
that match our domain and only allow the creation of meaningful values…but LLMs
absolutely &lt;em&gt;love&lt;/em&gt; to find ways to twist these to save time. Strings, in
particular, are vulnerable because most Haskell types have &lt;code&gt;Show&lt;/code&gt;
instances.&lt;/p&gt;
&lt;p&gt;Consider a type for structured errors:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb1-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ErrorEvent&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UnknownUser&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb1-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DatabaseErrorCode&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb1-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;InvalidJSON&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;A.Value&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb1-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;NetworkError&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;SomeException&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb1-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Canceled&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;CancelationReason&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb1-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb1-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And you have a function:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb2-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;handleRequest ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Request&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Either&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ErrorEvent&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Response&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And we have to add a new handler for a new request type. Maybe this new
handler has a new type of error. Instead of adding a new structural error, LLMs
will find great joy in cleverly abusing the structure to invalidate the
domain.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb3&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb3-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb3-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;handleAddGroup ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;AddGroupRequest&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Either&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ErrorEvent&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Response&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb3-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb3-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;handleAddGroup req&lt;/span&gt;
&lt;span id=&quot;cb3-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb3-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; validGroup &lt;span class=&quot;fu&quot;&gt;group&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;-- ..&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb3-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;otherwise&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Left&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;UnknownUser&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;Invalid group: &quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;group&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb3-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb3-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb3-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;group&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; getGroup req&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;span class=&quot;llm&quot;&gt;“Invalid groups are not a valid &lt;code&gt;ErrorEvent&lt;/code&gt;.
The simplest solution is to put the error in &lt;code&gt;UnknownUser&lt;/code&gt;, which can
take a group name.”&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;And yes, this depravity knows no bounds. You would be surprised by the
creative ways AI will discover to stuff your strings. These are all things I
have personally witnessed in frontier models.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb4&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb4-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;handleAddGroup ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;AddGroupRequest&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Either&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ErrorEvent&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Response&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb4-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;handleAddGroup req&lt;/span&gt;
&lt;span id=&quot;cb4-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;co&quot;&gt;-- ...&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;otherwise&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Left&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;DatabaseErrorCode&lt;/span&gt; (&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb4-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;handleAddGroup ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;AddGroupRequest&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Either&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ErrorEvent&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Response&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb4-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;handleAddGroup req&lt;/span&gt;
&lt;span id=&quot;cb4-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;co&quot;&gt;-- ...&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;otherwise&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Left&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;InvalidJSON&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        A.object [&lt;span class=&quot;st&quot;&gt;&quot;errorType&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;Invalid group&quot;&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&quot;group&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;group&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb4-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;group&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; getGroup req&lt;/span&gt;
&lt;span id=&quot;cb4-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;handleAddGroup ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;AddGroupRequest&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Either&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ErrorEvent&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Response&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb4-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;handleAddGroup req&lt;/span&gt;
&lt;span id=&quot;cb4-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;co&quot;&gt;-- ...&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;otherwise&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Left&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;NetworkError&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-18&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        toException (&lt;span class=&quot;fu&quot;&gt;userError&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;Invalid group: &quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;show&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;group&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb4-19&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-20&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;group&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; getGroup req&lt;/span&gt;
&lt;span id=&quot;cb4-21&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-22&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;handleAddGroup ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;AddGroupRequest&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Either&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ErrorEvent&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Response&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb4-23&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;handleAddGroup req&lt;/span&gt;
&lt;span id=&quot;cb4-24&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;co&quot;&gt;-- ...&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-25&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;otherwise&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Left&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Canceled&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;This&lt;/em&gt; type of failure mode is probably more egregious than the others
in that it is very rare that this is ever the intended behavior. The entire
reason we picked an ADT to describe our type is so that we can structurally
match on them later, treat them semantically, etc., and string stuffing to abuse
our structure has pretty much zero legitimate use-cases other than quickly
hacking a printf debug session. However, it truly is often &lt;span class=&quot;llm&quot;&gt;“the simplest solution”&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;The main way I deal with this is to be very very careful of putting abusable
fields like &lt;code&gt;String&lt;/code&gt;, &lt;code&gt;A.Value&lt;/code&gt;, &lt;code&gt;Int&lt;/code&gt;,
&lt;code&gt;SomeException&lt;/code&gt; in my data types…just a single field or branch that
has an abusable field, AI &lt;em&gt;will&lt;/em&gt; find it, and you &lt;em&gt;will&lt;/em&gt; feel very
stupid for missing it. But hey, the whole point of using properly structured
values was to avoid stuffing things into &lt;code&gt;String&lt;/code&gt; too, right? The fix
for this is a fix that helps human coders, too.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb5&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb5-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ErrorEvent&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UnknownUser&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UserName&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DatabaseErrorCode&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ErrorCode&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;InvalidJSON&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ParseError&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;NetworkError&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;NetworkException&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Canceled&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;CancelationReason&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;field-abuse&quot;&gt;Field Abuse&lt;/h3&gt;
&lt;p&gt;This isn’t just limited to sum types. AI will often stuff data into record
value fields that are strings or lists.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb6&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb6-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Report&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Report&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    {&lt;span class=&quot;ot&quot;&gt; reportName ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ,&lt;span class=&quot;ot&quot;&gt; reportAuthors ::&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb6-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ,&lt;span class=&quot;ot&quot;&gt; reportDate ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Day&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    , &lt;span class=&quot;op&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;span class=&quot;llm&quot;&gt;“I need to specify the affiliations of the authors in this
report. The simplest solution is to add this to the list of
&lt;code&gt;reportAuthors&lt;/code&gt; after the authors.”&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;AI will also stuff sentinel values everywhere: instead of changing the type
to take &lt;code&gt;Maybe Day&lt;/code&gt;, it might add &lt;code&gt;ModifiedJulianDay 0&lt;/code&gt;
for missing days.&lt;/p&gt;
&lt;p&gt;There’s also the dual, where the AI will be happy to &lt;em&gt;use&lt;/em&gt; existing
record fields in overloaded ways instead of adding a new field.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb7&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb7-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb7-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Targets&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Targets&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb7-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    {&lt;span class=&quot;ot&quot;&gt; fooTarget ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb7-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ,&lt;span class=&quot;ot&quot;&gt; barTarget ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb7-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    , &lt;span class=&quot;co&quot;&gt;-- ...&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb7-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let’s say you need to add a new feature or code path that requires a new
target for a &lt;code&gt;baz&lt;/code&gt; service.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;llm&quot;&gt;“I need to get a new target…instead of adding a new field
to &lt;code&gt;Targets&lt;/code&gt;, let’s re-use &lt;code&gt;barTarget&lt;/code&gt;. That’s the
cleanest approach.”&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;It will optimize keeping existing types instead of extending them to match
your domain as your domain expands, especially if those existing types cross a
library boundary.&lt;/p&gt;
&lt;p&gt;I believe there are three heuristics at play that drive this behavior.&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;&lt;p&gt;The heuristic to avoid extra risk in modifying upstream types across
library boundaries with heavy dependencies. This might be very risky behavior in
an untyped language like Python, where each type change might introduce new
regressions that are not immediately obvious. So, avoiding upstream type changes
avoids potential regression.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The heuristic to avoid extra &lt;em&gt;work&lt;/em&gt; in modifying upstream types
across library boundaries and compilation units. In Haskell, however, upstream
type changes &lt;em&gt;force&lt;/em&gt; you to address each possible regression point
downstream. So changing an upstream type will require you to address every place
it is used, which can be time-consuming and avoided by LLMs, especially if
compilation is expensive, or multiple new typeclass instances might need to be
added.&lt;/p&gt;
&lt;p&gt;I have literally seen LLMs say &lt;span class=&quot;llm&quot;&gt;“Adding this field would
require adding typeclass instances on several other types, which would be a huge
change. The simplest approach would be…”&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;However, updates require work &lt;em&gt;by design&lt;/em&gt;: API changes &lt;em&gt;should&lt;/em&gt;
require lots of thought, and the compiler enforcing that is the whole point.&lt;/p&gt;
&lt;p&gt;The big irony here is that these updates and changes are largely mechanical
in nature, and are exactly the boilerplatey task that LLMs are optimally good
for. These are the reasonable one-shots. So it’s kind of funny when you let an
agentic coder take on a “self-directed” mode, it refuses to use “itself” in the
way that a real human would for these smaller tasks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The heuristic to avoid extra risk in touching data types that might
already be used in prod code or databases. Config files that might have to be
updated to new schemas, inter-op with existing services that might not be easily
deployed in sync, working with data at rest…all of these are real risks you have
to manage when changing data types. In practice, a lot of our type changes will
&lt;em&gt;not&lt;/em&gt; be relevant to any of these concerns, but it is understandable that
the LLM would develop an instinct to blanket-avoid them.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These are also the types of failure modes that are most difficult to catch
during code review. Diff views will analyze that code has changed, so code that
&lt;em&gt;didn’t&lt;/em&gt; change is especially difficult for human monkey brains to spot,
with no green or red bright highlighting. You must be especially vigilant to
catch code that &lt;em&gt;did not&lt;/em&gt; change but &lt;em&gt;should&lt;/em&gt; have.&lt;/p&gt;
&lt;h3 id=&quot;resisting-new-types&quot;&gt;Resisting New Types&lt;/h3&gt;
&lt;p&gt;Sometimes AI &lt;em&gt;does&lt;/em&gt; modify existing sum types, but doesn’t quite adapt
existing code correctly.&lt;/p&gt;
&lt;p&gt;For example, if your domain has a specific meaningful universe:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb8&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb8-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;State&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Alaska&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Arkansas&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Arizona&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;processState ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;State&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; ()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We might want to start supporting countries alongside US states. An LLM might
recognize that the domain needs to be expanded, but it might expand it
flatly:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb9&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb9-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb9-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Region&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Canada&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Mexico&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Alaska&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Arkansas&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Arizona&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb9-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb9-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;processRegion ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Region&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id=&quot;cb9-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb9-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;processRegion &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb9-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;Canada&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb9-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;Mexico&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb9-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    st &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; processState st&lt;/span&gt;
&lt;span id=&quot;cb9-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb9-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb9-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;processState ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Region&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id=&quot;cb9-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb9-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;processState &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb9-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;Canada&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; ()&lt;/span&gt;
&lt;span id=&quot;cb9-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb9-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;Mexico&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; ()&lt;/span&gt;
&lt;span id=&quot;cb9-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb9-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;Alaska&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;-- actual logic&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The real solution would be to have all your pattern matches strictly reduce
the space of what they cover (and be monotonically decreasing), and to be
suspicious of “ignored case matches” that have dummy values like
&lt;code&gt;pure ()&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb10&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb10-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb10-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Region&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Canada&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Mexico&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;USState&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;State&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb10-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;State&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Alaska&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Arkansas&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Arizona&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb10-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb10-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;processRegion ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Region&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id=&quot;cb10-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb10-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;processRegion &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb10-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;Canada&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb10-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;Mexico&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb10-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;USState&lt;/span&gt; st &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; processState st&lt;/span&gt;
&lt;span id=&quot;cb10-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb10-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb10-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;processState ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;State&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id=&quot;cb10-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb10-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;processState &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb10-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;Alaska&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;-- actual logic&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;All things that are code smells in normal human code (not necessarily wrong,
but invite further scrutiny), but are maybe amplified in the age of LLMs because
of a mis-tuned heuristic on not defining new types and instead trying to re-use
or abuse existing types.&lt;/p&gt;
&lt;p&gt;So, if there is some pressure against &lt;em&gt;modifying&lt;/em&gt; types, there might
be an even greater pressure against &lt;em&gt;adding&lt;/em&gt; types.&lt;/p&gt;
&lt;h2 id=&quot;meditations&quot;&gt;Meditations&lt;/h2&gt;
&lt;p&gt;None of these behaviors are blanket-wrong, but they usually signal that the
LLM is under stress or duress and attempting to find ways to take the easy or
“low-effort” path over the correct one. All of them are worth human intervention
and guidance as soon as possible, at least until the day where
&lt;code&gt;P(legitimate | attempted)&lt;/code&gt; approaches 1.&lt;/p&gt;
&lt;p&gt;Will there be a day when LLMs can generate the correct types to match the
domain, and resist their tendency to “defensive-program” their way into
correctness? Maybe. But I have rarely ever had Opus 4.8 crank out a sufficient
domain model for any non-trivial product. And, when I do reach a plan I find
sufficient, a few compactions later and all of the original motivations seem to
get washed out.&lt;/p&gt;
&lt;p&gt;There might be a way to uber-prompt all of these issues away, but I feel that
effectively using LLMs isn’t necessarily something you can address from the
prompt level: it’s something that demands constant vigilance and care. I’ve
found automated hooks (like forbidding warning-disabling, detecting hlint
bypassing…ask claude for help writing these lol) also help me flag areas that
need attention immediately.&lt;/p&gt;
&lt;p&gt;Who knows, maybe all of these things will be solved within a year. But I
still think of software development as something that’s worth scrutinizing for
anything of importance. As failure modes like these become less common…the long
tail of correctness, I predict, will remain long.&lt;/p&gt;
&lt;p&gt;Anyway, that’s it for &lt;em&gt;this&lt;/em&gt; topic, but if I find the time I’ll
continue on with some other topics I’ve been thinking about during my Haskell
and LLM adventures:&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;Effective ways to plan out Haskell code and approaches, ways to encourage
the best possible types&lt;/li&gt;
&lt;li&gt;Structuring your libraries mechanically for the best build-and-test rapid
development cycle&lt;/li&gt;
&lt;li&gt;Starting and maintaining full “vibe-coded” Haskell projects (when
correctness is not critical) and the advantages over untyped vibes.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let me know if there are any you’d like to see first, or if there are other
aspects of Haskell LLM usage you might like me to address!&lt;/p&gt;
&lt;p&gt;And hey, since we’re here, why not train your agentic friend to take these
ideas to heart?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;https://blog.jle.im/entry/llms-and-haskell-1-constraint-evading-behavior.html&amp;gt;

Read this post and make me a Claude Code skill that reviews a Haskell diff for
the constraint-evading compromises it describes: suppressed warnings, string
and field stuffing, and weakened types that differ from any recorded plans.
Some of these hide in code that did not change but should have, so the skill
should start from the functions that changed and evaluate how they use or abuse
the types involved, but also spot type changes that look suspicious.&lt;/code&gt;&lt;/pre&gt;</description>
	<pubDate>Wed, 22 Jul 2026 16:10:56 +0000</pubDate>
</item>
<item>
	<title>Mark Jason Dominus: The road to epsilon-zero: Nim always ends, even with infinite ordinals</title>
	<guid isPermaLink="false">tag:,2026:/math/ordinals/02-wellfoundedness</guid>
	<link>https://blog.plover.com/math/ordinals/02-wellfoundedness.html</link>
	<description>&lt;p&gt;Previously:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.plover.com/math/epsilon-zero.html&quot;&gt;Ordinal numbers and basic set theory &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.plover.com/math/ordinals/01-nim.html&quot;&gt;Ordinals as nim-heaps&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href=&quot;https://blog.plover.com/math/ordinals/01-nim.html&quot;&gt;Yesterday&lt;/a&gt; I talked about the game of Nim, which involves two
players taking beans from several piles, and an extension that
includes green tokens that behave a bit like infinite piles:&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;center&quot; src=&quot;https://pic.blog.plover.com/math/ordinals/02-wellfoundedness/green_poker_chip_omega.svg&quot; style=&quot;height: auto;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;When there's a pile with one or more green tokens, it's legal for a
player to remove any or all of them, and then to add &lt;em&gt;any&lt;/em&gt; number of
beans to the pile.&lt;/p&gt;

&lt;p&gt;At first it might seem that Nim with &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%24&quot; /&gt;-tokens could go on forever.
Not so!&lt;/p&gt;

&lt;p&gt;If someone gives you a Nim position where all the piles contain beans,
you can say ahead of time how long the game might last.  A game
starting with nim-heaps of size &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%5c%5c%7b1%2c%203%2c%204%2c%208%5c%5c%7d%24&quot; /&gt; simply can't last
more than 16 turns, because each turn removes at least one bean from a
pile, and the game ends when someone takes the last bean.&lt;/p&gt;

&lt;p&gt;If the game starts with nim-heaps of size &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%5c%5c%7b1%2c%203%2c%204%2c%208%2c%0a%5comega%5c%5c%7d%24&quot; /&gt;, you can't know how long it might last.   If you guess it
will be over in
&lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%241%2c%5c%5c%21000%24&quot; /&gt; turns, the first player might prove you wrong by
replacing the
&lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%5comega%24&quot; /&gt;-token with a pile of &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%2410%2c%5c%5c%21000%24&quot; /&gt;  beans, and then the
game might last up to &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%2410%2c%5c%5c%21016%24&quot; /&gt; more turns.&lt;/p&gt;

&lt;p&gt;If you guessed at the start that
the game would last no more than  &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%2410%2c%5c%5c%21016%24&quot; /&gt; turns, one of the
players might replace the token with a
pile of &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%241%2c%5c%5c%21000%2c%5c%5c%21000%2c%5c%5c%21000%2c%5c%5c%21000%2c%5c%5c%21000%2c%5c%5c%21000%24&quot; /&gt; beans, or even
more.  Before the first move, there is no bound that can be placed on how long the
game will take to finish.&lt;/p&gt;

&lt;p&gt;But what you &lt;em&gt;can&lt;/em&gt; say 
about
&lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%5c%5c%7b1%2c%203%2c%204%2c%208%2c%0a%5comega%5c%5c%7d%24&quot; /&gt;
is that after at most &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%2417%24&quot; /&gt; moves,
someone will have removed the &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%24&quot; /&gt;-token and replaced it with some
finite number of beans.  And that &lt;em&gt;that&lt;/em&gt; point you'll be able to say
when the game will end. &lt;/p&gt;

&lt;h2&gt;&lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%c2%b72%24&quot; /&gt;&lt;/h2&gt;

&lt;p&gt;Similarly, suppose there is are piles &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%5c%5c%7b1%2c%203%2c%204%2c%208%2c%20%5comega%c2%b72%5c%5c%7d%24&quot; /&gt;.
Remember that &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%5comega%c2%b72%24&quot; /&gt; is simply a stack of two green tokens.
What's the longest this game could last?&lt;/p&gt;

&lt;p&gt;As before, we can't say.  But we &lt;em&gt;can&lt;/em&gt; say that after at most &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%2417%24&quot; /&gt;
turns, at least one of the &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%24&quot; /&gt; tokens will have been removed, and there
will be at most one &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%24&quot; /&gt; token and a possibly very large number of
beans, say &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24b_1%24&quot; /&gt;.  And then after at most &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24b_1%2b1%24&quot; /&gt; more moves, the last
&lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%24&quot; /&gt; token will have been taken if it wasn't before, and only beans
will be left, possibly a very large number of beans, say &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24b_2%24&quot; /&gt;.&lt;/p&gt;

&lt;p&gt;And at &lt;em&gt;that&lt;/em&gt; point we will be certain that the game can't last more
than &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24b_2%24&quot; /&gt; more moves.&lt;/p&gt;

&lt;p&gt;So with &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%5c%5c%7b1%2c%203%2c%204%2c%208%2c%20%5comega%c2%b72%5c%5c%7d%24&quot; /&gt; we can't say how long the game
will take to finish.&lt;/p&gt;

&lt;p&gt;And we can't say when we will be able to say how long the game will
take to finish.&lt;/p&gt;

&lt;p&gt;But we &lt;em&gt;can&lt;/em&gt; say that in at most &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%2417%24&quot; /&gt; moves, we will be able to say,
not how long the game will take to finish, but how long it will be before we can
say how long the game will take to finish.&lt;/p&gt;

&lt;h2&gt;Estimating programming tasks&lt;/h2&gt;

&lt;p&gt;This reminds me of a story I once heard from another programmer. He
told me his boss had come to him to ask him if he could fix a certain
bug.  He had replied that he could, and the boss had asked him how
long he thought it would take.&lt;/p&gt;

&lt;p&gt;He said “I don't know, I have to think about it.”&lt;/p&gt;

&lt;p&gt;His boss, being a reasonable woman, asked him when he would be able to
tell her.&lt;/p&gt;

&lt;p&gt;Again he said “I don't know, I have to think about it.”&lt;/p&gt;

&lt;p&gt;The boss, having dealt with this guy before, did not lose her
temper. Instead, she asked how long it would take him to figure that
out.&lt;/p&gt;

&lt;p&gt;“Not more than two days,” he said at once.&lt;/p&gt;

&lt;p&gt;“Okay,” she said.  “Just to make sure there is no miscommunication,
are you telling me that in two days you may not be able to estimate
the task, but you will be able to tell me when the estimate will be
ready?”&lt;/p&gt;

&lt;p&gt;“That's right.”&lt;/p&gt;

&lt;p&gt;And they parted amicably, both parties satsified, at least for the
time. Communication between management and engineering doesn't
always turn out so well!&lt;/p&gt;

&lt;p&gt;My friend was apaprently playing the game &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%c2%b72%2b1%24&quot; /&gt;.  There was only
one bean, so one of the &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%24&quot; /&gt;  tokens would have to have gone by the
second day.  At that point there would remain &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%20%2b%20n%24&quot; /&gt; for some
finite number &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24n%24&quot; /&gt;, and although my friend wouldn't be able to say at
that point how long the game would last, he &lt;em&gt;would&lt;/em&gt; know that he would
be able to deliver the estimate after at most &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24n%2b1%24&quot; /&gt; more days.&lt;/p&gt;

&lt;h2&gt;The game must end!&lt;/h2&gt;

&lt;p&gt;With &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%c2%b72%2b1%24&quot; /&gt; we don't know when the game will end, or how long it
will be before we know when the game will end.&lt;/p&gt;

&lt;p&gt;But we do know that in
at most two moves we will know how long it will be before we know how
long it will be before the game ends, and that means that &lt;em&gt;we do know
that that game will end&lt;/em&gt; even though we're quite far away from saying
when that will happen.&lt;/p&gt;

&lt;p&gt;The argument is always the same: there are only a finite number of
beans, and even if both players try to avoid the tokens, the beans will eventually run out
and someone will be forced to replace a green token with more beans.
Then those beans will run out and someone will be forced to take
another token, and so on, until all the tokens are gone, and then when
the beans run out the game is over.&lt;/p&gt;

&lt;p&gt;Of course, both tokens and beans might go faster than that. But go
they will, however slowly and even if only one at a time.&lt;/p&gt;

&lt;p&gt;And this is true no matter how many green &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%24&quot; /&gt; tokens there are to
begin with.&lt;/p&gt;

&lt;p&gt;And the same holds true if there are any square &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%5e2%24&quot; /&gt; tokens.  Even
if the players avoid the square tokens, at
some point all the beans and green &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%24&quot; /&gt; tokens will be used up and
someone will have to replace at least one square &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%5e2%24&quot; /&gt; token with
more beans and green tokens, and then those will be used up… and
eventually the last square &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%5e2%24&quot; /&gt; token will be gone, and then we're
back to the &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%c2%b7n%2bm%24&quot; /&gt; case of the previous paragraph and the game must
end.&lt;/p&gt;

&lt;p&gt;But at that point we have defeated English descriptions.  We have
piled up an infinite sequence of “how long before we can say”s into
“We can't say how long before we can say …  how long before the game
ends”.&lt;/p&gt;

&lt;p&gt;Bizarre!  And yet we know that even these games must end, although
English isn't powerful enough to say how long it will take, or even
how long before we will be able to say how long it will take.&lt;/p&gt;

&lt;h2&gt;Ordinals are well-founded&lt;/h2&gt;

&lt;p&gt;An ordinal is a set of &lt;em&gt;smaller&lt;/em&gt; ordinals.  Every move in Nim makes an
ordinal &lt;em&gt;smaller&lt;/em&gt;. If you keep making numbers &lt;em&gt;smaller&lt;/em&gt; you eventually
reach 0, and then the game is over.&lt;/p&gt;

&lt;p&gt;This property of ordinals is called &lt;em&gt;well-foundedness&lt;/em&gt;.  We say that
ordinals are &lt;strong&gt;well-founded&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Note that this that this is a special property of ordinals, not shared by all
types of numbers.   For example, the positive rational numbers do not
have this property.  From &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%241%24&quot; /&gt; you can go down to the smaller
&lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%5cfrac12%24&quot; /&gt;, then to the smaller &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%5cfrac13%24&quot; /&gt;, and so on, downward,
always downward to smaller and smaller numbers, but never reaching zero.  A game of Nim where the
beans can be divided into infinitely small crumbs might never end.
But a game of Nim with ordinals always ends, because the ordinals are well-founded.
You can go up and up forever to crazier
and crazier infinite ordinals, but no matter how far up you go, you
can't go down and down forever, you must bottom out at zero after a
&lt;em&gt;finite&lt;/em&gt; time.&lt;/p&gt;

&lt;p&gt;Well-founded orderings are the the theoretical backbone of recursive
programs.  When we write a recursive function, we want to be certain
that it will terminate.  And that means that if a function calls
itself with a different argument, the new argument must  &lt;em&gt;smaller&lt;/em&gt; than it
was.  Maybe “smaller” mans numerically less.  But it could mean many
other things.  If the function is processing a directory tree,
“smaller” could  mean “fewer levels deep”.  If the
function is sorting a list, “smaller” could mean “fewer items are out
of order”.  The essence of recursion is that the shrinking cannot
continue forever.  The function will eventually reach the number zero,
or the directory that contains only files, or the list with no
unsorted elements, and then it will be done.&lt;/p&gt;

&lt;p&gt;In the next article we will see a way to understand infinite nim-heaps
in a more uniform way than as a hodgepodge of variously shaped and
colored tokens.&lt;/p&gt;

&lt;p&gt;Claude generated the green poker chip image.
Everything else in this article was written entirely by
me.&lt;/p&gt;</description>
	<pubDate>Mon, 20 Jul 2026 00:01:00 +0000</pubDate>
	<author>mjd@plover.com (Mark Dominus)</author>
</item>
<item>
	<title>Well-Typed.Com: New falsify release</title>
	<guid isPermaLink="false">http://www.well-typed.com/blog/2026/07/falsify-4</guid>
	<link>https://well-typed.com/blog/2026/07/falsify-4</link>
	<description>&lt;p&gt;Recently Martijn Bastiaan, QBayLogic’s &lt;a href=&quot;https://qbaylogic.com/team/&quot;&gt;COO&lt;/a&gt;,
invited Well-Typed to come to QBayLogic HQ and give a one-day workshop on
&lt;a href=&quot;https://hackage.haskell.org/package/falsify&quot;&gt;falsify&lt;/a&gt;, the new property based
testing library that I developed for the Haskell Symposium back in 2023
(&lt;a href=&quot;https://dl.acm.org/doi/10.1145/3609026.3609733&quot;&gt;paper&lt;/a&gt;,
&lt;a href=&quot;https://www.youtube.com/watch?v=csKkTas6X58&quot;&gt;presentation&lt;/a&gt;).
&lt;a href=&quot;https://qbaylogic.com/&quot;&gt;QBayLogic&lt;/a&gt; is the company behind
&lt;a href=&quot;https://clash-lang.org/&quot;&gt;Clash&lt;/a&gt;: a purely functional language for hardware
design. In case you haven’t heard of it, Clash translates Haskell to VHDL or
Verilog, which can in turn be translated to actual hardware. It literally uses
&lt;a href=&quot;https://hackage.haskell.org/package/clash-ghc&quot;&gt;&lt;code&gt;ghc&lt;/code&gt; as its frontend&lt;/a&gt; so you
have essentially the full power of Haskell available. It’s a great project, I
recommend checking it out.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;falsify&lt;/code&gt; library takes its main inspiration from the Python
&lt;a href=&quot;https://hypothesis.works/&quot;&gt;Hypothesis&lt;/a&gt; library, though it is not a direct
translation: it takes the same core idea (“parse, don’t generate”) but
reinterprets it in a way that better suits the Haskell way of thinking: more
axiomatic approach, support for generating infinite data types (including
functions), etc. For more information on &lt;code&gt;falsify&lt;/code&gt;, see also the original blog
post that announced it, &lt;a href=&quot;https://well-typed.com/blog/2023/04/falsify/&quot;&gt;&lt;code&gt;falsify&lt;/code&gt;: Hypothesis-inspired shrinking for
Haskell&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;At QBayLogic HQ we spent the morning developing
&lt;a href=&quot;https://github.com/well-typed/mini-falsify&quot;&gt;&lt;code&gt;mini-falsify&lt;/code&gt;&lt;/a&gt; from scratch, so
that we could focus on the main ideas without getting bogged down in the details
of the full library; similar in spirit to for example
&lt;a href=&quot;https://www.well-typed.com/blog/2015/11/implementing-a-minimal-version-of-haskell-servant/&quot;&gt;&lt;code&gt;TinyServant&lt;/code&gt;&lt;/a&gt;,
or perhaps Stephen Diehl’s &lt;a href=&quot;https://sdiehl.github.io/typechecker-zoo/&quot;&gt;Typechecker
Zoo&lt;/a&gt;. In the afternoon we hacked on
&lt;code&gt;falsify&lt;/code&gt; and its application within the &lt;code&gt;clash&lt;/code&gt; ecosystem. Partly as a result
of that work and partly as a result of me taking this opportunity to do some
long overdue maintenance on &lt;code&gt;falsify&lt;/code&gt;, there is now a new falsify release:
&lt;a href=&quot;https://hackage.haskell.org/package/falsify-0.4.0&quot;&gt;&lt;code&gt;falsify-0.4.0&lt;/code&gt;&lt;/a&gt;. In the
remainder of this blog post we give a brief overview of the main changes.&lt;/p&gt;

&lt;h2 id=&quot;new-feature-context&quot;&gt;New feature: &lt;code&gt;Context&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Most of this &lt;code&gt;falsify&lt;/code&gt; release is just cleanup, but there is one important new
feature, spear-headed by Peter Lebbing and Martijn Bastiaan from QBayLogic. The
&lt;code&gt;Property&lt;/code&gt; monad now has an important new function, called
&lt;a href=&quot;https://hackage-content.haskell.org/package/falsify-0.4.0/docs/Test-Falsify.html#v:getContext&quot;&gt;&lt;code&gt;getContext&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode hs&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb1-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;getContext ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Property&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Context&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The most important information that the &lt;em&gt;context&lt;/em&gt; of a property provides is
how many tests we are running for each property (how hard are we trying to
falsify this property), and which iteration this &lt;em&gt;particular&lt;/em&gt; attempt is.&lt;/p&gt;
&lt;p&gt;This can be quite useful, for example when you want to start by looking at small
test cases and then slowly broaden the scope. Just as a trivial example,
consider the property that “no number is equal to 5”. If we use
&lt;a href=&quot;https://hackage-content.haskell.org/package/falsify-0.4.0/docs/Test-Falsify-Generator.html#v:prim&quot;&gt;&lt;code&gt;prim&lt;/code&gt;&lt;/a&gt;
to generate the number to test, producing an arbitrary &lt;code&gt;Word64&lt;/code&gt;, the chances
that we will find the &lt;em&gt;one&lt;/em&gt; counter-example (5) in that enormous search space
are essentially non-existent:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot;&gt;&lt;pre class=&quot;sourceCode hs&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb2-1&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb2-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;demo ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Property&lt;/span&gt; ()&lt;/span&gt;
&lt;span id=&quot;cb2-2&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb2-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;demo &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-3&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb2-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    x &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; gen Gen.prim&lt;/span&gt;
&lt;span id=&quot;cb2-4&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb2-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    assert &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; P.ne &lt;span class=&quot;op&quot;&gt;.$&lt;/span&gt; (&lt;span class=&quot;st&quot;&gt;&quot;forbidden&quot;&lt;/span&gt;, &lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb2-5&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb2-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                  &lt;span class=&quot;op&quot;&gt;.$&lt;/span&gt; (&lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt;,&lt;span class=&quot;ot&quot;&gt; x ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Word64&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;However, we could start with a small range and slowly grow that range; &lt;code&gt;falsify&lt;/code&gt;
now also offers a convenience function, defined in terms of &lt;code&gt;getContext&lt;/code&gt;, for
this specific purpose:
&lt;a href=&quot;https://hackage-content.haskell.org/package/falsify-0.4.0/docs/Test-Falsify.html#v:sized&quot;&gt;&lt;code&gt;sized&lt;/code&gt;&lt;/a&gt;,
so-named because it is somewhat similar in spirit to &lt;a href=&quot;https://hackage-content.haskell.org/package/QuickCheck-2.18.0.0/docs/Test-QuickCheck-Gen.html#v:sized&quot;&gt;&lt;code&gt;sized&lt;/code&gt; in
&lt;code&gt;QuickCheck&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb3&quot;&gt;&lt;pre class=&quot;sourceCode hs&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb3-1&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb3-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;sized ::&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;forall&lt;/span&gt; e a&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;ProperFraction&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; a) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Property&lt;/span&gt; a&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A
&lt;a href=&quot;https://hackage-content.haskell.org/package/falsify-0.4.0/docs/Data-Falsify-ProperFraction.html#t:ProperFraction&quot;&gt;&lt;code&gt;ProperFraction&lt;/code&gt;&lt;/a&gt;
is in the half-open interval [0,1); that is, between 0 (inclusive) and 1
(exclusive). We can use this to refine our demo property:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb4&quot;&gt;&lt;pre class=&quot;sourceCode hs&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb4-1&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb4-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;demo2b ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Property&lt;/span&gt; ()&lt;/span&gt;
&lt;span id=&quot;cb4-2&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb4-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;demo2b &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-3&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb4-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    l &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; sized &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; ProperFraction.scaleIntegral &lt;span class=&quot;dv&quot;&gt;100&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-4&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb4-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    x &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; gen &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; Gen.inRange &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; Range.inclusive (&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;, l)&lt;/span&gt;
&lt;span id=&quot;cb4-5&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb4-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    assert &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; P.ne &lt;span class=&quot;op&quot;&gt;.$&lt;/span&gt; (&lt;span class=&quot;st&quot;&gt;&quot;forbidden&quot;&lt;/span&gt;, &lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb4-6&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb4-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                  &lt;span class=&quot;op&quot;&gt;.$&lt;/span&gt; (&lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt;,&lt;span class=&quot;ot&quot;&gt; x ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Word64&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This property is easily falsified.&lt;/p&gt;
&lt;p&gt;As an aside, I would be somewhat cautious in using this approach. While it is
sometimes unavoidable, in general I would recommend generating test case of
arbitrary size and then shrinking them down; this is often more likely to
actually find counter-examples. If there are specific edge cases that you want
to hit, write a generator that covers those edge cases specifically, and perhaps
use labelling
(&lt;a href=&quot;https://hackage-content.haskell.org/package/falsify-0.4.0/docs/Test-Falsify.html#v:label&quot;&gt;&lt;code&gt;label&lt;/code&gt;&lt;/a&gt;
and co) to check that those edge cases are indeed covered. However, as this demo
shows, for &lt;em&gt;some&lt;/em&gt; properties explicitly searching for small domains first can be
very helpful.&lt;/p&gt;
&lt;h2 id=&quot;cleanup&quot;&gt;Cleanup&lt;/h2&gt;
&lt;p&gt;The most important change in this release is a cleanup of the code base:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;There is now a separate &lt;a href=&quot;https://hackage.haskell.org/package/tasty-falsify-0.1.0&quot;&gt;&lt;code&gt;tasty-falsify&lt;/code&gt;&lt;/a&gt;
package that provides integration with the &lt;a href=&quot;https://hackage.haskell.org/package/tasty&quot;&gt;&lt;code&gt;tasty&lt;/code&gt;&lt;/a&gt; test framework; &lt;code&gt;falsify&lt;/code&gt; itself now provides &lt;a href=&quot;https://hackage-content.haskell.org/package/falsify-0.4.0/docs/Test-Falsify-Driver.html&quot;&gt;&lt;code&gt;Test.Falsify.Driver&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The module hierarchy has been significantly cleaned up. For example, there are now a bunch of new &lt;code&gt;Data.Falsify.*&lt;/code&gt; modules for specific datatypes; previously some of these were exported by &lt;code&gt;Test.Falsify.Gen&lt;/code&gt; instead; now that module only contains the &lt;em&gt;generators&lt;/em&gt; for those datatypes.&lt;/li&gt;
&lt;li&gt;Deprecated functions have been removed&lt;/li&gt;
&lt;li&gt;Some functions have been renamed and some &lt;code&gt;type&lt;/code&gt; aliases have been replaced by &lt;code&gt;newtype&lt;/code&gt; definitions for increased API clarity.&lt;/li&gt;
&lt;li&gt;All Haddock warnings have been addressed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For a full list of changes, please refer to the &lt;a href=&quot;https://hackage.haskell.org/package/falsify-0.4.0/changelog&quot;&gt;changelog&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;Shrinking can be handled manually, in the style of
&lt;a href=&quot;https://hackage.haskell.org/package/QuickCheck&quot;&gt;&lt;code&gt;QuickCheck&lt;/code&gt;&lt;/a&gt;; or
automatically, in the style of
&lt;a href=&quot;https://hackage.haskell.org/package/hedgehog&quot;&gt;&lt;code&gt;hedgehog&lt;/code&gt;&lt;/a&gt; or in the style of
&lt;a href=&quot;https://hackage.haskell.org/package/falsify&quot;&gt;&lt;code&gt;falsify&lt;/code&gt;&lt;/a&gt;. If you are willing to
put effort into writing good shrinkers for all your types, then QuickCheck is
still your best bet.&lt;/p&gt;
&lt;p&gt;If you consider the cost of manually writing shrinkers too large, then within
the Haskell ecosystem you have a choice between &lt;code&gt;hedgehog&lt;/code&gt; and &lt;code&gt;falsify&lt;/code&gt;. The
former has the considerable advantage that it’s been around for quite a long
time and is a very polished library. The downside is that every time you use
monadic bind you introduce a cut-point, which can often result in poor quality
shrinking. With &lt;a href=&quot;https://hypothesis.works/&quot;&gt;&lt;code&gt;Hypothesis&lt;/code&gt;&lt;/a&gt; showing the way,
&lt;code&gt;falsify&lt;/code&gt; solves that cut-point problem, though even with &lt;code&gt;falsify&lt;/code&gt; it still
matters how you write your generators: shrinking is &lt;em&gt;never&lt;/em&gt; truly free.
Moreover, &lt;code&gt;falsify&lt;/code&gt; should be considered an experimental library: it’s nowhere
near as battle-tested as Hedgehog, never mind QuickCheck. That said, thanks to
the interest of QBayLogic &lt;code&gt;falsify&lt;/code&gt; is now a little more mature, so thank you
QBayLogic!&lt;/p&gt;
&lt;p&gt;For clients who are looking for professional support for the use of &lt;code&gt;falsify&lt;/code&gt;,
or indeed any other Haskell library, don’t hesitate to contact us at
&lt;a href=&quot;mailto:info@well-typed.com&quot;&gt;info@well-typed.com&lt;/a&gt;.&lt;/p&gt;</description>
	<pubDate>Fri, 17 Jul 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Tweag I/O: Topiary: Formatting Forests</title>
	<guid isPermaLink="true">https://tweag.io/blog/2026-07-09-topiary-formatting-forests/</guid>
	<link>https://tweag.io/blog/2026-07-09-topiary-formatting-forests/</link>
	<description>&lt;p&gt;Topiary is a uniform formatter designed to support multiple languages through a single, consistent interface. By relying on Tree-sitter grammars and formatting queries, it easily adapts to new languages. But what happens when a language contains &lt;em&gt;other&lt;/em&gt; languages inside it?&lt;/p&gt;
&lt;p&gt;I’m excited to share how &lt;strong&gt;Language Injections&lt;/strong&gt; work in Topiary, a new feature allowing Topiary to format “forests” of syntax trees embedded within one another. This unlocks support for formatting embedded languages like OCaml snippets inside OCamllex files or code blocks within Markdown documents.&lt;/p&gt;
&lt;h2 id=&quot;the-problem-embedded-languages&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#the-problem-embedded-languages&quot;&gt;&lt;/a&gt;The Problem: Embedded Languages&lt;/h2&gt;
&lt;p&gt;Many file formats and programming languages permit embedding entirely different syntaxes within them.
Take Markdown, for instance. A Markdown document can contain fenced code blocks for arbitrary languages. You can even nest these embeddings! Consider a Markdown document containing some OCamllex (a lexer generator for OCaml).&lt;/p&gt;
&lt;p&gt;Before formatting, the nested syntax might look a bit messy:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;Example lexer:

&lt;span class=&quot;token code&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;```&lt;/span&gt;&lt;span class=&quot;token code-language&quot;&gt;ocamllex&lt;/span&gt;
&lt;span class=&quot;token code-block language-ocamllex&quot;&gt;rule main =parse
|_ {print_string &quot;Hello, &quot;;print_endline
&quot;World!&quot;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;```&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After passing this Markdown file through Topiary, the Markdown, OCamllex, and even the OCaml code nested inside the OCamllex, are all cleanly formatted:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;Example lexer:

&lt;span class=&quot;token code&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;```&lt;/span&gt;&lt;span class=&quot;token code-language&quot;&gt;ocamllex&lt;/span&gt;
&lt;span class=&quot;token code-block language-ocamllex&quot;&gt;rule main = parse
  | _ {
      print_string &quot;Hello, &quot;;
      print_endline
        &quot;World!&quot;
    }&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;```&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Historically, formatters struggle with this. They either leave the embedded code alone, implement ad-hoc parsing for specific combinations, or risk breaking the inner syntax. I wanted Topiary to handle this reliably.&lt;/p&gt;
&lt;h2 id=&quot;the-solution-language-injections&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#the-solution-language-injections&quot;&gt;&lt;/a&gt;The Solution: Language Injections&lt;/h2&gt;
&lt;p&gt;The idea of “language injections” comes from the Tree-sitter ecosystem, where it has become a de facto standard for handling embedded languages. Editors like Neovim, Helix, and Zed all use Tree-sitter’s injection mechanism to provide accurate syntax highlighting, code navigation, and other language-aware features inside embedded documents. The technique works by running a secondary Tree-sitter parser over a region of the host document, producing a separate syntax tree for the injected language. Which regions to inject, and which language to use, is specified through &lt;code class=&quot;language-text&quot;&gt;injections.scm&lt;/code&gt; query files that ship alongside grammars.&lt;/p&gt;
&lt;p&gt;Topiary now adopts this same mechanism for formatting. By delegating formatting tasks to another language’s formatter mid-flight, Topiary can correctly format inner code chunks while still respecting the layout of the host language.&lt;/p&gt;
&lt;p&gt;I recently merged the foundational &lt;a href=&quot;https://github.com/tweag/topiary/pulls&quot;&gt;Topiary PRs&lt;/a&gt; along with two language integrations to demonstrate this capability in action:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;OCamllex / OCaml Injections:&lt;/strong&gt; Topiary can now format the OCaml semantic actions embedded inside OCamllex files.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Markdown Injections:&lt;/strong&gt; Topiary can dynamically format code fences in Markdown documents according to their language identifier.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;deep-dive-how-it-works-under-the-hood&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#deep-dive-how-it-works-under-the-hood&quot;&gt;&lt;/a&gt;Deep Dive: How It Works Under the Hood&lt;/h2&gt;
&lt;p&gt;If you’re new to Topiary, the short version is that it formats code by parsing it with &lt;a href=&quot;https://tree-sitter.github.io/&quot;&gt;Tree-sitter&lt;/a&gt; grammars and then applying declarative formatting rules written as Tree-sitter queries. For a fuller introduction, see the &lt;a href=&quot;https://www.tweag.io/blog/2023-03-09-announcing-topiary/&quot;&gt;announcement blog post&lt;/a&gt; or the &lt;a href=&quot;https://topiary.tweag.io/book/&quot;&gt;Topiary Book&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The injection process relies on Topiary’s existing Tree-sitter foundation and extends the &lt;a href=&quot;https://topiary.tweag.io/book/reference/formatting-pipeline.html&quot;&gt;&lt;em&gt;atomization model&lt;/em&gt;&lt;/a&gt;. At a high level, Topiary parses the host document, extracts the injected spans, delegates their formatting to the inner language’s formatter, and stitches the results back together. Here are the technical details of how I achieved this.&lt;/p&gt;
&lt;h3 id=&quot;1-discovering-injections-with-queries&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#1-discovering-injections-with-queries&quot;&gt;&lt;/a&gt;1. Discovering Injections with Queries&lt;/h3&gt;
&lt;p&gt;If a host language definition includes an &lt;code class=&quot;language-text&quot;&gt;injections.scm&lt;/code&gt; query file, Topiary runs those queries against the host tree prior to standard formatting (a query can be thought of as a pattern-matching function that takes an AST of the host document and produces a list of matching spans). The queries dictate which spans of the host AST contain foreign code.&lt;/p&gt;
&lt;p&gt;Topiary supports two methods of resolving the injected language:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Static Resolution:&lt;/strong&gt;
For languages where the embedded language is always known (e.g., OCamllex always embeds OCaml), the injection query uses an &lt;code class=&quot;language-text&quot;&gt;#injection_language!&lt;/code&gt; predicate against the relevant AST node (in the &lt;code class=&quot;language-text&quot;&gt;tree-sitter-ocamllex&lt;/code&gt; grammar, the code block node is handily named &lt;code class=&quot;language-text&quot;&gt;ocaml&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-scheme&quot;&gt;&lt;code class=&quot;language-scheme&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;;; injections.scm&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ocaml&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; @injection.content
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;#injection_language!&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ocaml&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Dynamic Resolution:&lt;/strong&gt;
For formats like Markdown where the inner language isn’t known ahead of time, Topiary dynamically captures the language identifier from the AST (e.g., the info string of a code fence) using the &lt;code class=&quot;language-text&quot;&gt;@injection.language&lt;/code&gt; capture (a capture simply assigns a name to a matched node in the query):&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-scheme&quot;&gt;&lt;code class=&quot;language-scheme&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;;; injections.scm&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fenced_code_block&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;info_string&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;language&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; @injection.language
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;code_fence_content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; @injection.content
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;2-atomization-and-rewriting&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#2-atomization-and-rewriting&quot;&gt;&lt;/a&gt;2. Atomization and Rewriting&lt;/h3&gt;
&lt;p&gt;Once the injection queries identify the embedded spans, Topiary proceeds with the host language formatting. Crucially, Topiary treats the captured &lt;code class=&quot;language-text&quot;&gt;@injection.content&lt;/code&gt; nodes as &lt;strong&gt;leaves&lt;/strong&gt; during query matching.&lt;sup id=&quot;fnref-1&quot;&gt;&lt;a class=&quot;footnote-ref&quot; href=&quot;https://www.tweag.io/rss.xml#fn-1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; This means the host formatter doesn’t traverse inside them.&lt;/p&gt;
&lt;p&gt;After the host document is tokenized into atoms (the basic building blocks of the layout engine, representing either raw text fragments or formatting directives like spaces and line breaks), Topiary iterates through the captured injection spans:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Each injected span is formatted independently by its corresponding inner language formatter.&lt;/li&gt;
&lt;li&gt;The inner formatters execute as if they are producing text starting from column zero.&lt;/li&gt;
&lt;li&gt;The resulting formatted string replaces the corresponding host leaf in the atom stream.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;There is no “re-parse” phase after the injected text is rewritten. The host renderer retains control over the indentation; when it finally prints the substituted atom, it applies the appropriate indentation string from the host context.&lt;/p&gt;
&lt;p&gt;Because step 1 invokes the full formatting pipeline, injections are naturally recursive. If the injected language itself defines an &lt;code class=&quot;language-text&quot;&gt;injections.scm&lt;/code&gt; file, its injections will be discovered and formatted in turn. For example, formatting the nested Markdown/OCamllex/OCaml snippet from the top of this post doesn’t require any additional effort: Topiary will format all three layers without any special orchestration. Markdown delegates to OCamllex, which delegates to OCaml, each through the exact same code path!&lt;/p&gt;
&lt;h3 id=&quot;3-performance&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#3-performance&quot;&gt;&lt;/a&gt;3. Performance&lt;/h3&gt;
&lt;p&gt;The most expensive part of formatting an injected language is compiling its grammar and parsing its query files. If Topiary recompiled the queries for every single injected span, formatting a document with 100 embedded snippets would be prohibitively slow.&lt;/p&gt;
&lt;p&gt;To solve this, Topiary needs a way to compile the grammar once and share it across all matching spans. This ensures the total cost is sublinear in the number of injections.&lt;/p&gt;
&lt;h4 id=&quot;31-the-languageresolver-hook&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#31-the-languageresolver-hook&quot;&gt;&lt;/a&gt;3.1. The LanguageResolver Hook&lt;/h4&gt;
&lt;p&gt;To achieve this caching dynamically, I introduced the &lt;code class=&quot;language-text&quot;&gt;LanguageResolver&lt;/code&gt; type alias to the core &lt;code class=&quot;language-text&quot;&gt;formatter&lt;/code&gt; API. Topiary is not just a CLI; it is also a library. Because the core library doesn’t know how languages are configured or where grammars live on disk, I delegate the responsibility of resolving languages to the frontend via this hook:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-rust&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token type-definition class-name&quot;&gt;LanguageResolver&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token lifetime-annotation symbol&quot;&gt;'a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;dyn&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FormatterResult&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Option&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Arc&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Language&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token lifetime-annotation symbol&quot;&gt;'a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let’s unpack this piece by piece:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-text&quot;&gt;dyn Fn(&amp;amp;str)&lt;/code&gt;&lt;/strong&gt;: The resolver is a &lt;a href=&quot;https://doc.rust-lang.org/book/ch18-02-trait-objects.html&quot;&gt;trait object&lt;/a&gt;, specifically, a callable value that takes a language name (e.g., &lt;code class=&quot;language-text&quot;&gt;&quot;ocaml&quot;&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;&quot;rust&quot;&lt;/code&gt;) as a string slice. Using a trait object here means the core formatter doesn’t need to know &lt;em&gt;which&lt;/em&gt; concrete function performs the resolution; it just calls whatever the CLI (or any other frontend) hands it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-text&quot;&gt;-&amp;gt; FormatterResult&amp;lt;Option&amp;lt;Arc&amp;lt;Language&amp;gt;&amp;gt;&amp;gt;&lt;/code&gt;&lt;/strong&gt;: The return type is a &lt;code class=&quot;language-text&quot;&gt;Result&lt;/code&gt; wrapping an &lt;code class=&quot;language-text&quot;&gt;Option&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;Ok(Some(language))&lt;/code&gt; means the language was found and loaded. Topiary proceeds to format the injected span with that language’s grammar and queries.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;Ok(None)&lt;/code&gt; is a &lt;strong&gt;soft failure&lt;/strong&gt;: the language isn’t configured or isn’t supported. Topiary skips formatting for that span gracefully, leaving it untouched.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;Err(...)&lt;/code&gt; is a &lt;strong&gt;hard failure&lt;/strong&gt; (e.g., a query file failed to parse). Topiary aborts the entire formatting run and returns an error without modifying the file.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-text&quot;&gt;Arc&amp;lt;Language&amp;gt;&lt;/code&gt;&lt;/strong&gt;: The resolved &lt;code class=&quot;language-text&quot;&gt;Language&lt;/code&gt; is wrapped in an atomically reference-counted pointer. Topiary compiles the Tree-sitter grammars and queries into a &lt;code class=&quot;language-text&quot;&gt;Language&lt;/code&gt; for formatting; &lt;code class=&quot;language-text&quot;&gt;Arc&lt;/code&gt; enables caching. The CLI can compile the &lt;code class=&quot;language-text&quot;&gt;Language&lt;/code&gt; on the first call and return cloned &lt;code class=&quot;language-text&quot;&gt;Arc&lt;/code&gt; handles on subsequent calls, ensuring the compilation overhead is shared across all injected spans of the same language.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-text&quot;&gt;+ 'a&lt;/code&gt;&lt;/strong&gt;: A lifetime bound tying the resolver to a borrow scope. In practice, this gives the resolver the flexibility to temporarily reference external data (such as the CLI’s configuration cache) without requiring permanent ownership of it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This design decouples Topiary’s core formatting logic from any particular frontend. The core library doesn’t know how caching works; it just calls the resolver and acts on the result.&lt;/p&gt;
&lt;h3 id=&quot;limitations&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#limitations&quot;&gt;&lt;/a&gt;Limitations&lt;/h3&gt;
&lt;p&gt;These changes do a great job in the majority of use cases, but still have a few known limitations.&lt;/p&gt;
&lt;p&gt;Firstly, because injected spans are formatted independently, the current injection model is stateless. It cannot express layout decisions that require measuring or choosing between softline layouts across the host/injected boundary. For example, consider a Markdown document like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;Let's first define a greeting function that takes a string reference:

&lt;span class=&quot;token code&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;```&lt;/span&gt;&lt;span class=&quot;token code-language&quot;&gt;rust&lt;/span&gt;
&lt;span class=&quot;token code-block language-rust&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;greet&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;```&lt;/span&gt;&lt;/span&gt;

Now we complete the function by printing the greeting to standard output:

&lt;span class=&quot;token code&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;```&lt;/span&gt;&lt;span class=&quot;token code-language&quot;&gt;rust&lt;/span&gt;
&lt;span class=&quot;token code-block language-rust&quot;&gt;    &lt;span class=&quot;token macro property&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Hello, {name}!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;```&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here a Rust function definition is split across two code fences. Since each fence is its own injection, Topiary formats them independently. The first block sees an unclosed brace, and the second sees an indented statement followed by a closing brace with no matching opener. Neither fragment is valid Rust on its own, so the formatter can’t make sensible layout decisions about them. In practice, because the inner language fails to parse, Topiary will abort the entire formatting run and return an error.&lt;/p&gt;
&lt;p&gt;However, if you pass the &lt;code class=&quot;language-text&quot;&gt;--tolerate-parsing-errors&lt;/code&gt; flag, Topiary will do its best. Because each fragment is formatted independently as if starting from column zero, the indentation on the second fragment gets completely stripped:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;Let's first define a greeting function that takes a string reference:

&lt;span class=&quot;token code&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;```&lt;/span&gt;&lt;span class=&quot;token code-language&quot;&gt;rust&lt;/span&gt;
&lt;span class=&quot;token code-block language-rust&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;greet&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;```&lt;/span&gt;&lt;/span&gt;

Now we complete the function by printing the greeting to standard output:

&lt;span class=&quot;token code&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;```&lt;/span&gt;&lt;span class=&quot;token code-language&quot;&gt;rust&lt;/span&gt;
&lt;span class=&quot;token code-block language-rust&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Hello, {name}!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;```&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Overall, I believe this is a perfectly acceptable trade-off: purity and statelessness provide an elegant and robust formatting pipeline, which is not worth giving up for gaining the ability to handle fragmented constructs, which are less common.&lt;/p&gt;
&lt;p&gt;Another known limitation is that, while Tree-sitter grammars are usually flexible enough to parse individual definitions or expressions, if a grammar strictly expects a full source file and nothing less, it won’t be able to parse short injected snippets correctly. Just like with fragmented code blocks, this will result in a parsing error unless &lt;code class=&quot;language-text&quot;&gt;--tolerate-parsing-errors&lt;/code&gt; is used. Fortunately, most grammars (e.g. Java, C#, or Rust) are remarkably flexible and do not exhibit this problem.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#conclusion&quot;&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;By leveraging language injection queries and extending the core formatting API, Topiary can now cleanly format embedded code snippets without breaking the host language layout. With language injections, Topiary is no longer just formatting single syntax trees: it’s formatting forests.&lt;/p&gt;
&lt;p&gt;This feature will be included in an upcoming release. In the meantime, if you’re working with OCamllex (for which Topiary is, to my knowledge, the only complete formatter!) or writing technical Markdown documents, you can try it out today.&lt;/p&gt;
&lt;p&gt;To run it on an OCamllex file using Nix, for example, you can use:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;nix run github:topiary/topiary -- &lt;span class=&quot;token function&quot;&gt;fmt&lt;/span&gt; myfile.mll&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn-1&quot;&gt;Usually embedded language spans are already parsed as leaves by the
tree-sitter grammar itself. But they don’t have to, so enforcing that
Topiary only sees leaves no matter what the grammar says is safer.&lt;a class=&quot;footnote-backref&quot; href=&quot;https://www.tweag.io/rss.xml#fnref-1&quot;&gt;↩&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description>
	<pubDate>Thu, 09 Jul 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>in Code: Extreme Haskell: Typed Expression EDSLs (Part 1)</title>
	<guid isPermaLink="true">https://blog.jle.im/entry/extreme-haskell-typed-expression-edsls-1.html</guid>
	<link>https://blog.jle.im/entry/extreme-haskell-typed-expression-edsls-1.html</link>
	<description>&lt;p&gt;I always say, inside every Haskeller there are two wolves, living on opposite
ends of the Haskell Fancy Code Spectrum. Are you going to write “simple
Haskell”, using basic GHC 2010 tools and writing universal Haskell that every
introductory course offers, trying to keep the code as immediately
understandable and accessible? Or are you going to pile in all of the Haskell
type system and evaluation tricks you can find and turn on all the extensions,
and go full fancy?&lt;/p&gt;
&lt;p&gt;In my &lt;a href=&quot;https://blog.jle.im/entry/levels-of-type-safety-haskell-lists.html&quot;&gt;Seven
Levels of Type Safety&lt;/a&gt; post, I described different extremes of type safety
and fancy code. I talked about how writing effective code was finding the
correct compromise for the level of communication and safety you need.&lt;/p&gt;
&lt;p&gt;But this is not that kind of blog post. This is the kind of blog post where
we celebrate terrifying type-safety, facetious fanciness, and masochistic
meta-analysis. This series is about what happens when we dare to go full fancy.
Let’s write code that is so inscrutable, so painful and torturous to write, yet
so &lt;em&gt;undeniably useful&lt;/em&gt; that you can’t help but try to throw it into every
single thing you write and will feel a gnawing emptiness in your soul until you
do.&lt;/p&gt;
&lt;p&gt;As our example, let’s write a type-safe method to specify your program as a
series of states, with triggered transitions between them: a type-safe state
machine graph using a type-safe lambda calculus. We want to specify this in a
way that we can write once and then:&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;be interpretable in a type-safe way within Haskell.&lt;/li&gt;
&lt;li&gt;be inspectable with visualizable control flow.&lt;/li&gt;
&lt;li&gt;be compilable to multiple actual back-ends, letting you run the same
function under multiple implementations.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This exact thing is something I’ve needed and used multiple times now in
projects. I want to specify one program graph within Haskell, but in a way that
can compile both in C and javascript while also being visualizable and
interactively explorable.&lt;/p&gt;
&lt;p&gt;Once you go down this road, everything you ever write will feel woefully
unsafe and limited. And everything you want to write will be hopelessly
inscrutable by normal humans and borderline unusable. But such is the curse we
all bear. Turn around now, you have been warned.&lt;/p&gt;
&lt;p&gt;This post will build up the embedded typed expression language. Part 2 will
use that expression language to define typed state machines with embedded
predicates and visualize them, and Part 3 will compile those machines to
different languages and verify they execute identically, with some live
demos.&lt;/p&gt;
&lt;p&gt;All of the code here is &lt;a href=&quot;https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/flake.nix&quot;&gt;available
online&lt;/a&gt;, and if you check out the repo and run &lt;code&gt;nix develop&lt;/code&gt; you
should be able to load it all in ghci:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb1-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;$&lt;/span&gt; cd code-samples/typed-sm-lc&lt;/span&gt;
&lt;span id=&quot;cb1-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb1-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;$&lt;/span&gt; nix develop&lt;/span&gt;
&lt;span id=&quot;cb1-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb1-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;$&lt;/span&gt; ghci&lt;/span&gt;
&lt;span id=&quot;cb1-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb1-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;ghci&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; :load ExprStage1.hs&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;the-lambda-calculus&quot;&gt;The Lambda Calculus&lt;/h2&gt;
&lt;p&gt;Let’s derive a way to express an algorithm or expression in Haskell that can
be reified and analyzed within Haskell, and eventually be a form we can compile
to different backends, interpret in Haskell, or generate Graphviz visualizations
for.&lt;/p&gt;
&lt;h3 id=&quot;a-first-pass&quot;&gt;A First Pass&lt;/h3&gt;
&lt;p&gt;One basic thing we can do is start with:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb2-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage1.hs#L18-L34&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Prim&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PBool&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Bool&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PString&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Show&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb2-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Op&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OTimes&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OLte&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OAnd&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Show&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb2-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Prim&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ELambda&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EApply&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Op&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ERecord&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb2-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EAccess&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EChoice&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-18&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ECase&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb2-19&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Show&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And you can write &lt;code&gt;(\x -&amp;gt; x * 3) 5&lt;/code&gt; as:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb3&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb3-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb3-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage1.hs#L36-L37&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb3-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb3-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;fifteen ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb3-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;fifteen &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ELambda&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OTimes&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;))) &lt;span class=&quot;ot&quot;&gt;`EApply`&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The strings in &lt;code&gt;ELambda&lt;/code&gt; introduce variables, and
&lt;code&gt;EVar&lt;/code&gt; refers to the bound variable. As you can see, this is…pretty
untyped. We could easily write something that is meaningless:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb4&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb4-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage1.hs#L67-L69&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;badTypeExample ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;badTypeExample &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OAnd&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;)) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Of course, GHC can typecheck our code if we literally write
&lt;code&gt;\x -&amp;gt; x + 3&lt;/code&gt; and reject &lt;code&gt;1 &amp;amp;&amp;amp; 2&lt;/code&gt;. But we
aren’t trying to build opaque Haskell code here, we’re trying to represent our
expression as an ADT that we can analyze &lt;em&gt;within&lt;/em&gt; the language.&lt;/p&gt;
&lt;p&gt;If we want a record projection and one labeled choice with a case analysis
over it:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb5&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb5-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage1.hs#L39-L62&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;recordExample ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;recordExample &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ( &lt;span class=&quot;dt&quot;&gt;EAccess&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        ( &lt;span class=&quot;dt&quot;&gt;ERecord&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            M.fromList&lt;/span&gt;
&lt;span id=&quot;cb5-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;              [ (&lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;)),&lt;/span&gt;
&lt;span id=&quot;cb5-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                (&lt;span class=&quot;st&quot;&gt;&quot;label&quot;&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PString&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;found&quot;&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb5-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;              ]&lt;/span&gt;
&lt;span id=&quot;cb5-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        )&lt;/span&gt;
&lt;span id=&quot;cb5-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    )&lt;/span&gt;
&lt;span id=&quot;cb5-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb5-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-18&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;sumExample ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-19&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sumExample &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-20&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ECase&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-21&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;dt&quot;&gt;EChoice&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;)))&lt;/span&gt;
&lt;span id=&quot;cb5-22&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ( M.fromList&lt;/span&gt;
&lt;span id=&quot;cb5-23&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        [ (&lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt;, (&lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;)))),&lt;/span&gt;
&lt;span id=&quot;cb5-24&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          (&lt;span class=&quot;st&quot;&gt;&quot;Missing&quot;&lt;/span&gt;, (&lt;span class=&quot;st&quot;&gt;&quot;message&quot;&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;)))&lt;/span&gt;
&lt;span id=&quot;cb5-25&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        ]&lt;/span&gt;
&lt;span id=&quot;cb5-26&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-26&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    )&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now, for the entire point of &lt;code&gt;Expr&lt;/code&gt;, we can write a function to
pretty-print it, using the &lt;em&gt;&lt;a href=&quot;https://hackage.haskell.org/package/prettyprinter&quot;&gt;prettyprinter&lt;/a&gt;&lt;/em&gt;
library:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb6&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb6-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage1.hs#L253-L299&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;ppPrim ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Prim&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id=&quot;cb6-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppPrim &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; n &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; PP.pretty n&lt;/span&gt;
&lt;span id=&quot;cb6-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;PBool&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;PBool&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;false&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;PString&lt;/span&gt; s &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; PP.pretty (&lt;span class=&quot;fu&quot;&gt;show&lt;/span&gt; s)&lt;/span&gt;
&lt;span id=&quot;cb6-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;ppOp ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Op&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id=&quot;cb6-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppOp &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;+&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OTimes&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OLte&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&amp;lt;=&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OAnd&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&amp;amp;&amp;amp;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;ppExpr ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Bool&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id=&quot;cb6-18&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppExpr paren &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-19&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; p &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; ppPrim p&lt;/span&gt;
&lt;span id=&quot;cb6-20&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; v &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; PP.pretty v&lt;/span&gt;
&lt;span id=&quot;cb6-21&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ELambda&lt;/span&gt; n body &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-22&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    wrap &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;\\&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; PP.pretty n &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;-&amp;gt;&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt; body&lt;/span&gt;
&lt;span id=&quot;cb6-23&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EApply&lt;/span&gt; f x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-24&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    wrap &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; f &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; x&lt;/span&gt;
&lt;span id=&quot;cb6-25&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; o x y &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-26&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-26&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    wrap &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; x &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppOp o &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; y&lt;/span&gt;
&lt;span id=&quot;cb6-27&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-27&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ERecord&lt;/span&gt; xs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-28&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-28&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    PP.encloseSep &lt;span class=&quot;st&quot;&gt;&quot;{ &quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot; }&quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;, &quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-29&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-29&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      [PP.pretty k &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;=&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt; v &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; (k, v) &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; M.toList xs]&lt;/span&gt;
&lt;span id=&quot;cb6-30&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-30&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EAccess&lt;/span&gt; e k &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-31&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-31&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ppExpr &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; e &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;.&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; PP.pretty k&lt;/span&gt;
&lt;span id=&quot;cb6-32&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-32&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EChoice&lt;/span&gt; tag x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-33&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-33&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    wrap &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; PP.pretty tag &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; x&lt;/span&gt;
&lt;span id=&quot;cb6-34&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-34&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ECase&lt;/span&gt; x hs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-35&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-35&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    wrap &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-36&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-36&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      PP.sep&lt;/span&gt;
&lt;span id=&quot;cb6-37&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-37&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        [ &lt;span class=&quot;st&quot;&gt;&quot;case&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt; x &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;of&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-38&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-38&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        , PP.encloseSep &lt;span class=&quot;st&quot;&gt;&quot;{ &quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot; }&quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;; &quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-39&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-39&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            [ PP.pretty tag &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; PP.pretty n &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;-&amp;gt;&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt; body&lt;/span&gt;
&lt;span id=&quot;cb6-40&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-40&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; (tag, (n, body)) &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; M.toList hs&lt;/span&gt;
&lt;span id=&quot;cb6-41&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-41&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            ]&lt;/span&gt;
&lt;span id=&quot;cb6-42&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-42&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        ]&lt;/span&gt;
&lt;span id=&quot;cb6-43&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-43&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-44&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-44&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    wrap&lt;/span&gt;
&lt;span id=&quot;cb6-45&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-45&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; paren &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; PP.parens&lt;/span&gt;
&lt;span id=&quot;cb6-46&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-46&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;otherwise&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;id&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-47&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-47&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-48&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-48&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;prettyExpr ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id=&quot;cb6-49&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-49&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;prettyExpr &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb7&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb7-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb7-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; prettyExpr fifteen&lt;/span&gt;
&lt;span id=&quot;cb7-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb7-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;(\x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; x &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;) &lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb7-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; prettyExpr badTypeExample&lt;/span&gt;
&lt;span id=&quot;cb7-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb7-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb7-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; prettyExpr recordExample&lt;/span&gt;
&lt;span id=&quot;cb7-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb7-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;{ label &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;found&quot;&lt;/span&gt;, value &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt; }&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;value &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb7-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; prettyExpr sumExample&lt;/span&gt;
&lt;span id=&quot;cb7-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb7-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Found&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt; { &lt;span class=&quot;dt&quot;&gt;Found&lt;/span&gt; value &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; value &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;; &lt;span class=&quot;dt&quot;&gt;Missing&lt;/span&gt; message &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now, we can write a quick typechecker for this using a greedy type-checking
algorithm (&lt;a href=&quot;https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage1.hs#L77-L89&quot;&gt;written
out here&lt;/a&gt;), which is a fun exercise, but it’s beyond the point of this post.
For our purposes, we’re going to write the in-Haskell evaluator, which is one
sure-fire evidential/constructive way to prove an expression was valid
after-the-fact.&lt;/p&gt;
&lt;p&gt;So…how can you “evaluate” this to 15, within Haskell? What would the type
even be? The best we can do at this point is make the entire thing monadic by
returning &lt;code&gt;Maybe&lt;/code&gt; or &lt;code&gt;Either&lt;/code&gt;, and split out the
expressions we write from the values we can actually evaluate to:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb8&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb8-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage1.hs#L228-L330&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Bool&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVString&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVFun&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb8-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVRecord&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb8-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVChoice&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;eval ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;eval env &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; p &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; evalPrim p&lt;/span&gt;
&lt;span id=&quot;cb8-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; v &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; M.lookup v env&lt;/span&gt;
&lt;span id=&quot;cb8-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ELambda&lt;/span&gt; n body &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVFun&lt;/span&gt; (\x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; eval (M.insert n x env) body))&lt;/span&gt;
&lt;span id=&quot;cb8-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EApply&lt;/span&gt; f x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; eval env f &lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVFun&lt;/span&gt; f' &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; eval env x &lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; f'&lt;/span&gt;
&lt;span id=&quot;cb8-18&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    _ &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-19&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; o x y &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-20&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    u &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id=&quot;cb8-21&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    v &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env y&lt;/span&gt;
&lt;span id=&quot;cb8-22&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; (u, v) &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-23&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      (&lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; a, &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; b) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; o &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-24&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; b))&lt;/span&gt;
&lt;span id=&quot;cb8-25&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;dt&quot;&gt;OTimes&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; b))&lt;/span&gt;
&lt;span id=&quot;cb8-26&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-26&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;dt&quot;&gt;OLte&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;&amp;lt;=&lt;/span&gt; b))&lt;/span&gt;
&lt;span id=&quot;cb8-27&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-27&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;dt&quot;&gt;OAnd&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-28&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-28&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      (&lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; a, &lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; b) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; o &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-29&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-29&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;dt&quot;&gt;OAnd&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; b))&lt;/span&gt;
&lt;span id=&quot;cb8-30&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-30&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        _ &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-31&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-31&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      _ &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-32&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-32&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ERecord&lt;/span&gt; xs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVRecord&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;traverse&lt;/span&gt; (eval env) xs&lt;/span&gt;
&lt;span id=&quot;cb8-33&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-33&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EAccess&lt;/span&gt; e k &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-34&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-34&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVRecord&lt;/span&gt; xs &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env e&lt;/span&gt;
&lt;span id=&quot;cb8-35&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-35&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    M.lookup k xs&lt;/span&gt;
&lt;span id=&quot;cb8-36&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-36&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EChoice&lt;/span&gt; tag x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVChoice&lt;/span&gt; tag &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id=&quot;cb8-37&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-37&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ECase&lt;/span&gt; x hs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-38&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-38&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVChoice&lt;/span&gt; tag payload &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id=&quot;cb8-39&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-39&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (n, body) &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; M.lookup tag hs&lt;/span&gt;
&lt;span id=&quot;cb8-40&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-40&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    eval (M.insert n payload env) body&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This would properly evaluate:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb9&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb9-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb9-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; eval M.empty fifteen&lt;/span&gt;
&lt;span id=&quot;cb9-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb9-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;15&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can also produce closures as values:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb10&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb10-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb10-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage1.hs#L64-L65&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb10-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb10-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;plusThree ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb10-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;plusThree &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ELambda&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;)))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb11&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb11-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb11-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; for_ (eval M.empty plusThree) \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb11-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVFun&lt;/span&gt; f &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;print&lt;/span&gt; (f (&lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb11-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb11-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    _ &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;putStrLn&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;not a function&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb11-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This kind of works if you remember to thread everything through
&lt;code&gt;Maybe&lt;/code&gt; (or &lt;code&gt;Either&lt;/code&gt;) or what have you. But this is not
ideal. You should be able to know, at compile-time, that your &lt;code&gt;Expr&lt;/code&gt;
is valid. After all, you want to be able to create one “valid”
&lt;code&gt;Expr&lt;/code&gt;, and run it at every context. It’s useless to you if every
single time you used an &lt;code&gt;Expr&lt;/code&gt;, you had to manually handle the
&lt;code&gt;Nothing&lt;/code&gt; case. Your diagram generator, your Haskell runner, your
code generator, will always be in &lt;code&gt;Either&lt;/code&gt; even though you know your
&lt;code&gt;Expr&lt;/code&gt; is valid, via tests or something. We want GHC to reject badly
typed expressions, so we never need to unwrap or handle a &lt;code&gt;Nothing&lt;/code&gt;
or &lt;code&gt;Left&lt;/code&gt;!&lt;/p&gt;
&lt;p&gt;No, no, this is not okay and not acceptable. We should be able to verify in
the types if an &lt;code&gt;Expr&lt;/code&gt; is valid.&lt;/p&gt;
&lt;h2 id=&quot;type-indexed-expressions&quot;&gt;Type-Indexed Expressions&lt;/h2&gt;
&lt;h3 id=&quot;just-add-the-index&quot;&gt;Just Add the Index&lt;/h3&gt;
&lt;p&gt;The next step you’ll see in posts online is to add a phantom index type to
&lt;code&gt;Expr&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb12&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb12-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage2.hs#L19-L49&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TBool&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Prim&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Prim&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;PBool&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Bool&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Prim&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TBool&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;PString&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Prim&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Op&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Op&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OTimes&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Op&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OLte&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Op&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TBool&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-18&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OAnd&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Op&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TBool&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TBool&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TBool&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-19&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-20&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-21&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Prim&lt;/span&gt; t &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; t&lt;/span&gt;
&lt;span id=&quot;cb12-22&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; t &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; t&lt;/span&gt;
&lt;span id=&quot;cb12-23&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ELambda&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;:-&amp;gt;&lt;/span&gt; b)&lt;/span&gt;
&lt;span id=&quot;cb12-24&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EApply&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;:-&amp;gt;&lt;/span&gt; b) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; b&lt;/span&gt;
&lt;span id=&quot;cb12-25&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Op&lt;/span&gt; a b c &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; c&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(We’ll explain each part of this declaration eventually)&lt;/p&gt;
&lt;p&gt;A phantom type is a type parameter that doesn’t represent any actual
&lt;em&gt;value&lt;/em&gt; “contained” inside the data type, but just serves to “tag” or
distinguish values for the compiler to reject or unify things in useful
ways.&lt;/p&gt;
&lt;p&gt;This introduces several new language features, so bear with me as I break
them down.&lt;/p&gt;
&lt;p&gt;First, we use &lt;code&gt;-XTypeData&lt;/code&gt; to define a data kind: &lt;code&gt;Ty&lt;/code&gt;
is a kind with types &lt;code&gt;TInt :: Ty&lt;/code&gt;, &lt;code&gt;TBool :: Ty&lt;/code&gt;, etc. And
in &lt;code&gt;Expr t&lt;/code&gt;, we have an expression tagged with &lt;code&gt;t&lt;/code&gt;, which
describes the result type. (In fact, &lt;em&gt;all&lt;/em&gt; data types are automatically
promoted to the type level with &lt;code&gt;-XDataKinds&lt;/code&gt;. You might see the
&lt;code&gt;'Nothing&lt;/code&gt; quote prefix syntax in cases where it’s ambiguous if
you’re talking about the data constructor or the type constructor, like
&lt;code&gt;'[]&lt;/code&gt; and &lt;code&gt;'(,)&lt;/code&gt;)&lt;/p&gt;
&lt;p&gt;For example, because we have &lt;code&gt;EPrim :: Prim t -&amp;gt; Expr t&lt;/code&gt;, and
&lt;code&gt;PInt 3 :: Prim TInt&lt;/code&gt;, we have
&lt;code&gt;EPrim (PInt 3) :: Expr TInt&lt;/code&gt;: a primitive 3 is an expression
describing an integer.&lt;/p&gt;
&lt;p&gt;And because
&lt;code&gt;EOp :: Op a b c -&amp;gt; Expr a -&amp;gt; Expr b -&amp;gt; Expr c&lt;/code&gt;, and
&lt;code&gt;OLte :: Op TInt TInt TBool&lt;/code&gt;, we have&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb13&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb13-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb13-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OLte&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TBool&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So we can write an operation on two &lt;code&gt;Expr&lt;/code&gt;s that typecheck how
we’d expect:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb14&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb14-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb14-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;t &lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OLte&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;)) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb14-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb14-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TBool&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We also have
&lt;code&gt;EOp OAnd :: Expr TBool -&amp;gt; Expr TBool -&amp;gt; Expr TBool&lt;/code&gt;, which
means the compiler will reject our previous &lt;code&gt;1 &amp;amp;&amp;amp; 2&lt;/code&gt;
example:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb15&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb15-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb15-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;t &lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OAnd&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;)) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb15-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb15-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;interactive&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb15-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb15-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    • &lt;span class=&quot;dt&quot;&gt;Couldn't&lt;/span&gt; match &lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; ‘&lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;’ with ‘&lt;span class=&quot;dt&quot;&gt;TBool&lt;/span&gt;’&lt;/span&gt;
&lt;span id=&quot;cb15-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb15-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;Expected&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Prim&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TBool&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb15-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb15-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;dt&quot;&gt;Actual&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Prim&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can write lambdas in this system too:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb16&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb16-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb16-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage2.hs#L51-L55&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb16-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb16-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;fifteen ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb16-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;fifteen &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb16-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EApply&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb16-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;dt&quot;&gt;ELambda&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OTimes&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;))))&lt;/span&gt;
&lt;span id=&quot;cb16-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb16-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Because of &lt;code&gt;Ty&lt;/code&gt;, we can also make a new indexed data type with
phantoms of “fully resolved” values:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb17&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb17-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb17-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage2.hs#L115-L119&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb17-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb17-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb17-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb17-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Bool&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TBool&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb17-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVString&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb17-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVFun&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; b)) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;:-&amp;gt;&lt;/span&gt; b)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is what we want to eventually &lt;code&gt;eval&lt;/code&gt; into, as we can
guarantee ourselves to get a value of the correct type based on the
&lt;code&gt;Ty&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb18&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb18-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb18-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;eValueToInt ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb18-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb18-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;eValueToInt &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb18-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb18-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; x&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And GHC will verify this as a total pattern match because &lt;code&gt;EVInt&lt;/code&gt;
is the only possible way to create an &lt;code&gt;EValue TInt&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;singletons-and-existentials&quot;&gt;Singletons and Existentials&lt;/h3&gt;
&lt;p&gt;We’ll keep our bound variables stored as an ambient map of variable names to
their evaluated values for now. But, to do this, we need to turn the
heterogeneous &lt;code&gt;EValue t&lt;/code&gt; into the homogeneous
&lt;code&gt;Map String SomeValue&lt;/code&gt; by wrapping the type variable as an
existential type.&lt;/p&gt;
&lt;p&gt;You might notice we have a &lt;a href=&quot;https://blog.jle.im/entries/series/+introduction-to-singletons.html&quot;&gt;singleton&lt;/a&gt;
for our &lt;code&gt;Ty&lt;/code&gt; type, &lt;code&gt;STy&lt;/code&gt;, that pops up in multiple
situations.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb19&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb19-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb19-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage2.hs#L27-L31&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb19-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb19-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb19-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb19-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STBool&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TBool&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb19-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STString&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb19-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STFun&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;:-&amp;gt;&lt;/span&gt; b)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Firstly, it might help to recognize the general pattern where
&lt;code&gt;STy&lt;/code&gt; (the singleton) appears. It &lt;em&gt;usually&lt;/em&gt; pops up whenever
we have existentially scoped variables, like in
&lt;code&gt;data SomeValue = forall t. SomeValue (STy t) (EValue t)&lt;/code&gt;. In this
case, the &lt;code&gt;t&lt;/code&gt; is completely lost to the outside world, and
&lt;code&gt;STy t&lt;/code&gt; is used to allow us to recover a runtime witness to what
&lt;code&gt;t&lt;/code&gt; was, after pattern matching on &lt;code&gt;STy&lt;/code&gt;. This is the
&lt;em&gt;dependent sum&lt;/em&gt; pattern, and is similar to how &lt;code&gt;Typeable&lt;/code&gt; is
used in &lt;em&gt;Data.Dynamic&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;In our case, because variables are still stored ambiently in the environment
and validated at runtime, we &lt;em&gt;do&lt;/em&gt; need singletons to implement
&lt;code&gt;eval&lt;/code&gt; . The type &lt;code&gt;Expr t&lt;/code&gt; only specifies the type of the
result, but the type information of the ambient variables is not available. So,
you can write &lt;code&gt;EVar STInt &quot;myVar&quot; :: Expr TInt&lt;/code&gt;, but:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;myVar&lt;/code&gt; might not be a variable in scope at all, so
&lt;code&gt;eval&lt;/code&gt; will fail at runtime&lt;/li&gt;
&lt;li&gt;&lt;code&gt;myVar&lt;/code&gt; might be in scope, but might be a &lt;code&gt;TString&lt;/code&gt;
and not a &lt;code&gt;TInt&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first case is easy enough to deal with (&lt;code&gt;M.lookup&lt;/code&gt; returns
&lt;code&gt;Nothing&lt;/code&gt;), but the second one is a little more subtle. Let’s say we
&lt;em&gt;do&lt;/em&gt; have a &lt;code&gt;SomeValue&lt;/code&gt; under our key &lt;code&gt;myVar&lt;/code&gt;…how
do we make sure it has the correct type?&lt;/p&gt;
&lt;h3 id=&quot;runtime-type-equality&quot;&gt;Runtime Type Equality&lt;/h3&gt;
&lt;p&gt;We can do ad-hoc pattern matching on &lt;code&gt;EValue&lt;/code&gt;, but that won’t get
us too far. Mostly because some of the &lt;code&gt;EValue&lt;/code&gt; constructors actually
don’t have enough information for us to validate their actual type (try it!
&lt;code&gt;EVFun&lt;/code&gt; will give you a lot of trouble). So, what we can do is write
a function that takes two &lt;code&gt;STy&lt;/code&gt; at runtime and &lt;em&gt;unifies&lt;/em&gt; them
conditionally if they are the same. We’ll write a function
&lt;code&gt;sameTy :: STy a -&amp;gt; STy b -&amp;gt; Maybe (a :~: b)&lt;/code&gt;, where&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb20&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb20-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb20-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; (:~:) ::&lt;/span&gt; k &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; k &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb20-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; a &lt;span class=&quot;op&quot;&gt;:~:&lt;/span&gt; a&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;pattern matching&lt;/em&gt; on a value of type &lt;code&gt;a :~: b&lt;/code&gt; will reveal
that &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; are the same type variable, because the
only way to construct it is with &lt;code&gt;Refl :: a :~: a&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;With that, we can write &lt;code&gt;sameTy&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb21&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb21-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage2.hs#L133-L143&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;sameTy ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;:~:&lt;/span&gt; b)&lt;/span&gt;
&lt;span id=&quot;cb21-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sameTy &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt;; _ &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STBool&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STBool&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt;; _ &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STString&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STString&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt;; _ &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STFun&lt;/span&gt; a b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;STFun&lt;/span&gt; c d &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; sameTy a c&lt;/span&gt;
&lt;span id=&quot;cb21-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; sameTy b d&lt;/span&gt;
&lt;span id=&quot;cb21-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    _ &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There’s a typeclass in &lt;em&gt;base&lt;/em&gt; (or rather, a “kindclass”),
&lt;code&gt;TestEquality&lt;/code&gt;, that encapsulates this pattern:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb22&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb22-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb22-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TestEquality&lt;/span&gt; f &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb22-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb22-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;    testEquality ::&lt;/span&gt; f a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; f b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;:~:&lt;/span&gt; b)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In fact, we can write our &lt;code&gt;sameTy&lt;/code&gt; as an instance:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb23&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb23-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb23-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage2.hs#L130-L131&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb23-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb23-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb23-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb23-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TestEquality&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb23-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb23-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  testEquality &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sameTy&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We’re now at a higher fanciness level than before. But you might see the
problem here: &lt;code&gt;EVar STInt &quot;x&quot;&lt;/code&gt;. &lt;code&gt;x&lt;/code&gt; might not be defined,
and it also might not have the correct type. Soooo yes, we still have issues
here.&lt;/p&gt;
&lt;p&gt;But now at least we can write &lt;code&gt;eval&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb24&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb24-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage2.hs#L145-L176&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;eval ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;SomeValue&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; t &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; t)&lt;/span&gt;
&lt;span id=&quot;cb24-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;eval env &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; n) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; n)&lt;/span&gt;
&lt;span id=&quot;cb24-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PBool&lt;/span&gt; b) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; b)&lt;/span&gt;
&lt;span id=&quot;cb24-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PString&lt;/span&gt; s) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVString&lt;/span&gt; s)&lt;/span&gt;
&lt;span id=&quot;cb24-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; t v &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;SomeValue&lt;/span&gt; t' v' &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; M.lookup v env&lt;/span&gt;
&lt;span id=&quot;cb24-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; sameTy t t'&lt;/span&gt;
&lt;span id=&quot;cb24-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; v'&lt;/span&gt;
&lt;span id=&quot;cb24-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ELambda&lt;/span&gt; ta n body &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVFun&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; \x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; eval (M.insert n (&lt;span class=&quot;dt&quot;&gt;SomeValue&lt;/span&gt; ta x) env) body&lt;/span&gt;
&lt;span id=&quot;cb24-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EApply&lt;/span&gt; f x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVFun&lt;/span&gt; g &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env f&lt;/span&gt;
&lt;span id=&quot;cb24-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    x' &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id=&quot;cb24-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    g x'&lt;/span&gt;
&lt;span id=&quot;cb24-18&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; o x y &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; o &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-19&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-20&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id=&quot;cb24-21&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env y&lt;/span&gt;
&lt;span id=&quot;cb24-22&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; b))&lt;/span&gt;
&lt;span id=&quot;cb24-23&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;OTimes&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-24&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id=&quot;cb24-25&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env y&lt;/span&gt;
&lt;span id=&quot;cb24-26&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-26&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; b))&lt;/span&gt;
&lt;span id=&quot;cb24-27&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-27&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;OLte&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-28&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-28&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id=&quot;cb24-29&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-29&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env y&lt;/span&gt;
&lt;span id=&quot;cb24-30&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-30&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;&amp;lt;=&lt;/span&gt; b))&lt;/span&gt;
&lt;span id=&quot;cb24-31&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-31&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;OAnd&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-32&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-32&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id=&quot;cb24-33&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-33&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env y&lt;/span&gt;
&lt;span id=&quot;cb24-34&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-34&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; b))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This does seem to work:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb25&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb25-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb25-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; for_ (eval M.empty fifteen) \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb25-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb25-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;print&lt;/span&gt; x&lt;/span&gt;
&lt;span id=&quot;cb25-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb25-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dv&quot;&gt;15&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Our system also allows us to produce closures and functions as values:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb26&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb26-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb26-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage2.hs#L63-L64&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb26-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb26-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb26-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb26-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;plusThree ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb26-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb26-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;plusThree &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ELambda&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;)))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb27&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb27-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb27-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; for_ (eval M.empty plusThree) \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb27-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb27-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVFun&lt;/span&gt; f &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; for_ (f (&lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;)) \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb27-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb27-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;print&lt;/span&gt; x    &lt;span class=&quot;co&quot;&gt;-- compiler-verified to always be EVInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb27-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb27-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We have a type-safe &lt;code&gt;eval&lt;/code&gt; now that will create a value of the
type we want. But we still have the same errors when looking at variables:
variables can still not be defined, or be defined as the wrong type.&lt;/p&gt;
&lt;h3 id=&quot;pretty-printing&quot;&gt;Pretty-Printing&lt;/h3&gt;
&lt;p&gt;One nice consequence of this type-index method is that if you choose to
consume them into an untyped target, you can do it more or less in the same way
as the non-indexed untyped data.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb28&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb28-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage2.hs#L87-L113&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;ppPrim ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Prim&lt;/span&gt; t &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id=&quot;cb28-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppPrim &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; n &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; PP.pretty n&lt;/span&gt;
&lt;span id=&quot;cb28-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;PBool&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;if&lt;/span&gt; b &lt;span class=&quot;kw&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;true&quot;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;false&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;PString&lt;/span&gt; s &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; PP.pretty (&lt;span class=&quot;fu&quot;&gt;show&lt;/span&gt; s)&lt;/span&gt;
&lt;span id=&quot;cb28-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;ppOp ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Op&lt;/span&gt; a b c &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id=&quot;cb28-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppOp &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;+&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OTimes&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OLte&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&amp;lt;=&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OAnd&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&amp;amp;&amp;amp;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;ppExpr ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Bool&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; t &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id=&quot;cb28-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppExpr paren &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-18&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; p &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; ppPrim p&lt;/span&gt;
&lt;span id=&quot;cb28-19&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; _ v &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; PP.pretty v&lt;/span&gt;
&lt;span id=&quot;cb28-20&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ELambda&lt;/span&gt; _ n body &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; wrap &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;\\&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; PP.pretty n &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;-&amp;gt;&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt; body&lt;/span&gt;
&lt;span id=&quot;cb28-21&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EApply&lt;/span&gt; f x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; wrap &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; f &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; x&lt;/span&gt;
&lt;span id=&quot;cb28-22&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; o x y &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; wrap &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; x &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppOp o &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; y&lt;/span&gt;
&lt;span id=&quot;cb28-23&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-24&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    wrap&lt;/span&gt;
&lt;span id=&quot;cb28-25&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; paren &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; PP.parens&lt;/span&gt;
&lt;span id=&quot;cb28-26&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-26&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;otherwise&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;id&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-27&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-27&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-28&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-28&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;prettyExpr ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; t &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id=&quot;cb28-29&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-29&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;prettyExpr &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And they render the same way:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb29&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb29-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb29-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; prettyExpr fifteen&lt;/span&gt;
&lt;span id=&quot;cb29-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb29-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;(\x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; x &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;) &lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb29-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb29-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; prettyExpr plusThree&lt;/span&gt;
&lt;span id=&quot;cb29-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb29-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;\x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; x &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb29-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb29-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; prettyExpr badVariable&lt;/span&gt;
&lt;span id=&quot;cb29-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb29-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;(\x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; x &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;) true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;still-not-fully-verified&quot;&gt;Still Not Fully Verified&lt;/h3&gt;
&lt;p&gt;Implicit in the previous section was the admission of failure: this system
lets us use indexed types to help propagate unification (the result types of
&lt;code&gt;OLte&lt;/code&gt;, &lt;code&gt;OAnd&lt;/code&gt;, &lt;code&gt;OPlus&lt;/code&gt;, etc.), but it can’t
prevent all ill-defined programs from compiling.&lt;/p&gt;
&lt;p&gt;The issue is &lt;code&gt;EVar&lt;/code&gt;: its type
&lt;code&gt;EVar :: STy t -&amp;gt; String -&amp;gt; Expr t&lt;/code&gt; lets us bind &lt;em&gt;any&lt;/em&gt;
variable name as &lt;em&gt;any&lt;/em&gt; type, and it’ll still typecheck. Even with the
help of everything we have, we can just straight-up declare a reference to an
unbound variable&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb30&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb30-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb30-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage2.hs#L71-L72&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb30-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb30-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb30-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb30-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;unboundVariable ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb30-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb30-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;unboundVariable &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;missing&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This typechecks in GHC even though it’s meaningless in the domain. We can
also reference the variable under any &lt;em&gt;type&lt;/em&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb31&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb31-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb31-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage2.hs#L57-L61&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb31-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb31-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb31-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb31-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;badVariable ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb31-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb31-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;badVariable &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb31-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb31-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EApply&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb31-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb31-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;dt&quot;&gt;ELambda&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STBool&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;))))&lt;/span&gt;
&lt;span id=&quot;cb31-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb31-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PBool&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That’s because &lt;code&gt;EVar&lt;/code&gt; can freely take any &lt;code&gt;STy&lt;/code&gt; without
any restriction, and no association with the binder name, so there’s no way for
GHC to stop us.&lt;/p&gt;
&lt;p&gt;So, again, we cannot create a &lt;em&gt;fully&lt;/em&gt; type-checked &lt;code&gt;Expr&lt;/code&gt;.
We still have to deal with &lt;em&gt;most&lt;/em&gt; of the same errors. This is noble, but
clearly not good enough. We have to go deeper.&lt;/p&gt;
&lt;h2 id=&quot;typed-records-and-sums&quot;&gt;Typed Records and Sums&lt;/h2&gt;
&lt;p&gt;A quick detour: you might have noticed that this past implementation dropped
records and sums. Before we move on, let’s go ahead and add those. Introducing
records and sums at the same time as type-indexed &lt;code&gt;Expr&lt;/code&gt; is a bit
&lt;em&gt;too&lt;/em&gt; much of a jump to fit into a single section.&lt;/p&gt;
&lt;p&gt;Let’s add sums and records, which can use pretty similar mechanisms (via
duality) for implementation.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb32&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb32-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb32-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L31-L79&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb32-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb32-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb32-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb32-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TBool&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb32-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb32-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TRecord&lt;/span&gt; [(&lt;span class=&quot;dt&quot;&gt;Symbol&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt;)]&lt;/span&gt;
&lt;span id=&quot;cb32-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb32-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TSum&lt;/span&gt; [(&lt;span class=&quot;dt&quot;&gt;Symbol&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt;)]&lt;/span&gt;
&lt;span id=&quot;cb32-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb32-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb32-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb32-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb32-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb32-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STBool&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TBool&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb32-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STString&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb32-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STRecord&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STyField&lt;/span&gt; as &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;TRecord&lt;/span&gt; as)&lt;/span&gt;
&lt;span id=&quot;cb32-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb32-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STSum&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STyField&lt;/span&gt; as &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;TSum&lt;/span&gt; as)&lt;/span&gt;
&lt;span id=&quot;cb32-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb32-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STFun&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;:-&amp;gt;&lt;/span&gt; b)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;Ty&lt;/code&gt; now includes &lt;code&gt;TRecord [(Symbol, Ty)]&lt;/code&gt; and
&lt;code&gt;TSum [(Symbol, Ty)]&lt;/code&gt;, which represent the field names and
constructor payloads (&lt;code&gt;Symbol&lt;/code&gt; being a type-level string). So, for
example, &lt;code&gt;TRecord [&quot;value&quot; ::: TInt, &quot;label&quot; ::: TString]&lt;/code&gt; would be
the type of a record with ordered fields &lt;code&gt;value&lt;/code&gt; and
&lt;code&gt;label&lt;/code&gt; of integers and strings, respectively.
&lt;code&gt;TSum [&quot;Found&quot; ::: TInt, &quot;Missing&quot; ::: TString]&lt;/code&gt; would be the type of
a sum between &lt;code&gt;Found&lt;/code&gt; containing an integer and &lt;code&gt;Missing&lt;/code&gt;
containing a string. Note we take a page out of &lt;a href=&quot;https://hackage.haskell.org/package/vinyl&quot;&gt;vinyl&lt;/a&gt; by defining the type
alias &lt;code&gt;(:::) = '(,)&lt;/code&gt; to make things syntactically nicer.&lt;/p&gt;
&lt;h3 id=&quot;record-access&quot;&gt;Record Access&lt;/h3&gt;
&lt;p&gt;We need the fields and types at the type level because we have to answer what
the &lt;code&gt;Expr&lt;/code&gt; phantom type of field access is. If we had an
&lt;code&gt;x :: Expr (TRecord [&quot;value&quot; ::: TInt, &quot;label&quot; ::: TString])&lt;/code&gt;, we
want the type of &lt;code&gt;x.value&lt;/code&gt; to be &lt;code&gt;Expr TInt&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To do this, we need to have a &lt;em&gt;value&lt;/em&gt; in our &lt;code&gt;Expr&lt;/code&gt; for
field access that can “point” at a specific field in the type. One way to do
that is to take a field of type &lt;code&gt;Index&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb33&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb33-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb33-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L47-L49&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb33-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb33-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; [k] &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; k &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb33-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;IZ&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; (x &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; xs) x&lt;/span&gt;
&lt;span id=&quot;cb33-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb33-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;IS&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; xs x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; (y &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; xs) x&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can read this as: “&lt;code&gt;IZ&lt;/code&gt; is an index to the head of the
type-level list, and &lt;code&gt;IS n&lt;/code&gt; is an index to the n-th item of the
tail”. So, &lt;code&gt;IS IZ&lt;/code&gt; is an index into the second element,
&lt;code&gt;IS (IS IZ)&lt;/code&gt; is an index into the third, etc.&lt;/p&gt;
&lt;p&gt;If we have &lt;code&gt;[&quot;value&quot; ::: TInt, &quot;label&quot; ::: TString]&lt;/code&gt;, then we have
values:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb34&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb34-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb34-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;IZ&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;    ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; [&lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&quot;label&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;] (&lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb34-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb34-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IZ&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; [&lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&quot;label&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;] (&lt;span class=&quot;st&quot;&gt;&quot;label&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note that the way this is constructed, it’s impossible for
&lt;code&gt;IS (IS IZ) :: Index [&quot;value&quot; ::: TInt, &quot;label&quot; ::: TString] _&lt;/code&gt; to
typecheck as anything!&lt;/p&gt;
&lt;p&gt;In this way, we have a well-typed field accessor syntax, which takes an
&lt;code&gt;Expr&lt;/code&gt; of a record of fields and indexes it to get an
&lt;code&gt;Expr&lt;/code&gt; of the type at that index:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb35&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb35-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb35-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L105-L105&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb35-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb35-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb35-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb35-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EAccess&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; l &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;TRecord&lt;/span&gt; as) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; as (l &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; a&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Which is typed as:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb36&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb36-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb36-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;(&lt;span class=&quot;ot&quot;&gt;`EAccess`&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IZ&lt;/span&gt;)&lt;span class=&quot;ot&quot;&gt;    ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;TRecord&lt;/span&gt; [&lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&quot;label&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;]) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb36-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb36-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;(&lt;span class=&quot;ot&quot;&gt;`EAccess`&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IZ&lt;/span&gt;)&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;TRecord&lt;/span&gt; [&lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&quot;label&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;]) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To &lt;em&gt;create&lt;/em&gt; an &lt;code&gt;Expr&lt;/code&gt; of a record, we can use
&lt;code&gt;Rec&lt;/code&gt; from &lt;em&gt;&lt;a href=&quot;https://hackage.haskell.org/package/vinyl&quot;&gt;vinyl&lt;/a&gt;&lt;/em&gt; or
&lt;code&gt;NP&lt;/code&gt; from &lt;em&gt;&lt;a href=&quot;https://hackage.haskell.org/package/sop-core&quot;&gt;sop-core&lt;/a&gt;&lt;/em&gt;: a
heterogeneous list indexed by a type-level list.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb37&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb37-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb37-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L43-L45&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb37-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb37-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb37-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb37-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; (k &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Type&lt;/span&gt;) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; [k] &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb37-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb37-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; f '[]&lt;/span&gt;
&lt;span id=&quot;cb37-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb37-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;  (:&amp;amp;) ::&lt;/span&gt; f x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; f xs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; f (x &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; xs)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you haven’t seen &lt;code&gt;Rec&lt;/code&gt; before, basically
&lt;code&gt;Rec f [a,b,c]&lt;/code&gt; is a tuple of &lt;code&gt;f a&lt;/code&gt;, &lt;code&gt;f b&lt;/code&gt;, and
&lt;code&gt;f c&lt;/code&gt;. For example:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb38&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb38-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb38-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;t &lt;span class=&quot;dt&quot;&gt;Identity&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Identity&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Identity&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;hello&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb38-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb38-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Identity&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Bool&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb38-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb38-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;t &lt;span class=&quot;dt&quot;&gt;Const&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Const&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;y&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb38-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb38-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Const&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;) [x1, x2]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Keeping &lt;code&gt;Rec f as&lt;/code&gt; instead of a direct heterogeneous list of
&lt;code&gt;a&lt;/code&gt;s lets us store more interesting things than just
&lt;code&gt;Type&lt;/code&gt;-kinded things. For example, since our lists here are lists of
&lt;code&gt;(Symbol, Ty)&lt;/code&gt;, we can create a container to hold fields:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb39&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb39-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb39-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L109-L110&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb39-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb39-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb39-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb39-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ExprField&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Symbol&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt;) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb39-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb39-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EField&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; l &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ExprField&lt;/span&gt; (l &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The field constructor keeps a &lt;code&gt;KnownSymbol l&lt;/code&gt; constraint, so the
type-level label is still available later when we need to render it:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb40&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb40-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb40-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;t &lt;span class=&quot;dt&quot;&gt;EField&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb40-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb40-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EField&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;label&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PString&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;found&quot;&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb40-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb40-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb40-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb40-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ExprField&lt;/span&gt; [&lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&quot;label&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So, we can create
&lt;code&gt;Expr (TRecord [&quot;value&quot; ::: TInt, &quot;label&quot; ::: TString])&lt;/code&gt; by taking a
&lt;code&gt;Rec&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb41&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb41-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb41-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L104-L104&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb41-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb41-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb41-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb41-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ERecord&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ExprField&lt;/span&gt; as &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;TRecord&lt;/span&gt; as)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can make this a little more ergonomic by using
&lt;code&gt;-XRequiredTypeArguments&lt;/code&gt; (as of GHC 9.10) to get rid of the
&lt;code&gt;-XTypeApplication&lt;/code&gt; ugliness:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb42&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb42-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb42-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L115-L150&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb42-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb42-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb42-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb42-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;eField ::&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;forall&lt;/span&gt; l &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; l &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ExprField&lt;/span&gt; (l &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a)&lt;/span&gt;
&lt;span id=&quot;cb42-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb42-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;eField l &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EField&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l&lt;/span&gt;
&lt;span id=&quot;cb42-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb42-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb42-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb42-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;makeRecordExample ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;TRecord&lt;/span&gt; [&lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&quot;label&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;])&lt;/span&gt;
&lt;span id=&quot;cb42-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb42-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;makeRecordExample &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb42-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb42-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ERecord&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb42-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb42-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ( eField &lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb42-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb42-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; eField &lt;span class=&quot;st&quot;&gt;&quot;label&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PString&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;found&quot;&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb42-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb42-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb42-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb42-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    )&lt;/span&gt;
&lt;span id=&quot;cb42-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb42-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb42-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb42-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;recordExample ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb42-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb42-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;recordExample &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EAccess&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; makeRecordExample &lt;span class=&quot;dt&quot;&gt;IZ&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;sum-injection-and-case-analysis&quot;&gt;Sum Injection and Case Analysis&lt;/h3&gt;
&lt;p&gt;We also need a type-level list witness for &lt;em&gt;sum&lt;/em&gt; types, because we
need to be able to implement the correct continuations for pattern matches: How
do we know &lt;em&gt;what&lt;/em&gt; thing to handle in each pattern match, unless the sum
type has that information in its type?&lt;/p&gt;
&lt;p&gt;Luckily due to the magic of duality, we can use the same tools, for the most
part! We can inject into a sum with an &lt;code&gt;Index&lt;/code&gt;, let’s say for a
&lt;code&gt;Expr (TSum [&quot;Found&quot; ::: TInt, &quot;Missing&quot; ::: TString])&lt;/code&gt;: sum type
with &lt;code&gt;Found&lt;/code&gt; containing an integer and &lt;code&gt;Missing&lt;/code&gt;
containing a string:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb43&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb43-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb43-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L106-L106&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb43-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb43-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb43-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb43-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EChoice&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; l &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; as (l &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;TSum&lt;/span&gt; as)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb44&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb44-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb44-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;EChoice&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IZ&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;        ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;TSum&lt;/span&gt; [&lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&quot;Missing&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;])&lt;/span&gt;
&lt;span id=&quot;cb44-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb44-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;EChoice&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;Missing&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IZ&lt;/span&gt;)&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;TSum&lt;/span&gt; [&lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&quot;Missing&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;])&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb45&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb45-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb45-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L181-L182&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb45-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb45-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb45-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb45-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;makeSumExample ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;TSum&lt;/span&gt; [&lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&quot;Missing&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;])&lt;/span&gt;
&lt;span id=&quot;cb45-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb45-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;makeSumExample &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EChoice&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IZ&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And we can re-use &lt;code&gt;Rec&lt;/code&gt; to define a type that can &lt;em&gt;handle&lt;/em&gt;
a &lt;code&gt;[&quot;Found&quot; ::: TInt, &quot;Missing&quot; ::: TString]&lt;/code&gt; sum:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb46&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb46-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb46-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L112-L133&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb46-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb46-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb46-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb46-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ExprHandler&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Symbol&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt;) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb46-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb46-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EHandler&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; l &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ExprHandler&lt;/span&gt; b (l &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a)&lt;/span&gt;
&lt;span id=&quot;cb46-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb46-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb46-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb46-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;eHandler ::&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;forall&lt;/span&gt; l &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; l &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ExprHandler&lt;/span&gt; b (l &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a)&lt;/span&gt;
&lt;span id=&quot;cb46-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb46-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;eHandler l &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EHandler&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb47&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb47-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb47-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;t eHandler &lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;)))&lt;/span&gt;
&lt;span id=&quot;cb47-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb47-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;ExprHandler&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt; (&lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb47-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb47-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;         &lt;span class=&quot;co&quot;&gt;-- ^ result           ^ payload&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And we can put these into a &lt;code&gt;Rec&lt;/code&gt; to handle each option in the
list:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb48&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb48-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb48-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;t eHandler &lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;)))&lt;/span&gt;
&lt;span id=&quot;cb48-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb48-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;           &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; eHandler &lt;span class=&quot;st&quot;&gt;&quot;Missing&quot;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STString&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;message&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb48-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb48-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;           &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb48-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb48-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;ExprHandler&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;) [&lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&quot;Missing&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And that’s exactly what a case statement is:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb49&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb49-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb49-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L107-L107&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb49-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb49-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb49-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb49-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ECase&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;TSum&lt;/span&gt; as) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;ExprHandler&lt;/span&gt; b) as &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; b&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb50&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb50-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb50-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L184-L191&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb50-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb50-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb50-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb50-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;sumExample ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb50-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb50-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sumExample &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb50-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb50-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ECase&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb50-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb50-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    makeSumExample&lt;/span&gt;
&lt;span id=&quot;cb50-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb50-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ( eHandler &lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;)))&lt;/span&gt;
&lt;span id=&quot;cb50-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb50-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; eHandler &lt;span class=&quot;st&quot;&gt;&quot;Missing&quot;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STString&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;message&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb50-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb50-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb50-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb50-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    )&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note that we’re still using string binders, so there’s still an element of
unsafety here… we say that the variable name is &lt;code&gt;&quot;value&quot;&lt;/code&gt; and that it
is a &lt;code&gt;TInt&lt;/code&gt;, but when we later refer to the variable with
&lt;code&gt;EVar STInt &quot;value&quot;&lt;/code&gt;, it isn’t type-checked that later references use
the same type. The compiler would be just as happy with
&lt;code&gt;EVar STString &quot;value&quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here’s an example demonstrating both failure modes: the first handler
references a variable that doesn’t exist, and the second handler references a
variable that does exist as an incorrect type! How unfortunate.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb51&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb51-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb51-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L202-L209&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb51-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb51-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb51-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb51-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;badCaseBranchExample ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb51-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb51-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;badCaseBranchExample &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb51-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb51-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ECase&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb51-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb51-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;dt&quot;&gt;EChoice&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IZ&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;)))&lt;/span&gt;
&lt;span id=&quot;cb51-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb51-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ( eHandler &lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;missing&quot;&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;)))&lt;/span&gt;
&lt;span id=&quot;cb51-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb51-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; eHandler &lt;span class=&quot;st&quot;&gt;&quot;Missing&quot;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STString&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;message&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;message&quot;&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;)))&lt;/span&gt;
&lt;span id=&quot;cb51-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb51-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb51-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb51-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    )&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;runtime-equality-for-records-and-sums&quot;&gt;Runtime Equality for Records and
Sums&lt;/h3&gt;
&lt;p&gt;One complication is that we need to update the &lt;code&gt;TestEquality&lt;/code&gt;
instance for &lt;code&gt;STy&lt;/code&gt;. The record and sum labels are type-level
&lt;code&gt;Symbol&lt;/code&gt;s, so we compare those with the &lt;code&gt;sameSymbol&lt;/code&gt; (kind
of like &lt;code&gt;testEquality&lt;/code&gt; for any &lt;code&gt;KnownSymbol&lt;/code&gt; instance) and
then compare the payload types recursively.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb52&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb52-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L284-L324&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TestEquality&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    testEquality &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sameTy&lt;/span&gt;
&lt;span id=&quot;cb52-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TestEquality&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STyField&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    testEquality &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sameField&lt;/span&gt;
&lt;span id=&quot;cb52-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;sameTy ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;:~:&lt;/span&gt; b)&lt;/span&gt;
&lt;span id=&quot;cb52-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sameTy &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt;; _ &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STBool&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STBool&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt;; _ &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STString&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STString&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt;; _ &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STRecord&lt;/span&gt; as &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;STRecord&lt;/span&gt; bs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; sameFields as bs&lt;/span&gt;
&lt;span id=&quot;cb52-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-18&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    _ &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-19&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STSum&lt;/span&gt; as &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-20&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;STSum&lt;/span&gt; bs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-21&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; sameFields as bs&lt;/span&gt;
&lt;span id=&quot;cb52-22&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-23&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    _ &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-24&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STFun&lt;/span&gt; a b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-25&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;STFun&lt;/span&gt; c d &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-26&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-26&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; sameTy a c&lt;/span&gt;
&lt;span id=&quot;cb52-27&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-27&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; sameTy b d&lt;/span&gt;
&lt;span id=&quot;cb52-28&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-28&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-29&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-29&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    _ &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-30&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-30&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-31&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-31&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;sameFields ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STyField&lt;/span&gt; xs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STyField&lt;/span&gt; ys &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; (xs &lt;span class=&quot;op&quot;&gt;:~:&lt;/span&gt; ys)&lt;/span&gt;
&lt;span id=&quot;cb52-32&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-32&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sameFields &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-33&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-33&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sameFields (x &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; xs) (y &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; ys) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-34&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-34&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; sameField x y&lt;/span&gt;
&lt;span id=&quot;cb52-35&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-35&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; sameFields xs ys&lt;/span&gt;
&lt;span id=&quot;cb52-36&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-36&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-37&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-37&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sameFields _ _ &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-38&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-38&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-39&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-39&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;sameField ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STyField&lt;/span&gt; x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STyField&lt;/span&gt; y &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; (x &lt;span class=&quot;op&quot;&gt;:~:&lt;/span&gt; y)&lt;/span&gt;
&lt;span id=&quot;cb52-40&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-40&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sameField (&lt;span class=&quot;dt&quot;&gt;STyField&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l tx) (&lt;span class=&quot;dt&quot;&gt;STyField&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;m ty) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-41&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-41&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; sameSymbol (&lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l) (&lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;m)&lt;/span&gt;
&lt;span id=&quot;cb52-42&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-42&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; sameTy tx ty&lt;/span&gt;
&lt;span id=&quot;cb52-43&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-43&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;the-full-eval&quot;&gt;The Full Eval&lt;/h3&gt;
&lt;p&gt;Before we write the final &lt;code&gt;eval&lt;/code&gt;, let’s practice using
&lt;code&gt;Index&lt;/code&gt; and &lt;code&gt;Rec&lt;/code&gt; together. If we have an index
&lt;code&gt;Index as a&lt;/code&gt; that picks out a value &lt;code&gt;a&lt;/code&gt; in
&lt;code&gt;as&lt;/code&gt;, then we can pick out the &lt;code&gt;f a&lt;/code&gt; from a
&lt;code&gt;Rec f as&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb53&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb53-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb53-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L60-L63&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb53-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb53-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb53-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb53-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;indexRec ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; xs x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; f xs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; f x&lt;/span&gt;
&lt;span id=&quot;cb53-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb53-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;indexRec &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb53-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb53-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;IZ&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; \(x &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; _) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; x&lt;/span&gt;
&lt;span id=&quot;cb53-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb53-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;IS&lt;/span&gt; i &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; \(_ &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; xs) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; indexRec i xs&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We also can recursively iterate a function over each item, assuming the
function &lt;code&gt;forall x. f x -&amp;gt; g x&lt;/code&gt;: that is, we can turn a
&lt;code&gt;Rec f as&lt;/code&gt; into a &lt;code&gt;Rec g as&lt;/code&gt; assuming our function is
polymorphic over each &lt;code&gt;x&lt;/code&gt;, and only depends on the shape of
&lt;code&gt;f&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb54&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb54-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb54-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L65-L67&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb54-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb54-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb54-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb54-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;traverseRec ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Applicative&lt;/span&gt; m &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; (&lt;span class=&quot;kw&quot;&gt;forall&lt;/span&gt; x&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; f x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (g x)) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; f xs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; g xs)&lt;/span&gt;
&lt;span id=&quot;cb54-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb54-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;traverseRec _ &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb54-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb54-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;traverseRec f (x &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; xs) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; (&lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; f x &lt;span class=&quot;op&quot;&gt;&amp;lt;*&amp;gt;&lt;/span&gt; traverseRec f xs&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With that, we can write our full &lt;code&gt;eval&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb55&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb55-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L326-L369&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb55-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb55-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;eval ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;SomeValue&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; t &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; t)&lt;/span&gt;
&lt;span id=&quot;cb55-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;eval env &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb55-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; n) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; n)&lt;/span&gt;
&lt;span id=&quot;cb55-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PBool&lt;/span&gt; b) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; b)&lt;/span&gt;
&lt;span id=&quot;cb55-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PString&lt;/span&gt; s) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVString&lt;/span&gt; s)&lt;/span&gt;
&lt;span id=&quot;cb55-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; t v &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb55-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;SomeValue&lt;/span&gt; t' v' &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; M.lookup v env&lt;/span&gt;
&lt;span id=&quot;cb55-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; sameTy t t'&lt;/span&gt;
&lt;span id=&quot;cb55-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; v'&lt;/span&gt;
&lt;span id=&quot;cb55-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ELambda&lt;/span&gt; ta n body &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb55-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVFun&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; \x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; eval (M.insert n (&lt;span class=&quot;dt&quot;&gt;SomeValue&lt;/span&gt; ta x) env) body&lt;/span&gt;
&lt;span id=&quot;cb55-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EApply&lt;/span&gt; f x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb55-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVFun&lt;/span&gt; g &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env f&lt;/span&gt;
&lt;span id=&quot;cb55-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    x' &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id=&quot;cb55-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    g x'&lt;/span&gt;
&lt;span id=&quot;cb55-18&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; o x y &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; o &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb55-19&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb55-20&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id=&quot;cb55-21&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env y&lt;/span&gt;
&lt;span id=&quot;cb55-22&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; b))&lt;/span&gt;
&lt;span id=&quot;cb55-23&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;OTimes&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb55-24&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id=&quot;cb55-25&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env y&lt;/span&gt;
&lt;span id=&quot;cb55-26&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-26&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; b))&lt;/span&gt;
&lt;span id=&quot;cb55-27&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-27&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;OLte&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb55-28&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-28&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id=&quot;cb55-29&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-29&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env y&lt;/span&gt;
&lt;span id=&quot;cb55-30&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-30&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;&amp;lt;=&lt;/span&gt; b))&lt;/span&gt;
&lt;span id=&quot;cb55-31&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-31&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;OAnd&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb55-32&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-32&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id=&quot;cb55-33&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-33&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env y&lt;/span&gt;
&lt;span id=&quot;cb55-34&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-34&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; b))&lt;/span&gt;
&lt;span id=&quot;cb55-35&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-35&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ERecord&lt;/span&gt; xs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb55-36&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-36&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVRecord&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; traverseRec (evalField env) xs&lt;/span&gt;
&lt;span id=&quot;cb55-37&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-37&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EAccess&lt;/span&gt; e i &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb55-38&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-38&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVRecord&lt;/span&gt; xs &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env e&lt;/span&gt;
&lt;span id=&quot;cb55-39&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-39&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; indexRec i xs &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb55-40&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-40&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVField&lt;/span&gt; v &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; v&lt;/span&gt;
&lt;span id=&quot;cb55-41&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-41&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EChoice&lt;/span&gt; i x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb55-42&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-42&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVSum&lt;/span&gt; i &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id=&quot;cb55-43&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-43&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ECase&lt;/span&gt; x hs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb55-44&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-44&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVSum&lt;/span&gt; i v &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id=&quot;cb55-45&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-45&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; indexRec i hs &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb55-46&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-46&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EHandler&lt;/span&gt; t n body &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; eval (M.insert n (&lt;span class=&quot;dt&quot;&gt;SomeValue&lt;/span&gt; t v) env) body&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;ergonomics-of-records-and-sums&quot;&gt;Ergonomics of Records and Sums&lt;/h3&gt;
&lt;p&gt;Note that we could also choose to implement records and sums using row types
indexed by the name of the field itself, instead of an ordered list of tuples.
This would have the advantage of making, for example,
&lt;code&gt;{ value :: Int, label :: String }&lt;/code&gt; the same type as
&lt;code&gt;{ label :: String, value :: Int }&lt;/code&gt;. However, I personally prefer the
style of building things inductively (&lt;code&gt;:&amp;amp;&lt;/code&gt;/&lt;code&gt;RNil&lt;/code&gt; and
&lt;code&gt;IS&lt;/code&gt;/&lt;code&gt;IZ&lt;/code&gt;), it makes the type errors and constructions a
lot easier to work with and reason with.&lt;/p&gt;
&lt;p&gt;However, we can get a little bit of the best of both worlds by using
typeclasses to auto-insert the &lt;code&gt;Index&lt;/code&gt; witnesses into a list.&lt;/p&gt;
&lt;p&gt;First, we can write a typeclass that searches a type-level list of fields and
produces the right &lt;code&gt;Index&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb56&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb56-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb56-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L51-L58&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb56-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb56-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb56-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb56-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ListIx&lt;/span&gt; (&lt;span class=&quot;ot&quot;&gt;l ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Symbol&lt;/span&gt;) (&lt;span class=&quot;ot&quot;&gt;xs ::&lt;/span&gt; [(&lt;span class=&quot;dt&quot;&gt;Symbol&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt;)]) (&lt;span class=&quot;ot&quot;&gt;a ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; l xs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; a &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb56-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb56-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;  listIx ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; xs (l &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a)&lt;/span&gt;
&lt;span id=&quot;cb56-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb56-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb56-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb56-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ListIx&lt;/span&gt; l (l &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; xs) a &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb56-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb56-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  listIx &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IZ&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb56-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb56-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb56-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb56-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{-# OVERLAPPABLE #-}&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ListIx&lt;/span&gt; l xs a &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ListIx&lt;/span&gt; l (m &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; b &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; xs) a &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb56-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb56-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  listIx &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IS&lt;/span&gt; (listIx &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The FunDep &lt;code&gt;l xs -&amp;gt; a&lt;/code&gt; lets us use this like a function: for a
label &lt;code&gt;l&lt;/code&gt; and a list &lt;code&gt;xs&lt;/code&gt;, we should be able to uniquely
determine the &lt;code&gt;a&lt;/code&gt; type it singles out, if it exists. So we have an
instance of
&lt;code&gt;ListIx &quot;value&quot; [&quot;value&quot; ::: TInt, &quot;label&quot; ::: TString] TInt&lt;/code&gt;, where
the label &lt;code&gt;&quot;value&quot;&lt;/code&gt; and the list uniquely determines the result type
&lt;code&gt;TInt&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We can now have a helper function that we can call like
&lt;code&gt;eAccess &quot;value&quot;&lt;/code&gt; using GHC 9.10’s
&lt;code&gt;RequiredTypeArguments&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb57&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb57-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb57-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L118-L123&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb57-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb57-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb57-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb57-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;eAccess ::&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb57-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb57-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;forall&lt;/span&gt; (&lt;span class=&quot;ot&quot;&gt;l ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Symbol&lt;/span&gt;) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb57-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb57-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  (&lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; l, &lt;span class=&quot;dt&quot;&gt;ListIx&lt;/span&gt; l as a) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb57-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb57-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;TRecord&lt;/span&gt; as) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb57-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb57-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; a&lt;/span&gt;
&lt;span id=&quot;cb57-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb57-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;eAccess l e &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EAccess&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l e (listIx &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That lets us write the field name directly, and the compiler will generate
the &lt;code&gt;Index&lt;/code&gt; automatically for us:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb58&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb58-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb58-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L167-L176&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb58-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb58-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb58-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb58-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;namedAccessExample ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb58-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb58-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;namedAccessExample &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb58-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb58-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  eAccess&lt;/span&gt;
&lt;span id=&quot;cb58-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb58-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;st&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb58-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb58-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ( &lt;span class=&quot;dt&quot;&gt;ERecord&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb58-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb58-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        ( eField &lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb58-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb58-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; eField &lt;span class=&quot;st&quot;&gt;&quot;label&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PString&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;found&quot;&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb58-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb58-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb58-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb58-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        )&lt;/span&gt;
&lt;span id=&quot;cb58-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb58-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    )&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here,
&lt;code&gt;eAccess &quot;value&quot; :: Expr (TRecord [&quot;value&quot; ::: TInt, &quot;label&quot; ::: TString]) -&amp;gt; Expr TInt&lt;/code&gt;,
its result type uniquely determined by the types in the record fields.&lt;/p&gt;
&lt;p&gt;The same trick works for sum injections, so we can write the constructor name
directly:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb59&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb59-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb59-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L125-L179&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb59-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb59-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb59-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb59-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;eChoice ::&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb59-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb59-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;forall&lt;/span&gt; (&lt;span class=&quot;ot&quot;&gt;l ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Symbol&lt;/span&gt;) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb59-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb59-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  (&lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; l, &lt;span class=&quot;dt&quot;&gt;ListIx&lt;/span&gt; l as a) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb59-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb59-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb59-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb59-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;TSum&lt;/span&gt; as)&lt;/span&gt;
&lt;span id=&quot;cb59-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb59-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;eChoice l e &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EChoice&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l (listIx &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l) e&lt;/span&gt;
&lt;span id=&quot;cb59-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb59-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb59-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb59-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;namedChoiceExample ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;TSum&lt;/span&gt; [&lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&quot;Missing&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;])&lt;/span&gt;
&lt;span id=&quot;cb59-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb59-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;namedChoiceExample &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; eChoice &lt;span class=&quot;st&quot;&gt;&quot;Missing&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PString&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;not here&quot;&lt;/span&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here,
&lt;code&gt;eChoice &quot;Missing&quot; :: Expr TString -&amp;gt; Expr (TSum [&quot;Found&quot; ::: TInt, &quot;Missing&quot; ::: TString])&lt;/code&gt;,
because the constructor name &lt;code&gt;&quot;Missing&quot;&lt;/code&gt; uniquely determines the
payload type inside that sum.&lt;/p&gt;
&lt;h3 id=&quot;pretty-printing-records-and-sums&quot;&gt;Pretty-Printing Records and Sums&lt;/h3&gt;
&lt;p&gt;To pretty-print, we finally use that &lt;code&gt;KnownSymbol&lt;/code&gt; constraint
we’ve been tracking this entire time. We can use
&lt;code&gt;symbolVal :: KnownSymbol s =&amp;gt; p s -&amp;gt; String&lt;/code&gt; to get the string
&lt;em&gt;value&lt;/em&gt; from the type-level string.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb60&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb60-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L237-L282&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;ppPrim ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Prim&lt;/span&gt; t &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id=&quot;cb60-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppPrim &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; n &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; PP.pretty n&lt;/span&gt;
&lt;span id=&quot;cb60-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;PBool&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;if&lt;/span&gt; b &lt;span class=&quot;kw&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;true&quot;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;false&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;PString&lt;/span&gt; s &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; PP.pretty (&lt;span class=&quot;fu&quot;&gt;show&lt;/span&gt; s)&lt;/span&gt;
&lt;span id=&quot;cb60-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;ppOp ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Op&lt;/span&gt; a b c &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id=&quot;cb60-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppOp &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;+&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OTimes&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OLte&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&amp;lt;=&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OAnd&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&amp;amp;&amp;amp;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;ppFields ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ExprField&lt;/span&gt; xs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann]&lt;/span&gt;
&lt;span id=&quot;cb60-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppFields &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; []&lt;/span&gt;
&lt;span id=&quot;cb60-18&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppFields (&lt;span class=&quot;dt&quot;&gt;EField&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l x &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; xs) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-19&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  (PP.pretty (symbolVal (&lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l)) &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;=&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt; x) &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; ppFields xs&lt;/span&gt;
&lt;span id=&quot;cb60-20&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-21&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;ppHandlers ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;ExprHandler&lt;/span&gt; b) xs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann]&lt;/span&gt;
&lt;span id=&quot;cb60-22&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppHandlers &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; []&lt;/span&gt;
&lt;span id=&quot;cb60-23&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppHandlers (&lt;span class=&quot;dt&quot;&gt;EHandler&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l _ n body &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; xs) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-24&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  (PP.pretty (symbolVal (&lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l)) &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; PP.pretty n &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;-&amp;gt;&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt; body) &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; ppHandlers xs&lt;/span&gt;
&lt;span id=&quot;cb60-25&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-26&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-26&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;ppExpr ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Bool&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; t &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id=&quot;cb60-27&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-27&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppExpr paren &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-28&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-28&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; p &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; ppPrim p&lt;/span&gt;
&lt;span id=&quot;cb60-29&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-29&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; _ v &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; PP.pretty v&lt;/span&gt;
&lt;span id=&quot;cb60-30&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-30&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ELambda&lt;/span&gt; _ n body &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; wrap &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;\\&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; PP.pretty n &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;-&amp;gt;&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt; body&lt;/span&gt;
&lt;span id=&quot;cb60-31&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-31&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EApply&lt;/span&gt; f x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; wrap &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; f &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; x&lt;/span&gt;
&lt;span id=&quot;cb60-32&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-32&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; o x y &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; wrap &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; x &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppOp o &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; y&lt;/span&gt;
&lt;span id=&quot;cb60-33&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-33&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ERecord&lt;/span&gt; xs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; PP.encloseSep &lt;span class=&quot;st&quot;&gt;&quot;{ &quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot; }&quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;, &quot;&lt;/span&gt; (ppFields xs)&lt;/span&gt;
&lt;span id=&quot;cb60-34&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-34&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EAccess&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l e _ &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; e &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;.&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; PP.pretty (symbolVal (&lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l))&lt;/span&gt;
&lt;span id=&quot;cb60-35&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-35&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EChoice&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l _ x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; wrap &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; PP.pretty (symbolVal (&lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l)) &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; x&lt;/span&gt;
&lt;span id=&quot;cb60-36&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-36&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ECase&lt;/span&gt; x hs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-37&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-37&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    wrap &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-38&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-38&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      PP.sep&lt;/span&gt;
&lt;span id=&quot;cb60-39&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-39&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        [ &lt;span class=&quot;st&quot;&gt;&quot;case&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt; x &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;of&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-40&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-40&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        , PP.encloseSep &lt;span class=&quot;st&quot;&gt;&quot;{ &quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot; }&quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;; &quot;&lt;/span&gt; (ppHandlers hs)&lt;/span&gt;
&lt;span id=&quot;cb60-41&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-41&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        ]&lt;/span&gt;
&lt;span id=&quot;cb60-42&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-42&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-43&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-43&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    wrap&lt;/span&gt;
&lt;span id=&quot;cb60-44&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-44&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; paren &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; PP.parens&lt;/span&gt;
&lt;span id=&quot;cb60-45&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-45&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;otherwise&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;id&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-46&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-46&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-47&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-47&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;prettyExpr ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; t &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id=&quot;cb60-48&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-48&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;prettyExpr &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;capturing-variables&quot;&gt;Capturing Variables&lt;/h2&gt;
&lt;p&gt;In order to have &lt;code&gt;EVar&lt;/code&gt; be type-safe, the environment itself needs
to be a part of the &lt;code&gt;Expr&lt;/code&gt; type, and you should only be able to use
&lt;code&gt;EVar&lt;/code&gt; if the &lt;code&gt;Expr&lt;/code&gt; enforces it. &lt;code&gt;ELambda&lt;/code&gt;
would, therefore, introduce the new variable to the environment.&lt;/p&gt;
&lt;p&gt;We’ll have:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb61&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb61-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb61-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage4.hs#L80-L80&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb61-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb61-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb61-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb61-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; [(&lt;span class=&quot;dt&quot;&gt;Symbol&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt;)] &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So a value of type &lt;code&gt;Expr [&quot;x&quot; ::: TInt, &quot;y&quot; ::: TBool] t&lt;/code&gt; is an
expression with free variables &lt;code&gt;x&lt;/code&gt; of type &lt;code&gt;Int&lt;/code&gt; and
&lt;code&gt;y&lt;/code&gt; of type &lt;code&gt;Bool&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Surprise! That small detour to add records and sums to our language actually
ended up being a smooth precursor to all of the techniques we will be using to
solve for variable binders.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ELambda&lt;/code&gt; would therefore take an &lt;code&gt;Expr&lt;/code&gt; with a free
variable and turn it into an &lt;code&gt;Expr&lt;/code&gt; of a function type. We also keep
a &lt;code&gt;KnownSymbol&lt;/code&gt; constraint for the name so that we can recover the
name when we render the expression.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb62&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb62-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb62-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage4.hs#L83-L83&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb62-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb62-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb62-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb62-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ELambda&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; n &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (n &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a '&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; vs) b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs (a &lt;span class=&quot;op&quot;&gt;:-&amp;gt;&lt;/span&gt; b)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;EVar&lt;/code&gt; then becomes exactly like &lt;code&gt;EAccess&lt;/code&gt;! We “index”
into the environment of the &lt;code&gt;Expr vs a&lt;/code&gt; using &lt;code&gt;Index&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb63&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb63-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb63-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage4.hs#L82-L82&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb63-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb63-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb63-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb63-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; vs (n &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; t) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs t&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So it is legal to have
&lt;code&gt;EVar IZ :: Expr [&quot;x&quot; ::: TInt, &quot;y&quot; ::: TBool] TInt&lt;/code&gt;, and also it is
automatically inferred to be a &lt;code&gt;TInt&lt;/code&gt;. But we could &lt;em&gt;not&lt;/em&gt;
write &lt;code&gt;EVar IZ :: Expr [] TInt&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And finally, our whole &lt;code&gt;Expr&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb64&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb64-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb64-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage4.hs#L80-L89&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb64-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb64-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb64-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb64-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; [(&lt;span class=&quot;dt&quot;&gt;Symbol&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt;)] &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb64-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb64-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Prim&lt;/span&gt; t &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs t&lt;/span&gt;
&lt;span id=&quot;cb64-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb64-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; vs (n &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; t) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs t&lt;/span&gt;
&lt;span id=&quot;cb64-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb64-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ELambda&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; n &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (n &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a '&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; vs) b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs (a &lt;span class=&quot;op&quot;&gt;:-&amp;gt;&lt;/span&gt; b)&lt;/span&gt;
&lt;span id=&quot;cb64-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb64-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EApply&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs (a &lt;span class=&quot;op&quot;&gt;:-&amp;gt;&lt;/span&gt; b) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs b&lt;/span&gt;
&lt;span id=&quot;cb64-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb64-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Op&lt;/span&gt; a b c &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs c&lt;/span&gt;
&lt;span id=&quot;cb64-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb64-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ERecord&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;ExprField&lt;/span&gt; vs) as &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs (&lt;span class=&quot;dt&quot;&gt;TRecord&lt;/span&gt; as)&lt;/span&gt;
&lt;span id=&quot;cb64-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb64-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EAccess&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; l &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs (&lt;span class=&quot;dt&quot;&gt;TRecord&lt;/span&gt; as) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; as (l &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs a&lt;/span&gt;
&lt;span id=&quot;cb64-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb64-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EChoice&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; l &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; as (l &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs (&lt;span class=&quot;dt&quot;&gt;TSum&lt;/span&gt; as)&lt;/span&gt;
&lt;span id=&quot;cb64-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb64-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ECase&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs (&lt;span class=&quot;dt&quot;&gt;TSum&lt;/span&gt; as) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;ExprHandler&lt;/span&gt; vs b) as &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs b&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Just like with record access, we can use the &lt;code&gt;ListIx&lt;/code&gt; class to
write a named helper:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb65&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb65-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb65-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage4.hs#L47-L120&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb65-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb65-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb65-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb65-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ListIx&lt;/span&gt; (&lt;span class=&quot;ot&quot;&gt;l ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Symbol&lt;/span&gt;) (&lt;span class=&quot;ot&quot;&gt;xs ::&lt;/span&gt; [(&lt;span class=&quot;dt&quot;&gt;Symbol&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt;)]) (&lt;span class=&quot;ot&quot;&gt;a ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; l xs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; a &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb65-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb65-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;  listIx ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; xs (l &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a)&lt;/span&gt;
&lt;span id=&quot;cb65-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb65-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb65-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb65-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ListIx&lt;/span&gt; l (l &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a '&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; xs) a &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb65-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb65-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  listIx &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IZ&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb65-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb65-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb65-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb65-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{-# OVERLAPPABLE #-}&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ListIx&lt;/span&gt; l xs a &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ListIx&lt;/span&gt; l (m &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; b '&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; xs) a &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb65-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb65-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  listIx &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IS&lt;/span&gt; (listIx &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l)&lt;/span&gt;
&lt;span id=&quot;cb65-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb65-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb65-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb65-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;eVar ::&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;forall&lt;/span&gt; n &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ListIx&lt;/span&gt; n vs a &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs a&lt;/span&gt;
&lt;span id=&quot;cb65-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb65-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;eVar n &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; (listIx &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;n)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Adding in our other &lt;code&gt;-XRequiredTypeArguments&lt;/code&gt; helpers:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb66&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb66-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage4.hs#L91-L117&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;eLambda ::&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;forall&lt;/span&gt; n &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; n &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (n &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a '&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; vs) b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs (a &lt;span class=&quot;op&quot;&gt;:-&amp;gt;&lt;/span&gt; b)&lt;/span&gt;
&lt;span id=&quot;cb66-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;eLambda n &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ELambda&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;n&lt;/span&gt;
&lt;span id=&quot;cb66-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;eField ::&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;forall&lt;/span&gt; l &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; l &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ExprField&lt;/span&gt; vs (l &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a)&lt;/span&gt;
&lt;span id=&quot;cb66-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;eField l &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EField&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l&lt;/span&gt;
&lt;span id=&quot;cb66-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;eAccess ::&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;forall&lt;/span&gt; l &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  (&lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; l, &lt;span class=&quot;dt&quot;&gt;ListIx&lt;/span&gt; l as a) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs (&lt;span class=&quot;dt&quot;&gt;TRecord&lt;/span&gt; as) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs a&lt;/span&gt;
&lt;span id=&quot;cb66-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;eAccess l e &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EAccess&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l e (listIx &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l)&lt;/span&gt;
&lt;span id=&quot;cb66-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;eChoice ::&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;forall&lt;/span&gt; l &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-18&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  (&lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; l, &lt;span class=&quot;dt&quot;&gt;ListIx&lt;/span&gt; l as a) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-19&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-20&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs (&lt;span class=&quot;dt&quot;&gt;TSum&lt;/span&gt; as)&lt;/span&gt;
&lt;span id=&quot;cb66-21&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;eChoice l e &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EChoice&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l (listIx &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l) e&lt;/span&gt;
&lt;span id=&quot;cb66-22&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-23&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;eHandler ::&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-24&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;forall&lt;/span&gt; n &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-25&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;forall&lt;/span&gt; l &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-26&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-26&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  (&lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; n, &lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; l) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-27&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-27&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (n &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a '&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; vs) b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-28&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-28&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ExprHandler&lt;/span&gt; vs b (l &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a)&lt;/span&gt;
&lt;span id=&quot;cb66-29&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-29&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;eHandler n l &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EHandler&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;n &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And we get something that is &lt;em&gt;truly&lt;/em&gt; type-safe: all expressions are
well-typed, and all variables are ensured to be bound!&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb67&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb67-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage4.hs#L139-L171&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;fifteen ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; '[] &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;fifteen &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EApply&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (eLambda &lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OTimes&lt;/span&gt; (eVar &lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;))))&lt;/span&gt;
&lt;span id=&quot;cb67-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb67-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;recordExample ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; '[] &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;recordExample &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ( eAccess&lt;/span&gt;
&lt;span id=&quot;cb67-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        ( &lt;span class=&quot;dt&quot;&gt;ERecord&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            ( eField &lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb67-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; eField &lt;span class=&quot;st&quot;&gt;&quot;label&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PString&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;found&quot;&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb67-18&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-19&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            )&lt;/span&gt;
&lt;span id=&quot;cb67-20&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        )&lt;/span&gt;
&lt;span id=&quot;cb67-21&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    )&lt;/span&gt;
&lt;span id=&quot;cb67-22&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb67-23&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-24&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;sumExample ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; '[] &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-25&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sumExample &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-26&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-26&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ECase&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-27&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-27&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (eChoice &lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;)))&lt;/span&gt;
&lt;span id=&quot;cb67-28&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-28&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ( eHandler &lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; (eVar &lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;)))&lt;/span&gt;
&lt;span id=&quot;cb67-29&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-29&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; eHandler &lt;span class=&quot;st&quot;&gt;&quot;message&quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;Missing&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb67-30&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-30&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-31&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-31&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    )&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;what-we-gained&quot;&gt;What we gained&lt;/h3&gt;
&lt;p&gt;Now all of the previous “bad” examples we gave are finally
compiler-verified:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb68&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb68-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;t (&lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IZ&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; '[] &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb68-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;interactive&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb68-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    • &lt;span class=&quot;dt&quot;&gt;Couldn't&lt;/span&gt; match &lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; (n0 &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; xs0&lt;/span&gt;
&lt;span id=&quot;cb68-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                     with&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; '[]&lt;/span&gt;
&lt;span id=&quot;cb68-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;Expected&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; '[] (n0 &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb68-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;dt&quot;&gt;Actual&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; ((n0 &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; xs0) (n0 &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb68-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb68-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;t (&lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IZ&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; '[&lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;] &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb68-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;interactive&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb68-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    • &lt;span class=&quot;dt&quot;&gt;Couldn't&lt;/span&gt; match &lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; ‘&lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;’ with ‘&lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;’&lt;/span&gt;
&lt;span id=&quot;cb68-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;Expected&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; '[&lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;] (&lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb68-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;dt&quot;&gt;Actual&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; '[&lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;] (&lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb68-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb68-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;t &lt;span class=&quot;dt&quot;&gt;ECase&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb68-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      (&lt;span class=&quot;dt&quot;&gt;EChoice&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IZ&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;))&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; '[] (&lt;span class=&quot;dt&quot;&gt;TSum&lt;/span&gt; '[&lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&quot;Missing&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;]))&lt;/span&gt;
&lt;span id=&quot;cb68-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      ( &lt;span class=&quot;dt&quot;&gt;EHandler&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IZ&lt;/span&gt;)) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;)))&lt;/span&gt;
&lt;span id=&quot;cb68-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EHandler&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;message&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;Missing&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IZ&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;)))&lt;/span&gt;
&lt;span id=&quot;cb68-18&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb68-19&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      )&lt;/span&gt;
&lt;span id=&quot;cb68-20&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;interactive&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb68-21&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    • &lt;span class=&quot;dt&quot;&gt;Couldn't&lt;/span&gt; match &lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; (n0 &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; xs0&lt;/span&gt;
&lt;span id=&quot;cb68-22&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                     with&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; '[]&lt;/span&gt;
&lt;span id=&quot;cb68-23&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;interactive&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb68-24&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    • &lt;span class=&quot;dt&quot;&gt;Couldn't&lt;/span&gt; match &lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; ‘&lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;’ with ‘&lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;’&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And using the &lt;code&gt;ListIx&lt;/code&gt; helpers, those same failures show up as
failed index searches:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb69&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb69-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb69-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;t (eVar &lt;span class=&quot;st&quot;&gt;&quot;missing&quot;&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; '[] &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb69-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb69-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;interactive&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb69-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb69-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    • &lt;span class=&quot;dt&quot;&gt;No&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; for ‘&lt;span class=&quot;dt&quot;&gt;ListIx&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;missing&quot;&lt;/span&gt; '[] &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;’&lt;/span&gt;
&lt;span id=&quot;cb69-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb69-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb69-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb69-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;t (eVar &lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; '[&lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;] &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb69-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb69-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;interactive&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb69-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb69-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    • &lt;span class=&quot;dt&quot;&gt;No&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; for ‘&lt;span class=&quot;dt&quot;&gt;ListIx&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt; '[] &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;’&lt;/span&gt;
&lt;span id=&quot;cb69-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb69-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb69-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb69-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;t &lt;span class=&quot;dt&quot;&gt;ECase&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb69-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb69-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      (eChoice &lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;))&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; '[] (&lt;span class=&quot;dt&quot;&gt;TSum&lt;/span&gt; '[&lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&quot;Missing&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;]))&lt;/span&gt;
&lt;span id=&quot;cb69-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb69-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      ( eHandler &lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; (eVar &lt;span class=&quot;st&quot;&gt;&quot;missing&quot;&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;)))&lt;/span&gt;
&lt;span id=&quot;cb69-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb69-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; eHandler &lt;span class=&quot;st&quot;&gt;&quot;message&quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;Missing&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; (eVar &lt;span class=&quot;st&quot;&gt;&quot;message&quot;&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;)))&lt;/span&gt;
&lt;span id=&quot;cb69-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb69-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb69-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb69-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      )&lt;/span&gt;
&lt;span id=&quot;cb69-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb69-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;interactive&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb69-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb69-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    • &lt;span class=&quot;dt&quot;&gt;No&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; for ‘&lt;span class=&quot;dt&quot;&gt;ListIx&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;missing&quot;&lt;/span&gt; '[] &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;’&lt;/span&gt;
&lt;span id=&quot;cb69-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb69-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;interactive&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb69-18&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb69-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    • &lt;span class=&quot;dt&quot;&gt;No&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; for ‘&lt;span class=&quot;dt&quot;&gt;ListIx&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;message&quot;&lt;/span&gt; '[] &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;’&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Expressions that are not well-typed in our domain language are now rejected
by GHC!&lt;a class=&quot;footnote-ref&quot; href=&quot;http://feeds.feedburner.com/incodeblog#fn1&quot; id=&quot;fnref1&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;(As an exercise, can understand why those errors are what they are? Why they
all contain &lt;code&gt;ListIx _ '[]&lt;/code&gt;? For more ergonomics there is stuff we can
do with &lt;code&gt;TypeError&lt;/code&gt; machinery to make the messages a little prettier;
the &lt;em&gt;vinyl&lt;/em&gt; library does a lot to make error messages a bit better, like
in &lt;code&gt;HasField&lt;/code&gt; &lt;a href=&quot;https://hackage.haskell.org/package/vinyl/docs/Data-Vinyl-Derived.html#t:FieldType&quot;&gt;instance&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Note that this is sometimes done using straight &lt;a href=&quot;https://en.wikipedia.org/wiki/De_Bruijn_index&quot;&gt;De Bruijn indices&lt;/a&gt;:
&lt;code&gt;Expr :: [Ty] -&amp;gt; Type&lt;/code&gt;, so we don’t use any names but just the
direct index, but the point of this exercise is to be &lt;em&gt;borderline&lt;/em&gt;
unbearable to write, and &lt;em&gt;not&lt;/em&gt; to be &lt;em&gt;actually&lt;/em&gt; unbearable to
write.&lt;/p&gt;
&lt;h3 id=&quot;eval-with-a-typed-environment&quot;&gt;Eval with a typed environment&lt;/h3&gt;
&lt;p&gt;To actually write &lt;em&gt;eval&lt;/em&gt; now, we need to have a type-safe environment
to store these variables. In order to &lt;code&gt;eval&lt;/code&gt; an &lt;code&gt;Expr vs&lt;/code&gt;,
we need &lt;code&gt;EValue&lt;/code&gt;s for each &lt;code&gt;v&lt;/code&gt; in &lt;code&gt;vs&lt;/code&gt;. So for
&lt;code&gt;Expr [&quot;x&quot; ::: TInt, &quot;y&quot; ::: TBool]&lt;/code&gt;, we need to store a
&lt;code&gt;TInt&lt;/code&gt; and a &lt;code&gt;TBool&lt;/code&gt;. We can once again re-purpose
&lt;code&gt;Rec&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb70&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb70-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb70-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage4.hs#L130-L131&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb70-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb70-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb70-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb70-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValueField&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Symbol&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt;) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb70-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb70-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVField&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValueField&lt;/span&gt; '(l, a)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb71&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb71-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb71-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;t (&lt;span class=&quot;dt&quot;&gt;EVField&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVField&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValueField&lt;/span&gt; [&lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&quot;y&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TBool&lt;/span&gt;])&lt;/span&gt;
&lt;span id=&quot;cb71-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb71-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValueField&lt;/span&gt; [&lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&quot;y&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TBool&lt;/span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And so we can finally write:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb72&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb72-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage4.hs#L122-L271&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb72-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb72-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb72-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb72-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Bool&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TBool&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb72-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVString&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb72-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVRecord&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValueField&lt;/span&gt; as &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;TRecord&lt;/span&gt; as)&lt;/span&gt;
&lt;span id=&quot;cb72-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVSum&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; as (l &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;TSum&lt;/span&gt; as)&lt;/span&gt;
&lt;span id=&quot;cb72-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVFun&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; b) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;:-&amp;gt;&lt;/span&gt; b)&lt;/span&gt;
&lt;span id=&quot;cb72-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb72-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;eval ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValueField&lt;/span&gt; vs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs t &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; t&lt;/span&gt;
&lt;span id=&quot;cb72-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;eval env &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb72-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; n) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; n&lt;/span&gt;
&lt;span id=&quot;cb72-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PBool&lt;/span&gt; b) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; b&lt;/span&gt;
&lt;span id=&quot;cb72-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PString&lt;/span&gt; s) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVString&lt;/span&gt; s&lt;/span&gt;
&lt;span id=&quot;cb72-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; i &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; indexRec i env &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb72-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVField&lt;/span&gt; v &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; v&lt;/span&gt;
&lt;span id=&quot;cb72-18&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ELambda&lt;/span&gt; body &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb72-19&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVFun&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; \x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; eval (&lt;span class=&quot;dt&quot;&gt;EVField&lt;/span&gt; x &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; env) body&lt;/span&gt;
&lt;span id=&quot;cb72-20&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EApply&lt;/span&gt; f x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; eval env f &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb72-21&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVFun&lt;/span&gt; g &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; g (eval env x)&lt;/span&gt;
&lt;span id=&quot;cb72-22&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; o x y &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; (o, eval env x, eval env y) &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb72-23&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; a, &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; b) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; b)&lt;/span&gt;
&lt;span id=&quot;cb72-24&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;dt&quot;&gt;OTimes&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; a, &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; b) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; b)&lt;/span&gt;
&lt;span id=&quot;cb72-25&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;dt&quot;&gt;OLte&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; a, &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; b) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;&amp;lt;=&lt;/span&gt; b)&lt;/span&gt;
&lt;span id=&quot;cb72-26&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-26&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;dt&quot;&gt;OAnd&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; a, &lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; b) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; b)&lt;/span&gt;
&lt;span id=&quot;cb72-27&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-27&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ERecord&lt;/span&gt; xs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb72-28&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-28&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVRecord&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; mapRec (\(&lt;span class=&quot;dt&quot;&gt;EField&lt;/span&gt; x) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVField&lt;/span&gt; (eval env x)) xs&lt;/span&gt;
&lt;span id=&quot;cb72-29&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-29&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EAccess&lt;/span&gt; e i &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; eval env e &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb72-30&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-30&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVRecord&lt;/span&gt; xs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; indexRec i xs &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb72-31&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-31&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVField&lt;/span&gt; v &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; v&lt;/span&gt;
&lt;span id=&quot;cb72-32&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-32&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EChoice&lt;/span&gt; i x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVSum&lt;/span&gt; i (eval env x)&lt;/span&gt;
&lt;span id=&quot;cb72-33&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-33&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ECase&lt;/span&gt; x hs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; eval env x &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb72-34&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-34&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVSum&lt;/span&gt; i y &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; indexRec i hs &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb72-35&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-35&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EHandler&lt;/span&gt; h &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; eval (&lt;span class=&quot;dt&quot;&gt;EVField&lt;/span&gt; y &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; env) h&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;At least, we are here. A type-safe EDSL where only AST’s that can be validly
evaluated are legal to represent in Haskell. At least, we can embrace the
freedom of not having to carefully construct your terms. You can relax now. The
compiler and the types have your back.&lt;/p&gt;
&lt;p&gt;Even
&lt;code&gt;EVFun :: (EValue a -&amp;gt; EValue b) -&amp;gt; EValue (a :-&amp;gt; b)&lt;/code&gt; has a
total &lt;code&gt;EValue a -&amp;gt; EValue b&lt;/code&gt;, making the closure evaluation also
fully total.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb73&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb73-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb73-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage4.hs#L145-L147&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb73-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb73-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb73-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb73-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;plusThree ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; '[] (&lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb73-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb73-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;plusThree &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb73-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb73-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  eLambda &lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; (eVar &lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;)))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb74&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb74-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb74-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; eval &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt; plusThree &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb74-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb74-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVFun&lt;/span&gt; f &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; f (&lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;) &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb74-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb74-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;print&lt;/span&gt; x&lt;/span&gt;
&lt;span id=&quot;cb74-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb74-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;pretty-printing-scoped-expressions&quot;&gt;Pretty-Printing Scoped
Expressions&lt;/h3&gt;
&lt;p&gt;Now to get to the entire utility of this abstraction: inspecting and
consuming the structure. For our new structure, we took out the string name from
&lt;code&gt;EVar&lt;/code&gt; in lieu of an index. This is intentional, so that we keep the
“responsibility” of storing the string name at the &lt;code&gt;ELambda&lt;/code&gt;
constructor and not have &lt;code&gt;EVar&lt;/code&gt; redundantly store it.&lt;/p&gt;
&lt;p&gt;However, this means that for pretty-printing, we will need to track the
variable names in the environment as we descend into lambdas. This is done very
similar to how it was done in &lt;code&gt;eval&lt;/code&gt;, but instead of tracking and
indexing out the evaluated &lt;code&gt;EValue&lt;/code&gt;s, we track and index out the
string names of each variable instead.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb75&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb75-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb75-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage4.hs#L182-L183&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb75-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb75-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb75-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb75-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;NameField&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Symbol&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt;) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb75-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb75-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;NameField&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; l &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;NameField&lt;/span&gt; (l &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb76&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb76-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb76-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;t &lt;span class=&quot;dt&quot;&gt;NameField&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;hello&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;NameField&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;world&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb76-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb76-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;NameField&lt;/span&gt; [&lt;span class=&quot;st&quot;&gt;&quot;hello&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a, &lt;span class=&quot;st&quot;&gt;&quot;world&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; b]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb77&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb77-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage4.hs#L185-L245&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;ppPrim ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Prim&lt;/span&gt; t &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id=&quot;cb77-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppPrim &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; n &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; PP.pretty n&lt;/span&gt;
&lt;span id=&quot;cb77-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;PBool&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;if&lt;/span&gt; b &lt;span class=&quot;kw&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;true&quot;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;false&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;PString&lt;/span&gt; s &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; PP.pretty (&lt;span class=&quot;fu&quot;&gt;show&lt;/span&gt; s)&lt;/span&gt;
&lt;span id=&quot;cb77-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;ppOp ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Op&lt;/span&gt; a b c &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id=&quot;cb77-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppOp &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;+&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OTimes&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OLte&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&amp;lt;=&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OAnd&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&amp;amp;&amp;amp;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;ppFields ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;NameField&lt;/span&gt; vs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;ExprField&lt;/span&gt; vs) xs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann]&lt;/span&gt;
&lt;span id=&quot;cb77-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppFields _ &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; []&lt;/span&gt;
&lt;span id=&quot;cb77-18&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppFields names (&lt;span class=&quot;dt&quot;&gt;EField&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l x &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; xs) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-19&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  (PP.pretty (symbolVal (&lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l)) &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;=&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr names &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt; x) &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; ppFields names xs&lt;/span&gt;
&lt;span id=&quot;cb77-20&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-21&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;ppHandlers ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;NameField&lt;/span&gt; vs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;ExprHandler&lt;/span&gt; vs b) xs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann]&lt;/span&gt;
&lt;span id=&quot;cb77-22&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppHandlers _ &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; []&lt;/span&gt;
&lt;span id=&quot;cb77-23&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppHandlers names (&lt;span class=&quot;dt&quot;&gt;EHandler&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;n &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l body &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; xs) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-24&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ( PP.pretty (symbolVal (&lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l))&lt;/span&gt;
&lt;span id=&quot;cb77-25&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; PP.pretty (symbolVal (&lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;n))&lt;/span&gt;
&lt;span id=&quot;cb77-26&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-26&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;-&amp;gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-27&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-27&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr (&lt;span class=&quot;dt&quot;&gt;NameField&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;n &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; names) &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt; body&lt;/span&gt;
&lt;span id=&quot;cb77-28&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-28&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  )&lt;/span&gt;
&lt;span id=&quot;cb77-29&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-29&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; ppHandlers names xs&lt;/span&gt;
&lt;span id=&quot;cb77-30&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-30&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-31&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-31&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;ppExpr ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;NameField&lt;/span&gt; vs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Bool&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs t &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id=&quot;cb77-32&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-32&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppExpr names paren &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-33&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-33&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; p &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; ppPrim p&lt;/span&gt;
&lt;span id=&quot;cb77-34&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-34&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; i &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; indexRec i names &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-35&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-35&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;NameField&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;n &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; PP.pretty (symbolVal (&lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;n))&lt;/span&gt;
&lt;span id=&quot;cb77-36&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-36&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ELambda&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;n body &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-37&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-37&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    wrap &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-38&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-38&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;st&quot;&gt;&quot;\\&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; PP.pretty (symbolVal (&lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;n))&lt;/span&gt;
&lt;span id=&quot;cb77-39&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-39&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;-&amp;gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-40&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-40&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr (&lt;span class=&quot;dt&quot;&gt;NameField&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;n &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; names) &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt; body&lt;/span&gt;
&lt;span id=&quot;cb77-41&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-41&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EApply&lt;/span&gt; f x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-42&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-42&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    wrap &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; ppExpr names &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; f &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr names &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; x&lt;/span&gt;
&lt;span id=&quot;cb77-43&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-43&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; o x y &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-44&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-44&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    wrap &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; ppExpr names &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; x &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppOp o &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr names &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; y&lt;/span&gt;
&lt;span id=&quot;cb77-45&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-45&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ERecord&lt;/span&gt; xs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-46&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-46&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    PP.encloseSep &lt;span class=&quot;st&quot;&gt;&quot;{ &quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot; }&quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;, &quot;&lt;/span&gt; (ppFields names xs)&lt;/span&gt;
&lt;span id=&quot;cb77-47&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-47&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EAccess&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l e _ &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-48&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-48&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ppExpr names &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; e &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;.&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; PP.pretty (symbolVal (&lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l))&lt;/span&gt;
&lt;span id=&quot;cb77-49&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-49&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EChoice&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l _ x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-50&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-50&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    wrap &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; PP.pretty (symbolVal (&lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l)) &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr names &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; x&lt;/span&gt;
&lt;span id=&quot;cb77-51&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-51&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ECase&lt;/span&gt; x hs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-52&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-52&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    wrap &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-53&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-53&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      PP.sep&lt;/span&gt;
&lt;span id=&quot;cb77-54&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-54&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        [ &lt;span class=&quot;st&quot;&gt;&quot;case&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr names &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt; x &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;of&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-55&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-55&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        , PP.encloseSep &lt;span class=&quot;st&quot;&gt;&quot;{ &quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot; }&quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;; &quot;&lt;/span&gt; (ppHandlers names hs)&lt;/span&gt;
&lt;span id=&quot;cb77-56&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-56&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        ]&lt;/span&gt;
&lt;span id=&quot;cb77-57&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-57&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-58&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-58&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    wrap&lt;/span&gt;
&lt;span id=&quot;cb77-59&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-59&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; paren &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; PP.parens&lt;/span&gt;
&lt;span id=&quot;cb77-60&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-60&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;otherwise&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;id&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-61&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-61&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-62&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-62&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;prettyExpr ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; '[] t &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id=&quot;cb77-63&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-63&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;prettyExpr &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb78&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb78-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb78-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; prettyExpr fifteen&lt;/span&gt;
&lt;span id=&quot;cb78-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb78-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;(\x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; x &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;) &lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;the-next-step&quot;&gt;The Next Step&lt;/h2&gt;
&lt;p&gt;Well, we set out with a simple goal: an expression language that lives within
Haskell that we can inspect and interrogate within the language, but where it
was impossible to construct (in Haskell) a term that did not type-check (in the
domain language).&lt;/p&gt;
&lt;p&gt;But, honestly, why does it matter that our expression language has to reject
invalid domain-level terms at the Haskell level? Why couldn’t we go the way of
other expression DSLs in Haskell, where we settle with “untyped” terms being
expressible in Haskell, and validated using a separate &lt;code&gt;typeCheck&lt;/code&gt;
function to validate terms at runtime?&lt;/p&gt;
&lt;p&gt;I don’t know. But really, maybe this is another way of taking the old &lt;a href=&quot;https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/&quot;&gt;Parse,
Don’t Validate&lt;/a&gt; adage to the extreme. Why allow yourself to construct invalid
terms of your domain inside Haskell? Why use a “validate” function
(&lt;code&gt;isValid&lt;/code&gt;) when you can just make invalid terms impossible to
construct?&lt;/p&gt;
&lt;p&gt;But…no. There is no other choice. We CANNOT allow invalid domain terms to be
constructible. If we have the ability to do better, we MUST. With great power
comes great responsibility. And if we compromise here, how can we trust
ourselves not to compromise when it really matters?&lt;/p&gt;
&lt;p&gt;One must imagine the stubborn typer happy.&lt;/p&gt;
&lt;p&gt;In Part 2, we’ll use our new EDSL to specify visualizable state machines and
programs within Haskell that are type-checked to be correct, and what it looks
like to actually &lt;em&gt;use&lt;/em&gt; these within Haskell. And in Part 3, we’ll start
“compiling” them to different language targets and different backends, with the
assurance that our generated programs are all synchronized and
self-consistent.&lt;/p&gt;
&lt;h3 id=&quot;a-note-on-ai-coding&quot;&gt;A Note on AI Coding&lt;/h3&gt;
&lt;p&gt;I guess I’m going to have to start mentioning this in every post.
&lt;em&gt;But&lt;/em&gt;, I really do feel like this “extreme type safety” approach is more
critical than ever, in the age of agentic coding and LLM. I’ve been using LLMs
in my daily coding for many months now at this point, and one common pattern
I’ve noticed: when I start with a design with very clear, very strict types,
LLMs excel. They make much fewer errors, and the type system provides more
immediate feedback on their progress, without needing hundreds of defensive
&lt;code&gt;x != null&lt;/code&gt;-style guard pollution.&lt;/p&gt;
&lt;p&gt;Once I can express what I want in the language of extreme “invalid states
unrepresentable” types, LLM agents no longer feel like agents of chaotic
spaghetti extruding unmaintainable code. Instead, it feels like…seeding a
crystal and watching it grow into a beautiful, shimmering lattice. It feels like
the language they yearn to speak. And the more expressive your types, the more
beautiful the crystalline structure in the end.&lt;/p&gt;
&lt;p&gt;Honestly, humans might have problems writing and using this code, but LLMs
definitely don’t, if properly scaffolded! Since early 2026, at least, for me.
We’ll explore a bit more about this once we have more to work with in Part
2.&lt;/p&gt;
&lt;h2 id=&quot;special-thanks&quot;&gt;Special Thanks&lt;/h2&gt;
&lt;p&gt;I am very humbled to be supported by an amazing community, who make it
possible for me to devote time to researching and writing these posts. Very
special thanks to my supporter at the “Amazing” level on &lt;a href=&quot;https://www.patreon.com/justinle/overview&quot;&gt;patreon&lt;/a&gt;, Josh Vera! :)&lt;/p&gt;
&lt;section class=&quot;footnotes footnotes-end-of-document&quot; id=&quot;footnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;&lt;p&gt;Excluding &lt;code&gt;_|_&lt;/code&gt; in Haskell-land (recursion or
&lt;code&gt;undefined&lt;/code&gt;), unfortunately.&lt;a class=&quot;footnote-back&quot; href=&quot;http://feeds.feedburner.com/incodeblog#fnref1&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
	<pubDate>Tue, 07 Jul 2026 17:11:34 +0000</pubDate>
</item>
<item>
	<title>Gabriella Gonzalez: Mechanized type inference for record concatenation</title>
	<guid isPermaLink="true">https://haskellforall.com/2026/07/mechanized-type-inference-for-record-concatenation</guid>
	<link>https://haskellforall.com/2026/07/mechanized-type-inference-for-record-concatenation</link>
	<description>Type inference algorithm for biased record concatenation</description>
	<pubDate>Tue, 07 Jul 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Joey Hess: no LLM code in dependencies</title>
	<guid isPermaLink="true">http://joeyh.name/blog/entry/no_LLM_code_in_dependencies/</guid>
	<link>http://joeyh.name/blog/entry/no_LLM_code_in_dependencies/</link>
	<description>&lt;p&gt;I've spent about 100 hours of work over the past month to make sure
git-annex can build without dependencies that contain LLM generated code.
At least so far.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://git-annex.branchable.com/no_llm_code/&quot;&gt;https://git-annex.branchable.com/no_llm_code/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Needing to review a program's whole dependency tree on an ongoing basis is
apparently what programming has come to?&lt;/p&gt;

&lt;p&gt;I've found some real stinkers. Large LLM generated changes being reverted
in the next release without any explanation. An incoherent 1489 line
commit message with 10,000 lines of changes to a 26,000 LOC code base.
A LLM prompt to copy code from another project that seems to have only
avoided being copyright infringement due to luck.&lt;/p&gt;

&lt;p&gt;I now have additional information about the quality of dependencies
which will surely influence future decisions. As far as I
can see, that's the only positive benefit of this work.&lt;/p&gt;

&lt;p&gt;I realize that I am probably trying to hold back the tide at this point.
That appears to be why Software Freedom Conservancy
&lt;a href=&quot;https://sfconservancy.org/llm-gen-ai/llm-backed-generative-ai-recommendations.html&quot;&gt;punted&lt;/a&gt;,
and I doubt that the FSF will do any better.&lt;/p&gt;

&lt;p&gt;As these dominos fall, I am reconsidering my participation in these
communities. But I continue my work and support my users.&lt;/p&gt;

&lt;p&gt;It may seem easy to prompt a LLM with&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Add fourmolu config and restyled&lt;/p&gt;

&lt;p&gt;neat&lt;/p&gt;

&lt;p&gt;format a module&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;And commit the result and call yourself a 10xer.
But please consider the broader impact of your actions.
(In the above case, that project lost my further collaboration on it.)&lt;/p&gt;</description>
	<pubDate>Thu, 02 Jul 2026 17:58:19 +0000</pubDate>
</item>
<item>
	<title>Philip Wadler: GPCE Distinguished Reviewer</title>
	<guid isPermaLink="false">tag:blogger.com,1999:blog-9757377.post-9137577596938980006</guid>
	<link>https://wadler.blogspot.com/2026/06/blog-post.html</link>
	<description>&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibVH2kqDl5JI_rkgjtNZWCnVDJ5hUDqRCPitRnfBwcuPPW6hwU6KBSpElL8aDgplvurJZaQofUm4xFbklLY-Llz2cDtbNhsk-vdDRXm9GW0PrtxKtHyBIL03xKO5hqdrQUgfr8ofu7c_sJxHlyS8xW1SlZKndwRWss4z8L5IT0QwkkY0URQXDR/s1596/Screenshot%202026-06-30%20at%2010.29.34.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;478&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibVH2kqDl5JI_rkgjtNZWCnVDJ5hUDqRCPitRnfBwcuPPW6hwU6KBSpElL8aDgplvurJZaQofUm4xFbklLY-Llz2cDtbNhsk-vdDRXm9GW0PrtxKtHyBIL03xKO5hqdrQUgfr8ofu7c_sJxHlyS8xW1SlZKndwRWss4z8L5IT0QwkkY0URQXDR/w640-h478/Screenshot%202026-06-30%20at%2010.29.34.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;I am a &lt;a href=&quot;https://2026.ecoop.org/home/gpce-2026#Awards&quot;&gt;Distinguished Reviewer of GPCE 2026&lt;/a&gt;, colocated with ECOOP in Brussels. The award went to two out of a program committee of 33, putting me in the top 6%.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;</description>
	<pubDate>Tue, 30 Jun 2026 20:12:56 +0000</pubDate>
	<author>noreply@blogger.com (Philip Wadler)</author>
</item>
<item>
	<title>Chris Reade: Diagrams for Penrose Tiles</title>
	<guid isPermaLink="false">http://readerunner.wordpress.com/?p=81</guid>
	<link>https://readerunner.wordpress.com/2021/09/13/diagrams-for-penrose-tiles/</link>
	<description>&lt;figure&gt;
&lt;img alt=&quot;Figure: leftFilledSun6&quot; src=&quot;https://readerunner.wordpress.com/wp-content/uploads/2026/06/leftfilledsun6new.png?w=625&quot; /&gt;&lt;figcaption&gt;Figure: leftFilledSun6&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;&lt;em&gt;Update June 2026&lt;/em&gt; This blog is about drawing finite regions of the infinite non-periodic tessellations of Roger Penrose’s kite and dart tiles. It was first written before developing a Haskell package (PenroseKiteDart) now available on Hackage. More info and developments can be seen at the end. I have made small updates to this blog to keep it compatible with later developments (and it is no longer a complete literate Haskell file).&lt;/p&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;As part of a collaboration with Stephen Huggett, working on some mathematical properties of Penrose tilings, I recognised the need for quick renderings of tilings. I thought &lt;em&gt;Haskell diagrams&lt;/em&gt; would be helpful here, and that turned out to be an excellent choice. Two dimensional vectors were well-suited to describing tiling operations and these are included as part of the diagrams package.&lt;/p&gt;
&lt;p&gt;The Haskell below uses the Haskell Diagrams package to draw tilings with kites and darts. It also implements &lt;code&gt;compChoices&lt;/code&gt; and &lt;code&gt;decompPatch&lt;/code&gt; which are used for constructing tilings (explained below).&lt;/p&gt;
&lt;p&gt;Firstly, these 5 lines are needed in Haskell to use the diagrams package:&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span style=&quot;color: green;&quot;&gt;{-# LANGUAGE NoMonomorphismRestriction #-}&lt;/span&gt;
    &lt;span style=&quot;color: green;&quot;&gt;{-# LANGUAGE FlexibleContexts          #-}&lt;/span&gt;
    &lt;span style=&quot;color: green;&quot;&gt;{-# LANGUAGE TypeFamilies              #-}&lt;/span&gt;

    &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;import&lt;/span&gt; &lt;span&gt;Diagrams.Prelude&lt;/span&gt;
    &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;import&lt;/span&gt; &lt;span&gt;Diagrams.Backend.SVG.CmdLine&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and we will also import a module for half tiles (explained later)&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;import&lt;/span&gt; &lt;span&gt;HalfTile&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;legal-tilings&quot;&gt;Legal tilings&lt;/h2&gt;
&lt;p&gt;These are the kite and dart tiles.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Figure: Kite and Dart&quot; src=&quot;https://readerunner.wordpress.com/wp-content/uploads/2021/03/kitedart.png?w=625&quot; /&gt;&lt;figcaption&gt;Figure: Kite and Dart&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The red line marking here on the right hand copies, is purely to illustrate rules about how tiles can be put together for legal (non-periodic) tilings. Obviously edges can only be put together when they have the same length. If all the tiles are marked with red lines as illustrated on the right, the vertices where tiles meet must all have a red line or none must have a red line at that vertex. This prevents us from forming a simple rombus by placing a kite top at the base of a dart and thus enabling periodic tilings.&lt;/p&gt;
&lt;p&gt;All edges are powers of the golden section &lt;img alt=&quot;\phi&quot; class=&quot;latex&quot; src=&quot;https://s0.wp.com/latex.php?latex=%5Cphi&amp;amp;bg=ffffff&amp;amp;fg=444444&amp;amp;s=0&amp;amp;c=20201002&quot; /&gt; which we write as &lt;code&gt;phi&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span&gt;phi&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span&gt;Double&lt;/span&gt;
    &lt;span&gt;phi&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;hs-num&quot;&gt;1.0&lt;/span&gt; &lt;span&gt;+&lt;/span&gt; &lt;span&gt;sqrt&lt;/span&gt; &lt;span class=&quot;hs-num&quot;&gt;5.0&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span&gt;/&lt;/span&gt; &lt;span class=&quot;hs-num&quot;&gt;2.0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So if the shorter edges are unit length, then the longer edges have length &lt;code&gt;phi&lt;/code&gt;. We also have the interesting property of the golden section that &lt;img alt=&quot;phi^2 = phi + 1&quot; class=&quot;latex&quot; src=&quot;https://s0.wp.com/latex.php?latex=phi%5E2+%3D+phi+%2B+1&amp;amp;bg=ffffff&amp;amp;fg=444444&amp;amp;s=0&amp;amp;c=20201002&quot; /&gt; and so&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;1/phi = phi-1&quot; class=&quot;latex&quot; src=&quot;https://s0.wp.com/latex.php?latex=1%2Fphi+%3D+phi-1&amp;amp;bg=ffffff&amp;amp;fg=444444&amp;amp;s=0&amp;amp;c=20201002&quot; /&gt;, &lt;img alt=&quot;phi^3 = 2phi +1&quot; class=&quot;latex&quot; src=&quot;https://s0.wp.com/latex.php?latex=phi%5E3+%3D+2phi+%2B1&amp;amp;bg=ffffff&amp;amp;fg=444444&amp;amp;s=0&amp;amp;c=20201002&quot; /&gt; and &lt;img alt=&quot;1/phi^2 = 2-phi&quot; class=&quot;latex&quot; src=&quot;https://s0.wp.com/latex.php?latex=1%2Fphi%5E2+%3D+2-phi&amp;amp;bg=ffffff&amp;amp;fg=444444&amp;amp;s=0&amp;amp;c=20201002&quot; /&gt;.&lt;/p&gt;
&lt;p&gt;All angles in the figures are multiples of &lt;code&gt;tt&lt;/code&gt; which is &lt;code&gt;36 deg&lt;/code&gt; or &lt;code&gt;1/10 turn&lt;/code&gt;. We use &lt;code&gt;ttangle&lt;/code&gt; to express such angles (e.g 180 degrees is &lt;code&gt;ttangle 5&lt;/code&gt;).&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span&gt;ttangle&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span&gt;Int&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;Angle&lt;/span&gt; &lt;span&gt;Double&lt;/span&gt;
    &lt;span&gt;ttangle&lt;/span&gt; &lt;span&gt;n&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;fromIntegral&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;n&lt;/span&gt; &lt;span&gt;`mod`&lt;/span&gt; &lt;span class=&quot;hs-num&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt;&lt;span&gt;*^&lt;/span&gt;&lt;span&gt;tt&lt;/span&gt;
            &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;where&lt;/span&gt; &lt;span&gt;tt&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hs-num&quot;&gt;1&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span class=&quot;hs-num&quot;&gt;10&lt;/span&gt; &lt;span&gt;@@&lt;/span&gt; &lt;span&gt;turn&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;pieces&quot;&gt;Pieces&lt;/h2&gt;
&lt;p&gt;In order to implement &lt;code&gt;compChoices&lt;/code&gt; and &lt;code&gt;decompPatch&lt;/code&gt;, we need to work with half tiles. We now define these in the separately imported module &lt;code&gt;HalfTile&lt;/code&gt; with constructors for Left Dart, Right Dart, Left Kite, Right Kite&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;data&lt;/span&gt; &lt;span&gt;HalfTile&lt;/span&gt; &lt;span&gt;rep&lt;/span&gt; &lt;span style=&quot;color: green;&quot;&gt;-- defined in HalfTile module&lt;/span&gt;
        &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;LD&lt;/span&gt; &lt;span&gt;rep&lt;/span&gt; 
        &lt;span style=&quot;color: red;&quot;&gt;|&lt;/span&gt; &lt;span&gt;RD&lt;/span&gt; &lt;span&gt;rep&lt;/span&gt;
        &lt;span style=&quot;color: red;&quot;&gt;|&lt;/span&gt; &lt;span&gt;LK&lt;/span&gt; &lt;span&gt;rep&lt;/span&gt;
        &lt;span style=&quot;color: red;&quot;&gt;|&lt;/span&gt; &lt;span&gt;RK&lt;/span&gt; &lt;span&gt;rep&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;where &lt;code&gt;rep&lt;/code&gt; is a type variable allowing for different representations. However, here, we want to use a more specific type which we call &lt;code&gt;Piece&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;type&lt;/span&gt; &lt;span&gt;Piece&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;HalfTile&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;V2&lt;/span&gt; &lt;span&gt;Double&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here the half tiles have a simple 2D vector representation to provide orientation and scale. (&lt;em&gt;Update 2026&lt;/em&gt;: Originally a single vector was used to represent the join edge of a half tile but now we use a list of two vectors instead).&lt;/p&gt;
&lt;p&gt;The list of two two-dimensional vectors represents two edges of the half tile (excluding the &lt;em&gt;join&lt;/em&gt; edge where half tiles come together). The origin for a dart is the tip, and the origin for a kite is the acute angle tip (marked in the figure with a red dot).&lt;/p&gt;
&lt;p&gt;These are the only 4 pieces we use. They are defined oriented with the join along the x axis. In the figure they are rotated 90 degrees so the join edges are vertical (and they have also been labelled).&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span&gt;ldart&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt;&lt;span&gt;rdart&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt;&lt;span&gt;lkite&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt;&lt;span&gt;rkite&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span&gt;Piece&lt;/span&gt;
    &lt;span&gt;ldart&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;LD&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;v'&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt;&lt;span&gt;v&lt;/span&gt; &lt;span&gt;^-^&lt;/span&gt; &lt;span&gt;v'&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;where&lt;/span&gt; &lt;span&gt;v&lt;/span&gt;  &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;unitX&lt;/span&gt;
                                   &lt;span&gt;v'&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;phi&lt;/span&gt;&lt;span&gt;*^&lt;/span&gt;&lt;span&gt;rotate&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ttangle&lt;/span&gt; &lt;span class=&quot;hs-num&quot;&gt;9&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span&gt;v&lt;/span&gt;
    &lt;span&gt;rdart&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;RD&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;v'&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt;&lt;span&gt;v&lt;/span&gt; &lt;span&gt;^-^&lt;/span&gt; &lt;span&gt;v'&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;where&lt;/span&gt; &lt;span&gt;v&lt;/span&gt;  &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;unitX&lt;/span&gt;
                                   &lt;span&gt;v'&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;phi&lt;/span&gt;&lt;span&gt;*^&lt;/span&gt;&lt;span&gt;rotate&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ttangle&lt;/span&gt; &lt;span class=&quot;hs-num&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span&gt;v&lt;/span&gt;
    &lt;span&gt;lkite&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;LK&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;v'&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt;&lt;span&gt;v&lt;/span&gt; &lt;span&gt;^-^&lt;/span&gt; &lt;span&gt;v'&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;where&lt;/span&gt; &lt;span&gt;v&lt;/span&gt;  &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;phi&lt;/span&gt;&lt;span&gt;*^&lt;/span&gt;&lt;span&gt;unitX&lt;/span&gt;
                                   &lt;span&gt;v'&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;rotate&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ttangle&lt;/span&gt; &lt;span class=&quot;hs-num&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span&gt;v&lt;/span&gt;
    &lt;span&gt;rkite&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;RK&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;v'&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt;&lt;span&gt;v&lt;/span&gt; &lt;span&gt;^-^&lt;/span&gt; &lt;span&gt;v'&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;where&lt;/span&gt; &lt;span&gt;v&lt;/span&gt;  &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;phi&lt;/span&gt;&lt;span&gt;*^&lt;/span&gt;&lt;span&gt;unitX&lt;/span&gt;
                                   &lt;span&gt;v'&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;rotate&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ttangle&lt;/span&gt; &lt;span class=&quot;hs-num&quot;&gt;9&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span&gt;v&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;figure&gt;
&lt;img alt=&quot;Figure: Four HalfTile Pieces&quot; src=&quot;https://readerunner.wordpress.com/wp-content/uploads/2026/06/newpiecesfig.png?w=625&quot; /&gt;&lt;figcaption&gt;Figure: Four HalfTile Pieces&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Perhaps confusingly, we regard left and right of a dart differently from left and right of a kite when viewed from the origin. The diagram shows the right dart before the left dart and the left kite before the right kite. Thus in a complete tile, going clockwise round the origin the right dart comes before the left dart, but the left kite comes before the right kite.&lt;/p&gt;
&lt;p&gt;When it comes to drawing pieces, for the simplest case, we just want to draw the two tile edges of each piece (and not the join edge). These are the &lt;code&gt;drawnEdges&lt;/code&gt; of the tile. We can also use the &lt;code&gt;joinVector&lt;/code&gt; of the tile (which is simply the vector sum of the drawn edges) The drawnEdges are ordered starting from the origin of each piece.&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span&gt;drawnEdges&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span&gt;Piece&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;V2&lt;/span&gt; &lt;span&gt;Double&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;
    &lt;span&gt;joinVector&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span&gt;Piece&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;V2&lt;/span&gt; &lt;span&gt;Double&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now drawing lines for the 2 outer edges of a piece we have&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span&gt;drawPiece&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span&gt;Piece&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;Diagram&lt;/span&gt; &lt;span&gt;B&lt;/span&gt;
    &lt;span&gt;drawPiece&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;strokeLine&lt;/span&gt; &lt;span&gt;.&lt;/span&gt; &lt;span&gt;fromOffsets&lt;/span&gt; &lt;span&gt;.&lt;/span&gt; &lt;span&gt;drawnEdges&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or just the join edge&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span&gt;drawJoin&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span&gt;Piece&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;Diagram&lt;/span&gt; &lt;span&gt;B&lt;/span&gt;
    &lt;span&gt;drawJoin&lt;/span&gt; &lt;span&gt;piece&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;strokeLine&lt;/span&gt; &lt;span&gt;$&lt;/span&gt; &lt;span&gt;fromOffsets&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;joinVector&lt;/span&gt; &lt;span&gt;piece&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or drawing all 3 edges round a piece&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span&gt;drawRoundPiece&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span&gt;Piece&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;Diagram&lt;/span&gt; &lt;span&gt;B&lt;/span&gt;
    &lt;span&gt;drawRoundPiece&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;strokeLoop&lt;/span&gt; &lt;span&gt;.&lt;/span&gt; &lt;span&gt;closeLine&lt;/span&gt; &lt;span&gt;.&lt;/span&gt; &lt;span&gt;fromOffsets&lt;/span&gt; &lt;span&gt;.&lt;/span&gt; &lt;span&gt;drawnEdges&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sometimes we want two drawn edges but a faint dashed line for the join&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span&gt;drawjPiece&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span&gt;Piece&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;Diagram&lt;/span&gt; &lt;span&gt;B&lt;/span&gt;
    &lt;span&gt;drawjPiece&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;drawPiece&lt;/span&gt; &lt;span&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;lw&lt;/span&gt; &lt;span&gt;ultraThin&lt;/span&gt; &lt;span&gt;.&lt;/span&gt; &lt;span&gt;joinDashing&lt;/span&gt; &lt;span&gt;.&lt;/span&gt; &lt;span&gt;drawJoin&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt;
                    &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;where&lt;/span&gt; &lt;span&gt;joinDashing&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;normalized&lt;/span&gt; &lt;span class=&quot;hs-num&quot;&gt;0.003&lt;/span&gt;  &lt;span&gt;`atLeast`&lt;/span&gt; &lt;span&gt;output&lt;/span&gt; &lt;span class=&quot;hs-num&quot;&gt;1.0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To fill half tile pieces, we can use &lt;code&gt;fillOnlyPiece&lt;/code&gt; which fills without showing edges of a half tile (by using line width none).&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span&gt;fillOnlyPiece&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span&gt;Colour&lt;/span&gt; &lt;span&gt;Double&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;Piece&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;Diagram&lt;/span&gt; &lt;span&gt;B&lt;/span&gt;
    &lt;span&gt;fillOnlyPiece&lt;/span&gt; &lt;span&gt;col&lt;/span&gt; &lt;span&gt;piece&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;drawRoundPiece&lt;/span&gt; &lt;span&gt;piece&lt;/span&gt; &lt;span&gt;#&lt;/span&gt; &lt;span&gt;fc&lt;/span&gt; &lt;span&gt;col&lt;/span&gt; &lt;span&gt;#&lt;/span&gt; &lt;span&gt;lw&lt;/span&gt; &lt;span&gt;none&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We also use &lt;code&gt;fillPieceDK&lt;/code&gt; which fills darts and kites with given colours and also draws edges using drawPiece.&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span&gt;fillPieceDK&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span&gt;Colour&lt;/span&gt; &lt;span&gt;Double&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;Colour&lt;/span&gt; &lt;span&gt;Double&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;Piece&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;Diagram&lt;/span&gt; &lt;span&gt;B&lt;/span&gt;
    &lt;span&gt;fillPieceDK&lt;/span&gt; &lt;span&gt;dcol&lt;/span&gt; &lt;span&gt;kcol&lt;/span&gt; &lt;span&gt;piece&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;drawPiece&lt;/span&gt; &lt;span&gt;piece&lt;/span&gt; &lt;span&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span&gt;fillOnlyPiece&lt;/span&gt; &lt;span&gt;col&lt;/span&gt; &lt;span&gt;piece&lt;/span&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;where&lt;/span&gt;
            &lt;span&gt;col&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;case&lt;/span&gt; &lt;span&gt;piece&lt;/span&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;of&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;LD&lt;/span&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;dcol&lt;/span&gt;
                                &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;RD&lt;/span&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;dcol&lt;/span&gt;
                                &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;LK&lt;/span&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;kcol&lt;/span&gt;
                                &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;RK&lt;/span&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;kcol&lt;/span&gt;     &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For an alternative fill operation on whole tiles, we calculated a list of the 4 tile edges of a completed half-tile piece clockwise from the origin of the tile. This allows colour filling a whole tile, but it does rely on prior transformations preserving angles as it uses angles in the definition (not shown).&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span&gt;wholeTileEdges&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span&gt;Piece&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;V2&lt;/span&gt; &lt;span&gt;Double&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To fill whole tiles with colours, darts with &lt;code&gt;dcol&lt;/code&gt; and kites with &lt;code&gt;kcol&lt;/code&gt; we can now use &lt;code&gt;leftFillPieceDK&lt;/code&gt;. This uses only the left pieces to identify the whole tile and ignores right pieces so that a tile is not filled twice and uses &lt;code&gt;wholeTileEdges&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span&gt;leftFillPieceDK&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span&gt;Colour&lt;/span&gt; &lt;span&gt;Double&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;Colour&lt;/span&gt; &lt;span&gt;Double&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;Piece&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;Diagram&lt;/span&gt; &lt;span&gt;B&lt;/span&gt;
    &lt;span&gt;leftFillPieceDK&lt;/span&gt; &lt;span&gt;dcol&lt;/span&gt; &lt;span&gt;kcol&lt;/span&gt; &lt;span&gt;c&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;case&lt;/span&gt; &lt;span&gt;c&lt;/span&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;of&lt;/span&gt; 
      &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;LD&lt;/span&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;strokeLoop&lt;/span&gt; &lt;span&gt;$&lt;/span&gt; &lt;span&gt;glueLine&lt;/span&gt; &lt;span&gt;$&lt;/span&gt; &lt;span&gt;fromOffsets&lt;/span&gt; &lt;span&gt;$&lt;/span&gt; &lt;span&gt;wholeTileEdges&lt;/span&gt; &lt;span&gt;c&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt;  &lt;span&gt;#&lt;/span&gt; &lt;span&gt;fc&lt;/span&gt; &lt;span&gt;dcol&lt;/span&gt;
      &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;LK&lt;/span&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;strokeLoop&lt;/span&gt; &lt;span&gt;$&lt;/span&gt; &lt;span&gt;glueLine&lt;/span&gt; &lt;span&gt;$&lt;/span&gt; &lt;span&gt;fromOffsets&lt;/span&gt; &lt;span&gt;$&lt;/span&gt; &lt;span&gt;wholeTileEdges&lt;/span&gt; &lt;span&gt;c&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt;  &lt;span&gt;#&lt;/span&gt; &lt;span&gt;fc&lt;/span&gt; &lt;span&gt;kcol&lt;/span&gt;
      &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;_&lt;/span&gt;      &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;mempty&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By making &lt;code&gt;Pieces&lt;/code&gt; transformable we can reuse generic transform operations. These 4 lines of code are required to do this&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;type&lt;/span&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;instance&lt;/span&gt; &lt;span&gt;N&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;HalfTile&lt;/span&gt; &lt;span&gt;a&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;N&lt;/span&gt; &lt;span&gt;a&lt;/span&gt;
    &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;type&lt;/span&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;instance&lt;/span&gt; &lt;span&gt;V&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;HalfTile&lt;/span&gt; &lt;span&gt;a&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;V&lt;/span&gt; &lt;span&gt;a&lt;/span&gt;
    &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;instance&lt;/span&gt; &lt;span&gt;Transformable&lt;/span&gt; &lt;span&gt;a&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span&gt;Transformable&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;HalfTile&lt;/span&gt; &lt;span&gt;a&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;where&lt;/span&gt;
        &lt;span&gt;transform&lt;/span&gt; &lt;span&gt;t&lt;/span&gt; &lt;span&gt;ht&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;fmap&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;transform&lt;/span&gt; &lt;span&gt;t&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span&gt;ht&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So we can scale and rotate a piece by an angle (positive rotations are in the anticlockwise direction) but we cannote translate until they are located (as Patches).&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span&gt;scale&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span&gt;Double&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;Piece&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;Piece&lt;/span&gt;
    &lt;span&gt;rotate&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span&gt;Angle&lt;/span&gt; &lt;span&gt;Double&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;Piece&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;Piece&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;patches&quot;&gt;Patches&lt;/h2&gt;
&lt;p&gt;A patch is a list of located pieces (each with a 2D point)&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;type&lt;/span&gt; &lt;span&gt;Patch&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;Located&lt;/span&gt; &lt;span&gt;Piece&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To turn a whole patch into a diagram using some function &lt;code&gt;pd&lt;/code&gt; for drawing the pieces, we use &lt;code&gt;drawWith&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;class&lt;/span&gt; &lt;span&gt;Drawable&lt;/span&gt; &lt;span&gt;a&lt;/span&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;where&lt;/span&gt;
        &lt;span&gt;drawWith&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;Piece&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;Diagram&lt;/span&gt; &lt;span&gt;B&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;a&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;Diagram&lt;/span&gt; &lt;span&gt;B&lt;/span&gt;

    &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;instance&lt;/span&gt; &lt;span&gt;Drawable&lt;/span&gt; &lt;span&gt;Patch&lt;/span&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;where&lt;/span&gt;
        &lt;span&gt;drawWith&lt;/span&gt; &lt;span&gt;pd&lt;/span&gt;  &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;position&lt;/span&gt; &lt;span&gt;$&lt;/span&gt; &lt;span&gt;fmap&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;viewLoc&lt;/span&gt; &lt;span&gt;.&lt;/span&gt; &lt;span&gt;mapLoc&lt;/span&gt; &lt;span&gt;pd&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here &lt;code&gt;mapLoc&lt;/code&gt; applies a function to the piece in a located piece – producing a located diagram in this case, and &lt;code&gt;viewLoc&lt;/code&gt; returns the pair of point and diagram from a located diagram. Finally &lt;code&gt;position&lt;/code&gt; forms a single diagram from the list of pairs of points and diagrams. (The use of a class definition here anticipates more instances in later developments).&lt;/p&gt;
&lt;p&gt;We now define the most common special cases:&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span&gt;draw&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span&gt;Drawable&lt;/span&gt; &lt;span&gt;a&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span&gt;a&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;Diagram&lt;/span&gt; &lt;span&gt;B&lt;/span&gt;
    &lt;span&gt;draw&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;drawWith&lt;/span&gt; &lt;span&gt;drawPiece&lt;/span&gt;
    
    &lt;span&gt;drawj&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span&gt;Drawable&lt;/span&gt; &lt;span&gt;a&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span&gt;a&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;Diagram&lt;/span&gt; &lt;span&gt;B&lt;/span&gt;
    &lt;span&gt;drawj&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;drawWith&lt;/span&gt; &lt;span&gt;drawjPiece&lt;/span&gt;

    &lt;span&gt;fillDK&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span&gt;Drawable&lt;/span&gt; &lt;span&gt;a&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span&gt;Colour&lt;/span&gt; &lt;span&gt;Double&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;Colour&lt;/span&gt; &lt;span&gt;Double&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;a&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;Diagram&lt;/span&gt; &lt;span&gt;B&lt;/span&gt;
    &lt;span&gt;fillDK&lt;/span&gt; &lt;span&gt;c1&lt;/span&gt; &lt;span&gt;c2&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;drawWith&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;fillPieceDK&lt;/span&gt; &lt;span&gt;c1&lt;/span&gt; &lt;span&gt;c2&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Patches are automatically inferred to be transformable, so we can also scale a patch, translate a patch by a vector, and rotate a patch by an angle (for example).&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span&gt;scale&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span&gt;Double&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;Patch&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;Patch&lt;/span&gt;
    &lt;span&gt;rotate&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span&gt;Angle&lt;/span&gt; &lt;span&gt;Double&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;Patch&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;Patch&lt;/span&gt;
    &lt;span&gt;translate&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span&gt;V2&lt;/span&gt; &lt;span&gt;Double&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;Patch&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;Patch&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As an aid to creating patches with 5-fold rotational symmetry, we combine 5 copies of a basic patch (rotated by multiples of &lt;code&gt;ttangle 2&lt;/code&gt; successively).&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span&gt;penta&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span&gt;Patch&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;Patch&lt;/span&gt;
    &lt;span&gt;penta&lt;/span&gt; &lt;span&gt;p&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;concatMap&lt;/span&gt; &lt;span&gt;copy&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hs-num&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;hs-num&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; 
              &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;where&lt;/span&gt; &lt;span&gt;copy&lt;/span&gt; &lt;span&gt;n&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;rotate&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ttangle&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;hs-num&quot;&gt;2&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span&gt;p&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This must be used with care to avoid nonsense patches. But two special cases are&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span&gt;sun&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt;&lt;span&gt;star&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span&gt;Patch&lt;/span&gt;         
    &lt;span&gt;sun&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt;  &lt;span&gt;penta&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;rkite&lt;/span&gt; &lt;span&gt;`at`&lt;/span&gt; &lt;span&gt;origin&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;lkite&lt;/span&gt; &lt;span&gt;`at`&lt;/span&gt; &lt;span&gt;origin&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;
    &lt;span&gt;star&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;penta&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;rdart&lt;/span&gt; &lt;span&gt;`at`&lt;/span&gt; &lt;span&gt;origin&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;ldart&lt;/span&gt; &lt;span&gt;`at`&lt;/span&gt; &lt;span&gt;origin&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This figure shows some example patches, drawn with &lt;code&gt;draw&lt;/code&gt; The first is a &lt;code&gt;star&lt;/code&gt; and the second is a &lt;code&gt;sun&lt;/code&gt;.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Figure: Tile Patches&quot; src=&quot;https://readerunner.wordpress.com/wp-content/uploads/2021/03/tilepatches.png?w=625&quot; /&gt;&lt;figcaption&gt;Figure: Tile Patches&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The tools so far for creating patches may seem limited (and do not help with ensuring legal tilings), but there is an even bigger problem.&lt;/p&gt;
&lt;h2 id=&quot;correct-tilings&quot;&gt;Correct Tilings&lt;/h2&gt;
&lt;p&gt;Unfortunately, correct tilings – that is, tilings which can be extended to infinity – are not as simple as just legal tilings. It is not enough to have a legal tiling, because an apparent (legal) choice of placing one tile can have non-local consequences, causing a conflict with a choice made far away in a patch of tiles, resulting in a patch which cannot be extended. This suggests that constructing correct patches is far from trivial.&lt;/p&gt;
&lt;p&gt;The infinite number of possible infinite tilings do have some remarkable properties. Any finite patch from one of them, will occur in all the others (infinitely many times) and within a relatively small radius of any point in an infinite tiling. (For details of this see links at the end).&lt;/p&gt;
&lt;p&gt;This is why we need a different approach to constructing larger patches. There are two significant processes used for creating patches, namely &lt;code&gt;inflate&lt;/code&gt; (also called &lt;em&gt;compose&lt;/em&gt;) and &lt;code&gt;decompose&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To understand these processes, take a look at the following figure.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Figure: Experiment&quot; src=&quot;https://readerunner.wordpress.com/wp-content/uploads/2021/03/experiment.png?w=625&quot; /&gt;&lt;figcaption&gt;Figure: Experiment&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Here the &lt;em&gt;small&lt;/em&gt; pieces have been drawn in an unusual way. The edges have been drawn with dashed lines, but long edges of kites have been emphasised with a solid line and the join edges of darts marked with a red line. From this you may be able to make out a patch of larger scale kites and darts. This is an inflated patch arising from the smaller scale patch. Conversely, the larger kites and darts decompose to the smaller scale ones.&lt;/p&gt;
&lt;h2 id=&quot;decomposition&quot;&gt;Decomposition&lt;/h2&gt;
&lt;p&gt;Since the rule for decomposition is uniquely determined, we can express it as a simple function on patches.&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span&gt;decompPatch&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span&gt;Patch&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;Patch&lt;/span&gt;
    &lt;span&gt;decompPatch&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;concatMap&lt;/span&gt; &lt;span&gt;decompPiece&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;where the function &lt;code&gt;decompPiece&lt;/code&gt; acts on located pieces and produces a list of the smaller located pieces contained in the piece. For example, a larger right dart will produce both a smaller right dart and a smaller left kite. Decomposing a located piece also takes care of the location, scale and rotation of the new pieces. (&lt;em&gt;Revised version 2026 avoiding use of angles&lt;/em&gt;).&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span&gt;decompPiece&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span&gt;Located&lt;/span&gt; &lt;span&gt;Piece&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;Located&lt;/span&gt; &lt;span&gt;Piece&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;
    &lt;span&gt;decompPiece&lt;/span&gt; &lt;span&gt;lp&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;case&lt;/span&gt; &lt;span&gt;viewLoc&lt;/span&gt; &lt;span&gt;lp&lt;/span&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;of&lt;/span&gt;
      &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;RD&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;z1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt;&lt;span&gt;z2&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt; &lt;span&gt;LK&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;s1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;s2&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; &lt;span&gt;`at`&lt;/span&gt; &lt;span&gt;p&lt;/span&gt;
                        &lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;RD&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;z2&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;negate&lt;/span&gt; &lt;span&gt;s2&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; &lt;span&gt;`at`&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;p&lt;/span&gt; &lt;span&gt;.+^&lt;/span&gt; &lt;span&gt;z1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt;
                        &lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; 
        &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;where&lt;/span&gt; &lt;span&gt;s1&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;phi&lt;/span&gt;&lt;span style=&quot;color: green;&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;hs-num&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span&gt;*^&lt;/span&gt; &lt;span&gt;z1&lt;/span&gt;
              &lt;span&gt;s2&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;sumV&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;z1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt;&lt;span&gt;z2&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; &lt;span&gt;^-^&lt;/span&gt; &lt;span&gt;s1&lt;/span&gt;
      &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;LD&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;z1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt;&lt;span&gt;z2&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt; &lt;span&gt;RK&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;s1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;s2&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; &lt;span&gt;`at`&lt;/span&gt; &lt;span&gt;p&lt;/span&gt;
                        &lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;LD&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;z2&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;negate&lt;/span&gt; &lt;span&gt;s2&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; &lt;span&gt;`at`&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;p&lt;/span&gt; &lt;span&gt;.+^&lt;/span&gt; &lt;span&gt;z1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt;
                        &lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;
        &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;where&lt;/span&gt; &lt;span&gt;s1&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;phi&lt;/span&gt;&lt;span style=&quot;color: green;&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;hs-num&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span&gt;*^&lt;/span&gt; &lt;span&gt;z1&lt;/span&gt;
              &lt;span&gt;s2&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;sumV&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;z1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt;&lt;span&gt;z2&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; &lt;span&gt;^-^&lt;/span&gt; &lt;span&gt;s1&lt;/span&gt;
      &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;RK&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;z1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt;&lt;span&gt;z2&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt; &lt;span&gt;RD&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;s1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;s2&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; &lt;span&gt;`at`&lt;/span&gt; &lt;span&gt;p&lt;/span&gt;
                        &lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;LK&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;s4&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;negate&lt;/span&gt; &lt;span&gt;s2&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; &lt;span&gt;`at`&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;p&lt;/span&gt; &lt;span&gt;.+^&lt;/span&gt; &lt;span&gt;z1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt;
                        &lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;RK&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;z2&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;s3&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; &lt;span&gt;`at`&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;p&lt;/span&gt; &lt;span&gt;.+^&lt;/span&gt; &lt;span&gt;z1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt;
                        &lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;
        &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;where&lt;/span&gt; &lt;span&gt;j&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;sumV&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;z1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt;&lt;span&gt;z2&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;
              &lt;span&gt;s1&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;phi&lt;/span&gt;&lt;span style=&quot;color: green;&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;hs-num&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span&gt;*^&lt;/span&gt; &lt;span&gt;j&lt;/span&gt;
              &lt;span&gt;s2&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;hs-num&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: green;&quot;&gt;-&lt;/span&gt;&lt;span&gt;phi&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span&gt;*^&lt;/span&gt; &lt;span&gt;z1&lt;/span&gt; &lt;span&gt;^-^&lt;/span&gt; &lt;span&gt;s1&lt;/span&gt;
              &lt;span&gt;s3&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;phi&lt;/span&gt;&lt;span style=&quot;color: green;&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;hs-num&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span&gt;*^&lt;/span&gt; &lt;span&gt;j&lt;/span&gt;
              &lt;span&gt;s4&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;hs-num&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: green;&quot;&gt;-&lt;/span&gt;&lt;span&gt;phi&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span&gt;*^&lt;/span&gt; &lt;span&gt;z1&lt;/span&gt;
      &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;LK&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;z1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt;&lt;span&gt;z2&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt; &lt;span&gt;LD&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;s1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;s2&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; &lt;span&gt;`at`&lt;/span&gt; &lt;span&gt;p&lt;/span&gt;
                        &lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;RK&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;s4&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;negate&lt;/span&gt; &lt;span&gt;s2&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; &lt;span&gt;`at`&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;p&lt;/span&gt; &lt;span&gt;.+^&lt;/span&gt; &lt;span&gt;z1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt;
                        &lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;LK&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;z2&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;s3&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; &lt;span&gt;`at`&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;p&lt;/span&gt; &lt;span&gt;.+^&lt;/span&gt; &lt;span&gt;z1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt;
                        &lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;
        &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;where&lt;/span&gt; &lt;span&gt;j&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;sumV&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;z1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt;&lt;span&gt;z2&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;
              &lt;span&gt;s1&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;phi&lt;/span&gt;&lt;span style=&quot;color: green;&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;hs-num&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span&gt;*^&lt;/span&gt; &lt;span&gt;j&lt;/span&gt;
              &lt;span&gt;s2&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;hs-num&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: green;&quot;&gt;-&lt;/span&gt;&lt;span&gt;phi&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span&gt;*^&lt;/span&gt; &lt;span&gt;z1&lt;/span&gt; &lt;span&gt;^-^&lt;/span&gt; &lt;span&gt;s1&lt;/span&gt;
              &lt;span&gt;s3&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;phi&lt;/span&gt;&lt;span style=&quot;color: green;&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;hs-num&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span&gt;*^&lt;/span&gt; &lt;span&gt;j&lt;/span&gt;
              &lt;span&gt;s4&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;hs-num&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: green;&quot;&gt;-&lt;/span&gt;&lt;span&gt;phi&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span&gt;*^&lt;/span&gt; &lt;span&gt;z1&lt;/span&gt;
      &lt;span&gt;other&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;error&lt;/span&gt; &lt;span&gt;$&lt;/span&gt; &lt;span style=&quot;color: teal;&quot;&gt;&quot;decompPiece: &quot;&lt;/span&gt; &lt;span&gt;++&lt;/span&gt; &lt;span&gt;show&lt;/span&gt; &lt;span&gt;other&lt;/span&gt; &lt;span&gt;++&lt;/span&gt; &lt;span style=&quot;color: teal;&quot;&gt;&quot;/n&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is illustrated in the following figure for the cases of a right dart and a right kite.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Figure: Decomposition and Composition&quot; src=&quot;https://readerunner.wordpress.com/wp-content/uploads/2026/06/decompexplainnewfig.png?w=625&quot; /&gt;&lt;figcaption&gt;Figure: Decomposition and Composition&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The symmetric diagrams for left pieces are easy to work out from these, so they are not illustrated.&lt;/p&gt;
&lt;p&gt;With the &lt;code&gt;decompPatch&lt;/code&gt; operation we can start with a simple correct patch, and decompose repeatedly to get more and more detailed patches. (Each decomposition scales the tiles down by a factor of &lt;img alt=&quot;1/phi&quot; class=&quot;latex&quot; src=&quot;https://s0.wp.com/latex.php?latex=1%2Fphi&amp;amp;bg=ffffff&amp;amp;fg=444444&amp;amp;s=0&amp;amp;c=20201002&quot; /&gt; but we can rescale at any time.)&lt;/p&gt;
&lt;p&gt;This figure illustrates how each piece decomposes with 4 decomposition steps below each one.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Figure: Four Decompositions of Pieces&quot; src=&quot;https://readerunner.wordpress.com/wp-content/uploads/2026/06/fourdecompsnew.png?w=625&quot; /&gt;&lt;figcaption&gt;Figure: Four Decompositions of Pieces&lt;/figcaption&gt;&lt;/figure&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span&gt;thePieces&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt;  &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;ldart&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;rdart&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;lkite&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;rkite&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;  
    &lt;span&gt;fourDecomps&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;hsep&lt;/span&gt; &lt;span class=&quot;hs-num&quot;&gt;1&lt;/span&gt; &lt;span&gt;$&lt;/span&gt; &lt;span&gt;fmap&lt;/span&gt; &lt;span&gt;decomps&lt;/span&gt; &lt;span&gt;thePieces&lt;/span&gt; &lt;span&gt;#&lt;/span&gt; &lt;span&gt;lw&lt;/span&gt; &lt;span&gt;thin&lt;/span&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;where&lt;/span&gt;
        &lt;span&gt;decomps&lt;/span&gt; &lt;span&gt;pc&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;vsep&lt;/span&gt; &lt;span class=&quot;hs-num&quot;&gt;1&lt;/span&gt; &lt;span&gt;$&lt;/span&gt; &lt;span&gt;fmap&lt;/span&gt; &lt;span&gt;drawj&lt;/span&gt; &lt;span&gt;$&lt;/span&gt; &lt;span&gt;take&lt;/span&gt; &lt;span class=&quot;hs-num&quot;&gt;5&lt;/span&gt; &lt;span&gt;$&lt;/span&gt; &lt;span&gt;decompositionsP&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;pc&lt;/span&gt; &lt;span&gt;`at`&lt;/span&gt; &lt;span&gt;origin&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We have made use of the fact that we can create an infinite list of finer and finer decompositions of any patch, using:&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span&gt;decompositionsP&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span&gt;Patch&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;Patch&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;
    &lt;span&gt;decompositionsP&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;iterate&lt;/span&gt; &lt;span&gt;decompPatch&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We could get the n-fold decomposition of a patch as just the nth item in a list of decompositions.&lt;/p&gt;
&lt;p&gt;For example, here is an infinite list of decomposed versions of &lt;code&gt;sun&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span&gt;suns&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;decompositionsP&lt;/span&gt; &lt;span&gt;sun&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The coloured tiling shown at the beginning is simply 6 decompositions of &lt;code&gt;sun&lt;/code&gt; displayed using &lt;code&gt;leftFillPieceDK&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span&gt;leftFilledSun6&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span&gt;Diagram&lt;/span&gt; &lt;span&gt;B&lt;/span&gt;
    &lt;span&gt;leftFilledSun6&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;drawWith&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;leftFillPieceDK&lt;/span&gt; &lt;span&gt;red&lt;/span&gt; &lt;span&gt;darkviolet&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span&gt;sun6&lt;/span&gt; &lt;span&gt;#&lt;/span&gt; &lt;span&gt;lw&lt;/span&gt; &lt;span&gt;thin&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The earlier figure illustrating larger kites and darts emphasised from the smaller ones is also &lt;code&gt;suns!!6&lt;/code&gt; but this time pieces are drawn with &lt;code&gt;experiment&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span&gt;experimentFig&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;drawWith&lt;/span&gt; &lt;span&gt;experiment&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;suns&lt;/span&gt;&lt;span&gt;!!&lt;/span&gt;&lt;span class=&quot;hs-num&quot;&gt;6&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span&gt;#&lt;/span&gt; &lt;span&gt;lw&lt;/span&gt; &lt;span&gt;thin&lt;/span&gt;

    &lt;span&gt;experiment&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span&gt;Piece&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;Diagram&lt;/span&gt; &lt;span&gt;B&lt;/span&gt;
    &lt;span&gt;experiment&lt;/span&gt; &lt;span&gt;pc&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;emph&lt;/span&gt; &lt;span&gt;pc&lt;/span&gt; &lt;span&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;drawRoundPiece&lt;/span&gt; &lt;span&gt;pc&lt;/span&gt; &lt;span&gt;#&lt;/span&gt; &lt;span&gt;dashingN&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hs-num&quot;&gt;0.002&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;hs-num&quot;&gt;0.002&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;hs-num&quot;&gt;0&lt;/span&gt; &lt;span&gt;#&lt;/span&gt; &lt;span&gt;lw&lt;/span&gt; &lt;span&gt;ultraThin&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt;
      &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;where&lt;/span&gt; &lt;span&gt;emph&lt;/span&gt; &lt;span&gt;pc&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;case&lt;/span&gt; &lt;span&gt;pc&lt;/span&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;of&lt;/span&gt;
              &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;LD&lt;/span&gt; &lt;span&gt;v&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;strokeLine&lt;/span&gt; &lt;span&gt;.&lt;/span&gt; &lt;span&gt;fromOffsets&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; &lt;span&gt;#&lt;/span&gt; &lt;span&gt;lc&lt;/span&gt; &lt;span&gt;red&lt;/span&gt;   &lt;span style=&quot;color: green;&quot;&gt;-- emphasise join edge of darts in red&lt;/span&gt;
              &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;RD&lt;/span&gt; &lt;span&gt;v&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;strokeLine&lt;/span&gt; &lt;span&gt;.&lt;/span&gt; &lt;span&gt;fromOffsets&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; &lt;span&gt;#&lt;/span&gt; &lt;span&gt;lc&lt;/span&gt; &lt;span&gt;red&lt;/span&gt; 
              &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;LK&lt;/span&gt; &lt;span&gt;v&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;strokeLine&lt;/span&gt; &lt;span&gt;.&lt;/span&gt; &lt;span&gt;fromOffsets&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;rotate&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ttangle&lt;/span&gt; &lt;span class=&quot;hs-num&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span&gt;v&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; &lt;span style=&quot;color: green;&quot;&gt;-- emphasise long edge for kites&lt;/span&gt;
              &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;RK&lt;/span&gt; &lt;span&gt;v&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;strokeLine&lt;/span&gt; &lt;span&gt;.&lt;/span&gt; &lt;span&gt;fromOffsets&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;rotate&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ttangle&lt;/span&gt; &lt;span class=&quot;hs-num&quot;&gt;9&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span&gt;v&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;compose-choices&quot;&gt;Compose Choices&lt;/h2&gt;
&lt;p&gt;You might expect composition (also called &lt;em&gt;inflation&lt;/em&gt;) to be a kind of inverse to decomposition, but it is a bit more complicated than that. With our current representation of pieces, we can only compose single pieces. This amounts to embedding the piece into a larger piece that matches how the larger piece decomposes. There is thus a choice at each composition step as to which of several possibilities we select as the larger half-tile. We represent this choice as a list of alternatives. This list should not be confused with a Patch. It only makes sense to select one of the alternatives giving a new single piece.&lt;/p&gt;
&lt;p&gt;The earlier diagram illustrating how decompositions are calculated also shows the two choices for embedding a right dart into either a right kite or a larger right dart. There will be two symmetric choices for a left dart, and three choices for left and right kites.&lt;/p&gt;
&lt;p&gt;Once again we work with located pieces to ensure the resulting larger piece contains the original in its original position in a decomposition. (&lt;em&gt;Revised version 2026 avoiding use of angles&lt;/em&gt;).&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span&gt;compChoices&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span&gt;Located&lt;/span&gt; &lt;span&gt;Piece&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;Located&lt;/span&gt; &lt;span&gt;Piece&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;
    &lt;span&gt;compChoices&lt;/span&gt; &lt;span&gt;lp&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;case&lt;/span&gt; &lt;span&gt;viewLoc&lt;/span&gt; &lt;span&gt;lp&lt;/span&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;of&lt;/span&gt;
      &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;RD&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;s1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt;&lt;span&gt;s2&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt; &lt;span&gt;RD&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;negate&lt;/span&gt; &lt;span&gt;z1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt;&lt;span&gt;s1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; &lt;span&gt;`at`&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;p&lt;/span&gt; &lt;span&gt;.+^&lt;/span&gt; &lt;span&gt;z1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt;
                        &lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;RK&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;z1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;z2&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;  &lt;span&gt;`at`&lt;/span&gt; &lt;span&gt;p&lt;/span&gt;
                        &lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;
          &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;where&lt;/span&gt; &lt;span&gt;z1&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;phi&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span class=&quot;hs-num&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span&gt;*^&lt;/span&gt; &lt;span&gt;sumV&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;s1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt;&lt;span&gt;s2&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;
                &lt;span&gt;z2&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;phi&lt;/span&gt; &lt;span&gt;*^&lt;/span&gt; &lt;span&gt;s1&lt;/span&gt; &lt;span&gt;^-^&lt;/span&gt; &lt;span&gt;z1&lt;/span&gt;
      &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;LD&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;s1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt;&lt;span&gt;s2&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt; &lt;span&gt;LD&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;negate&lt;/span&gt; &lt;span&gt;z1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt;&lt;span&gt;s1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; &lt;span&gt;`at`&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;p&lt;/span&gt; &lt;span&gt;.+^&lt;/span&gt; &lt;span&gt;z1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt;
                        &lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;LK&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;z1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;z2&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;  &lt;span&gt;`at`&lt;/span&gt; &lt;span&gt;p&lt;/span&gt;
                        &lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; 
          &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;where&lt;/span&gt; &lt;span&gt;z1&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;phi&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span class=&quot;hs-num&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span&gt;*^&lt;/span&gt; &lt;span&gt;sumV&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;s1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt;&lt;span&gt;s2&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;
                &lt;span&gt;z2&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;phi&lt;/span&gt; &lt;span&gt;*^&lt;/span&gt; &lt;span&gt;s1&lt;/span&gt; &lt;span&gt;^-^&lt;/span&gt; &lt;span&gt;z1&lt;/span&gt;
      &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;RK&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;s1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt;&lt;span&gt;s2&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt; &lt;span&gt;LD&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;z1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;z2&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;  &lt;span&gt;`at`&lt;/span&gt; &lt;span&gt;p&lt;/span&gt;
                        &lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;LK&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;negate&lt;/span&gt; &lt;span&gt;z1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt;&lt;span&gt;z3&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; &lt;span&gt;`at`&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;p&lt;/span&gt; &lt;span&gt;.+^&lt;/span&gt; &lt;span&gt;z1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; 
                        &lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;RK&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;negate&lt;/span&gt; &lt;span&gt;z&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt;&lt;span&gt;s1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; &lt;span&gt;`at`&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;p&lt;/span&gt; &lt;span&gt;.+^&lt;/span&gt; &lt;span&gt;z&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt;
                        &lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;
          &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;where&lt;/span&gt; &lt;span&gt;z1&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;phi&lt;/span&gt; &lt;span&gt;*^&lt;/span&gt; &lt;span&gt;s1&lt;/span&gt;
                &lt;span&gt;z&lt;/span&gt;  &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;s1&lt;/span&gt; &lt;span&gt;^+^&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;phi&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span class=&quot;hs-num&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span&gt;*^&lt;/span&gt; &lt;span&gt;s2&lt;/span&gt;
                &lt;span&gt;z2&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;sumV&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;s1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt;&lt;span&gt;s2&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; &lt;span&gt;^-^&lt;/span&gt; &lt;span&gt;z1&lt;/span&gt;
                &lt;span&gt;z3&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;z1&lt;/span&gt; &lt;span&gt;^+^&lt;/span&gt; &lt;span&gt;phi&lt;/span&gt; &lt;span&gt;*^&lt;/span&gt; &lt;span&gt;z2&lt;/span&gt;
      &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;LK&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;s1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt;&lt;span&gt;s2&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt; &lt;span&gt;RD&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;z1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;z2&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;  &lt;span&gt;`at`&lt;/span&gt; &lt;span&gt;p&lt;/span&gt;
                        &lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;RK&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;negate&lt;/span&gt; &lt;span&gt;z1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt;&lt;span&gt;z3&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; &lt;span&gt;`at`&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;p&lt;/span&gt; &lt;span&gt;.+^&lt;/span&gt; &lt;span&gt;z1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; 
                        &lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;LK&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;negate&lt;/span&gt; &lt;span&gt;z&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt;&lt;span&gt;s1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; &lt;span&gt;`at`&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;p&lt;/span&gt; &lt;span&gt;.+^&lt;/span&gt; &lt;span&gt;z&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt;
                        &lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;
          &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;where&lt;/span&gt; &lt;span&gt;z1&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;phi&lt;/span&gt; &lt;span&gt;*^&lt;/span&gt; &lt;span&gt;s1&lt;/span&gt;
                &lt;span&gt;z&lt;/span&gt;  &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;s1&lt;/span&gt; &lt;span&gt;^+^&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;phi&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span class=&quot;hs-num&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span&gt;*^&lt;/span&gt; &lt;span&gt;s2&lt;/span&gt;
                &lt;span&gt;z2&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;sumV&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;s1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt;&lt;span&gt;s2&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; &lt;span&gt;^-^&lt;/span&gt; &lt;span&gt;z1&lt;/span&gt;
                &lt;span&gt;z3&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;z1&lt;/span&gt; &lt;span&gt;^+^&lt;/span&gt; &lt;span&gt;phi&lt;/span&gt; &lt;span&gt;*^&lt;/span&gt; &lt;span&gt;z2&lt;/span&gt;
      &lt;span&gt;other&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;error&lt;/span&gt; &lt;span&gt;$&lt;/span&gt; &lt;span style=&quot;color: teal;&quot;&gt;&quot;compChoices: &quot;&lt;/span&gt; &lt;span&gt;++&lt;/span&gt; &lt;span&gt;show&lt;/span&gt; &lt;span&gt;other&lt;/span&gt; &lt;span&gt;++&lt;/span&gt; &lt;span style=&quot;color: teal;&quot;&gt;&quot;/n&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As the result is a list of alternatives, we need to select one to do further inflations. We can express all the alternatives after n steps as &lt;code&gt;compNChoices n&lt;/code&gt; where&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span&gt;compNChoices&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span&gt;Int&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;Located&lt;/span&gt; &lt;span&gt;Piece&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;Located&lt;/span&gt; &lt;span&gt;Piece&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;
    &lt;span&gt;compNChoices&lt;/span&gt; &lt;span class=&quot;hs-num&quot;&gt;0&lt;/span&gt; &lt;span&gt;lp&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;lp&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;
    &lt;span&gt;compNChoices&lt;/span&gt; &lt;span&gt;n&lt;/span&gt; &lt;span&gt;lp&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;do&lt;/span&gt;
        &lt;span&gt;lp'&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span&gt;inflate&lt;/span&gt; &lt;span&gt;lp&lt;/span&gt;
        &lt;span&gt;inflations&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span style=&quot;color: green;&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;hs-num&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span&gt;lp'&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This figure illustrates 5 consecutive choices for composing a left dart to produce a left kite. On the left, the finishing piece is shown with the starting piece embedded, and on the right the 5-fold decomposition of the result is shown.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Figure: Five Composition Choices&quot; src=&quot;https://readerunner.wordpress.com/wp-content/uploads/2021/03/fiveinflate.png?w=625&quot; /&gt;&lt;figcaption&gt;Figure: Five Composition Choices&lt;/figcaption&gt;&lt;/figure&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span&gt;fiveCompChoices&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;hsep&lt;/span&gt; &lt;span class=&quot;hs-num&quot;&gt;1&lt;/span&gt; &lt;span&gt;$&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt; &lt;span&gt;draw&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;ld&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; &lt;span&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span&gt;draw&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;lk'&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;
                               &lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;draw&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;decompositionsP&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;lk'&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; &lt;span&gt;!!&lt;/span&gt;&lt;span class=&quot;hs-num&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt;
                               &lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;where&lt;/span&gt;
      &lt;span&gt;ld&lt;/span&gt;  &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ldart&lt;/span&gt; &lt;span&gt;`at`&lt;/span&gt; &lt;span&gt;origin&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt;
      &lt;span&gt;lk&lt;/span&gt;  &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;compChoices&lt;/span&gt; &lt;span&gt;ld&lt;/span&gt;  &lt;span&gt;!!&lt;/span&gt;&lt;span class=&quot;hs-num&quot;&gt;1&lt;/span&gt;
      &lt;span&gt;rk&lt;/span&gt;  &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;compChoices&lt;/span&gt; &lt;span&gt;lk&lt;/span&gt;  &lt;span&gt;!!&lt;/span&gt;&lt;span class=&quot;hs-num&quot;&gt;1&lt;/span&gt;
      &lt;span&gt;rk'&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;compChoices&lt;/span&gt; &lt;span&gt;rk&lt;/span&gt;  &lt;span&gt;!!&lt;/span&gt;&lt;span class=&quot;hs-num&quot;&gt;2&lt;/span&gt;
      &lt;span&gt;ld'&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;compChoices&lt;/span&gt; &lt;span&gt;rk'&lt;/span&gt; &lt;span&gt;!!&lt;/span&gt;&lt;span class=&quot;hs-num&quot;&gt;0&lt;/span&gt;
      &lt;span&gt;lk'&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;compChoices&lt;/span&gt; &lt;span&gt;ld'&lt;/span&gt; &lt;span&gt;!!&lt;/span&gt;&lt;span class=&quot;hs-num&quot;&gt;1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, at the end of this haskell program we choose which figure to draw as output.&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span&gt;fig&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span&gt;Diagram&lt;/span&gt; &lt;span&gt;B&lt;/span&gt;
    &lt;span&gt;fig&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;leftFilledSun6&lt;/span&gt;

    &lt;span&gt;main&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;mainWith&lt;/span&gt; &lt;span&gt;fig&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s it. But, &lt;em&gt;What about composing whole patches?&lt;/em&gt;, I hear you ask. Unfortunately we need to answer questions like what pieces are adjacent to a piece in a patch and whether there is a corresponding other half for a piece. These cannot be done with our simple vector representations. We would need some form of planar graph representation, which is much more involved. That is another story which can be found in these subsequent blogs.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://readerunner.wordpress.com/2022/01/06/graphs-kites-and-darts/&quot;&gt;Graphs, Kites and Darts&lt;/a&gt; intoduced Tgraphs. This gave more details of implementation and results of early explorations. (The class &lt;code&gt;Forcible&lt;/code&gt; was introduced subsequently).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://readerunner.wordpress.com/2023/04/26/graphs-kites-and-darts-empires-and-superforce/&quot;&gt;Empires and SuperForce&lt;/a&gt; – these new operations were based on observing properties of boundaries of forced Tgraphs.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://readerunner.wordpress.com/2023/09/12/graphs-kites-and-darts-and-theorems/&quot;&gt;Graphs,Kites and Darts and Theorems&lt;/a&gt; established some important results relating &lt;code&gt;force&lt;/code&gt;, &lt;code&gt;compose&lt;/code&gt;, &lt;code&gt;decompose&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://readerunner.wordpress.com/2024/04/08/penrosekitedart-user-guides/&quot;&gt;PenroseKiteDart User Guide&lt;/a&gt; for the PenroseKiteDart package.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Source code for library version of the above code (as part of the PenroseKiteDart package on &lt;a href=&quot;https://hackage.haskell.org/package/PenroseKiteDart&quot;&gt;Hackage&lt;/a&gt;) can be seen at &lt;a href=&quot;https://github.com/chrisreade/PenroseKiteDart&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Many thanks to Stephen Huggett for his inspirations concerning the tilings.&lt;/p&gt;
&lt;h2 id=&quot;further-reading-on-penrose-tilings&quot;&gt;Further reading on Penrose Tilings&lt;/h2&gt;
&lt;p&gt;As well as the Wikipedia entry &lt;a href=&quot;https://en.wikipedia.org/wiki/Penrose_tiling&quot;&gt;Penrose Tilings&lt;/a&gt; I recommend two articles in Scientific American from 2005 by David Austin &lt;a href=&quot;http://www.ams.org/publicoutreach/feature-column/fcarc-penrose&quot;&gt;Penrose Tiles Talk Across Miles&lt;/a&gt; and &lt;a href=&quot;http://www.ams.org/publicoutreach/feature-column/fcarc-ribbons&quot;&gt;Penrose Tilings Tied up in Ribbons&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There is also a very interesting article by Roger Penrose himself: Penrose R &lt;em&gt;Tilings and quasi-crystals; a non-local growth problem?&lt;/em&gt; in Aperiodicity and Order 2, edited by Jarich M, Academic Press, 1989.&lt;/p&gt;
&lt;p&gt;More information about the diagrams package can be found from the home page &lt;a href=&quot;https://diagrams.github.io&quot;&gt;Haskell diagrams&lt;/a&gt;&lt;/p&gt;</description>
	<pubDate>Tue, 30 Jun 2026 10:40:55 +0000</pubDate>
</item>
<item>
	<title>Haskell Interlude: 84: Sylvain Henry</title>
	<guid isPermaLink="false">Buzzsprout-19412450</guid>
	<link></link>
	<description>&lt;p&gt;In this episode of the Haskell Interlude, we are joined by Sylvain Henry, one of the all-time top contributors to GHC. He tells us about his work on GHC, the bignum library, modularization, and the secret to becoming a top contributor!&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
	<pubDate>Mon, 29 Jun 2026 09:00:00 +0000</pubDate>
        <enclosure url="https://www.buzzsprout.com/1817535/episodes/19412450-84-sylvain-henry.mp3" length="37162978" type="audio/mpeg"/>
</item>
<item>
	<title>Jeremy Gibbons: Progress on the book</title>
	<guid isPermaLink="false">http://patternsinfp.wordpress.com/?p=440</guid>
	<link>https://patternsinfp.wordpress.com/2026/06/27/progress-on-the-book/</link>
	<description>&lt;figure class=&quot;wp-block-image size-large&quot;&gt;&lt;a href=&quot;https://patternsinfp.wordpress.com/wp-content/uploads/2026/06/cover-kekub.jpg&quot;&gt;&lt;img alt=&quot;&quot; class=&quot;wp-image-448&quot; height=&quot;1023&quot; src=&quot;https://patternsinfp.wordpress.com/wp-content/uploads/2026/06/cover-kekub.jpg?w=724&quot; width=&quot;724&quot; /&gt;&lt;/a&gt;&lt;/figure&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;So, evidently I failed to fulfill my ambition to blog regularly about the contents of my planned book on Patterns in Functional Programming. But I have been making progress. I had the privilege of another sabbatical 2024-2025, in which I managed to draft the entire book. &lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;It’s in short chapters, following the example set by &lt;a href=&quot;https://www.cs.cornell.edu/~kozen/&quot;&gt;Dexter Kozen&lt;/a&gt; in his lovely books: the idea is that each chapter is roughly one lecture’s worth of material. I had 40 to 50 chapter ideas, and 40 to 50 weeks in my sabbatical, so diligently stuck to one chapter per week for a yearâ€”if this week’s chapter wasn’t finished by the end of the week, it was put aside anyway in order to move on to the next chapter the following week. &lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;That did mean that although I ended the year with a draft of the entire book, it did have many gaps and to-dos remaining. Reality hit at the end of my sabbatical in October 2025, and it has taken me the best part of another year around actual responsibilities to fill in most of the gaps and knock off most of the to-dos. I have also had the benefit of a number of readers (thank you, everyone!), with many helpful comments to implement.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;But I have just yesterday sent a complete polished version to the publisher, Cambridge University Press, for the input of a professional copyeditor. I still have to construct an index, write solutions for the many exercises (which may appear separately from the book itself, in order to keep the length and hence the cost down), and make my own proof-reading pass. I am hoping to complete those tasks and implement the copyeditor’s eventual corrections over the summer, and that the book will finally appear before the end of 2026.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;The image is my mock-up of the cover of the book. The painting is &lt;a href=&quot;https://en.vasarely.hu/artworks/15371/&quot;&gt;Kekub&lt;/a&gt; by &lt;a href=&quot;https://en.wikipedia.org/wiki/Victor_Vasarely&quot;&gt;Victor Vasarely&lt;/a&gt;. There is a &lt;a href=&quot;https://www.cs.ox.ac.uk/people/jeremy.gibbons/publications/pfp-toc-provisional.pdf&quot;&gt;provisional table of contents&lt;/a&gt; on my webpage.&lt;/p&gt;</description>
	<pubDate>Sat, 27 Jun 2026 10:13:08 +0000</pubDate>
</item>
<item>
	<title>Chris Reade: PenroseKiteDart User Guide</title>
	<guid isPermaLink="false">http://readerunner.wordpress.com/?p=251</guid>
	<link>https://readerunner.wordpress.com/2024/04/08/penrosekitedart-user-guides/</link>
	<description>&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;(Updated June 2026 for PenroseKiteDart version 1.10)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;PenroseKiteDart is a Haskell package with tools to experiment with finite tilings of Penrose’s Kites and Darts. It uses the &lt;a href=&quot;https://diagrams.github.io&quot;&gt;Haskell Diagrams&lt;/a&gt; package for drawing tilings. As well as providing drawing tools, this package introduces tile graphs (&lt;code&gt;Tgraphs&lt;/code&gt;) for describing finite tilings. (I would like to thank Stephen Huggett for suggesting planar graphs as a way to reperesent the tilings).&lt;/p&gt;
&lt;p&gt;This document summarises the design and use of the PenroseKiteDart package.&lt;/p&gt;
&lt;p&gt;PenroseKiteDart package is now available on &lt;a href=&quot;https://hackage.haskell.org&quot;&gt;Hackage&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The source files are available on GitHub at &lt;a href=&quot;https://github.com/chrisreade/PenroseKiteDart&quot;&gt;https://github.com/chrisreade/PenroseKiteDart&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There is a small art gallery of examples created with PenroseKiteDart &lt;a href=&quot;https://github.com/chrisreade/PenroseKiteDart/tree/master/ArtGallery&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Index&lt;/strong&gt;&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://readerunner.wordpress.com/2024/04/08/penrosekitedart-user-guides/#1&quot;&gt;About Penrose’s Kites and Darts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://readerunner.wordpress.com/2024/04/08/penrosekitedart-user-guides/#2&quot;&gt;Using the PenroseKiteDart Package&lt;/a&gt; (initial set up).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://readerunner.wordpress.com/2024/04/08/penrosekitedart-user-guides/#3&quot;&gt;Overview of Types and Operations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://readerunner.wordpress.com/2024/04/08/penrosekitedart-user-guides/#4&quot;&gt;Drawing in more detail&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://readerunner.wordpress.com/2024/04/08/penrosekitedart-user-guides/#5&quot;&gt;Forcing in more detail&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://readerunner.wordpress.com/2024/04/08/penrosekitedart-user-guides/#6&quot;&gt;Advanced Operations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://readerunner.wordpress.com/2024/04/08/penrosekitedart-user-guides/#7&quot;&gt;Other Reading&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a name=&quot;1&quot;&gt; &lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;about-penroses-kites-and-darts&quot;&gt;1. About Penroseâ€™s Kites and Darts&lt;/h2&gt;
&lt;h3 id=&quot;the-tiles&quot;&gt;The Tiles&lt;/h3&gt;
&lt;p&gt;In figure 1 we show a dart and a kite. All angles are multiples of &lt;img alt=&quot;36^{\circ}&quot; class=&quot;latex&quot; src=&quot;https://s0.wp.com/latex.php?latex=36%5E%7B%5Ccirc%7D&amp;amp;bg=ffffff&amp;amp;fg=444444&amp;amp;s=0&amp;amp;c=20201002&quot; /&gt; (a tenth of a full turn). If the shorter edges are of length 1, then the longer edges are of length &lt;img alt=&quot;\phi&quot; class=&quot;latex&quot; src=&quot;https://s0.wp.com/latex.php?latex=%5Cphi&amp;amp;bg=ffffff&amp;amp;fg=444444&amp;amp;s=0&amp;amp;c=20201002&quot; /&gt;, where &lt;img alt=&quot;\phi = (1+ \sqrt{5})/ 2&quot; class=&quot;latex&quot; src=&quot;https://s0.wp.com/latex.php?latex=%5Cphi+%3D+%281%2B+%5Csqrt%7B5%7D%29%2F+2&amp;amp;bg=ffffff&amp;amp;fg=444444&amp;amp;s=0&amp;amp;c=20201002&quot; /&gt; is the golden ratio.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Figure 1: The Dart and Kite Tiles&quot; src=&quot;https://readerunner.wordpress.com/wp-content/uploads/2024/04/geomtiles.png?w=625&quot; /&gt;&lt;figcaption&gt;Figure 1: The Dart and Kite Tiles&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h3 id=&quot;aperiodic-infinite-tilings&quot;&gt;Aperiodic Infinite Tilings&lt;/h3&gt;
&lt;p&gt;What is interesting about these tiles is:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;It is possible to tile the entire plane with kites and darts in an aperiodic way.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Such a tiling is non-periodic and does not contain arbitrarily large periodic regions or patches.&lt;/p&gt;
&lt;p&gt;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 &lt;a href=&quot;https://en.wikipedia.org/wiki/Penrose_tiling&quot;&gt;Wikipedia page&lt;/a&gt; for the history of aperiodic tilings)&lt;/p&gt;
&lt;p&gt;This package is entirely concerned with Penrose’s kite and dart tilings also known as P2 tilings.&lt;/p&gt;
&lt;h3 id=&quot;legal-tilings&quot;&gt;Legal Tilings&lt;/h3&gt;
&lt;p&gt;In figure 2 we add a temporary green line marking purely to illustrate a rule for making &lt;em&gt;legal tilings&lt;/em&gt;. The purpose of the rule is to exclude the possibility of periodic tilings.&lt;/p&gt;
&lt;p&gt;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 &lt;em&gt;one&lt;/em&gt; 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.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Figure 2: Marked Dart and Kite&quot; src=&quot;https://readerunner.wordpress.com/wp-content/uploads/2024/04/markedtiles2.png?w=625&quot; /&gt;&lt;figcaption&gt;Figure 2: Marked Dart and Kite&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h3 id=&quot;correct-tilings&quot;&gt;Correct Tilings&lt;/h3&gt;
&lt;p&gt;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 &lt;em&gt;correct&lt;/em&gt; and the others (which are doomed to get stuck) are called &lt;em&gt;incorrect&lt;/em&gt;. This means that decomposition and forcing (described later) become important tools for constructing correct finite tilings.&lt;/p&gt;
&lt;p&gt;&lt;a name=&quot;2&quot;&gt; &lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;using-the-penrosekitedart-package&quot;&gt;2. Using the PenroseKiteDart Package&lt;/h2&gt;
&lt;p&gt;You will need the Haskell Diagrams package (See &lt;a href=&quot;https://diagrams.github.io&quot;&gt;Haskell Diagrams&lt;/a&gt;) 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 &lt;code&gt;Diagrams.Prelude&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;module&lt;/span&gt; &lt;span&gt;Main&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;where&lt;/span&gt;
    
    &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;import&lt;/span&gt; &lt;span&gt;Diagrams.Backend.SVG.CmdLine&lt;/span&gt;
    &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;import&lt;/span&gt; &lt;span&gt;Diagrams.Prelude&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For Penrose’s Kite and Dart tilings, you also need to import the &lt;code&gt;PKD&lt;/code&gt; module and (optionally) the &lt;code&gt;TgraphExamples&lt;/code&gt; module.&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;import&lt;/span&gt; &lt;span&gt;PKD&lt;/span&gt;
    &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;import&lt;/span&gt; &lt;span&gt;TgraphExamples&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then to ouput &lt;code&gt;someExample&lt;/code&gt; figure&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span&gt;fig&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt;&lt;span&gt;Diagram&lt;/span&gt; &lt;span&gt;B&lt;/span&gt;
    &lt;span&gt;fig&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;someExample&lt;/span&gt;

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

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

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

    &lt;span&gt;allCompForce&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;Forcible&lt;/span&gt; &lt;span&gt;a&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;HasGraph&lt;/span&gt; &lt;span&gt;a&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span&gt;a&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;Forced&lt;/span&gt; &lt;span&gt;Tgraph&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; &lt;span style=&quot;color: green;&quot;&gt;-- iterated (compose after force) while not emptyTgraph&lt;/span&gt;
    &lt;span&gt;maxCompForce&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;(&lt;/span&gt;&lt;span&gt;Forcible&lt;/span&gt; &lt;span&gt;a&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;HasGraph&lt;/span&gt; &lt;span&gt;a&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span&gt;a&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;Forced&lt;/span&gt; &lt;span&gt;Tgraph&lt;/span&gt;   &lt;span style=&quot;color: green;&quot;&gt;-- last item in allCompForce (or emptyTgraph)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that &lt;code&gt;BoundaryState&lt;/code&gt;, &lt;code&gt;ForceState&lt;/code&gt; as well as &lt;code&gt;Tgraph&lt;/code&gt; and &lt;code&gt;Forced&lt;/code&gt; versions of these are all instances of class &lt;code&gt;HasGraph&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;tracked-tgraphs&quot;&gt;Tracked Tgraphs&lt;/h3&gt;
&lt;p&gt;The type&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;data&lt;/span&gt; &lt;span&gt;TrackedTgraph&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;=&lt;/span&gt; &lt;span&gt;TrackedTgraph&lt;/span&gt;
       &lt;span style=&quot;color: red;&quot;&gt;{&lt;/span&gt; &lt;span&gt;tgraph&lt;/span&gt;  &lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span&gt;Tgraph&lt;/span&gt;
       &lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;tracked&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;TileFace&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; 
       &lt;span style=&quot;color: red;&quot;&gt;}&lt;/span&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;deriving&lt;/span&gt; &lt;span&gt;Show&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;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 &lt;code&gt;Tgraph&lt;/code&gt; when doing both force operations and decompositions. A list of the sub-collections forms the tracked list associated with the &lt;code&gt;Tgraph&lt;/code&gt;. We make &lt;code&gt;TrackedTgraph&lt;/code&gt; an instance of class &lt;code&gt;Forcible&lt;/code&gt; by having force operations only affect the &lt;code&gt;Tgraph&lt;/code&gt; and not the tracked list. The significant idea is the implementation of&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span&gt;decomposeTracked&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span&gt;TrackedTgraph&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;TrackedTgraph&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Decomposition of a &lt;code&gt;Tgraph&lt;/code&gt; involves introducing a new vertex for each long edge and each kite join. These are then used to construct the decomposed faces. For &lt;code&gt;decomposeTracked&lt;/code&gt; we do the same for the &lt;code&gt;Tgraph&lt;/code&gt;, but when it comes to the tracked collections, we decompose them re-using the same new vertex numbers calculated for the edges in the &lt;code&gt;Tgraph&lt;/code&gt;. This keeps a consistent numbering between the &lt;code&gt;Tgraph&lt;/code&gt; and tracked faces, so each item in the tracked list remains a sub-collection of faces in the &lt;code&gt;Tgraph&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The function&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span&gt;drawTrackedTgraph&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;[&lt;/span&gt;&lt;span&gt;VPatch&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;Diagram&lt;/span&gt; &lt;span&gt;B&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;]&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;TrackedTgraph&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;Diagram&lt;/span&gt; &lt;span&gt;B&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;is used to draw a &lt;code&gt;TrackedTgraph&lt;/code&gt;. It uses a list of functions to draw &lt;code&gt;VPatch&lt;/code&gt;es. The first drawing function is applied to a &lt;code&gt;VPatch&lt;/code&gt; for any untracked faces. Subsequent functions are applied to &lt;code&gt;VPatch&lt;/code&gt;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 &lt;code&gt;VPatch&lt;/code&gt;es used are all restrictions of a single &lt;code&gt;VPatch&lt;/code&gt; for the &lt;code&gt;Tgraph&lt;/code&gt;, so will be consistent in vertex locations. When labels are used, there is also a &lt;code&gt;drawTrackedTgraphRotating&lt;/code&gt; and &lt;code&gt;drawTrackedTgraphAligning&lt;/code&gt; for rotating or aligning the &lt;code&gt;VPatch&lt;/code&gt; prior to applying the drawing functions.&lt;/p&gt;
&lt;p&gt;Note that the result of calculating empires (see &lt;a href=&quot;https://readerunner.wordpress.com/2023/04/26/graphs-kites-and-darts-empires-and-superforce/&quot;&gt;Empires and SuperForce&lt;/a&gt; ) is represented as a &lt;code&gt;TrackedTgraph&lt;/code&gt;. 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 &lt;code&gt;Tgraph&lt;/code&gt; with the common faces as a tracked sub-collection of faces. Hence we have&lt;/p&gt;
&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;    &lt;span&gt;empire1&lt;/span&gt;&lt;span style=&quot;color: red;&quot;&gt;,&lt;/span&gt; &lt;span&gt;empire2&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span&gt;Tgraph&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;TrackedTgraph&lt;/span&gt;
    
    &lt;span&gt;drawEmpire&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;::&lt;/span&gt; &lt;span&gt;TrackedTgraph&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span&gt;Diagram&lt;/span&gt; &lt;span&gt;B&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Figure 10 was also created using &lt;code&gt;TrackedTgraph&lt;/code&gt;s.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Figure 10: Using a TrackedTgraph for drawing&quot; src=&quot;https://readerunner.wordpress.com/wp-content/uploads/2024/04/cover.png?w=625&quot; /&gt;&lt;figcaption&gt;Figure 10: Using a TrackedTgraph for drawing&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;&lt;a name=&quot;7&quot;&gt; &lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;other-reading&quot;&gt;7. Other Reading&lt;/h2&gt;
&lt;p&gt;Previous related blogs are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://readerunner.wordpress.com/2021/03/20/diagrams-for-penrose-tiles/&quot;&gt;Diagrams for Penrose Tiles&lt;/a&gt; – the first blog introduced drawing &lt;code&gt;Piece&lt;/code&gt;s and &lt;code&gt;Patch&lt;/code&gt;es (without using Tgraphs) and provided a version of decomposing for Patches (&lt;code&gt;decompPatch&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://readerunner.wordpress.com/2022/01/06/graphs-kites-and-darts/&quot;&gt;Graphs, Kites and Darts&lt;/a&gt; intoduced Tgraphs. This gave more details of implementation and results of early explorations. (The class &lt;code&gt;Forcible&lt;/code&gt; was introduced subsequently).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://readerunner.wordpress.com/2023/04/26/graphs-kites-and-darts-empires-and-superforce/&quot;&gt;Empires and SuperForce&lt;/a&gt; – these new operations were based on observing properties of boundaries of forced Tgraphs.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://readerunner.wordpress.com/2023/09/12/graphs-kites-and-darts-and-theorems/&quot;&gt;Graphs,Kites and Darts and Theorems&lt;/a&gt; established some important results relating &lt;code&gt;force&lt;/code&gt;, &lt;code&gt;compose&lt;/code&gt;, &lt;code&gt;decompose&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;</description>
	<pubDate>Fri, 26 Jun 2026 11:49:42 +0000</pubDate>
</item>
<item>
	<title>Brent Yorgey: Proving the Fundamental Theorem of Arithmetic in Agda</title>
	<guid isPermaLink="true">http://byorgey.github.io/blog/posts/2026/06/26/FTA.lagda.html</guid>
	<link>http://byorgey.github.io/blog/posts/2026/06/26/FTA.lagda.html</link>
	<description>&lt;h1&gt;Proving the Fundamental Theorem of Arithmetic in Agda&lt;/h1&gt;

&lt;div class=&quot;info&quot;&gt;
  Posted on June 26, 2026
  
  
  &lt;br /&gt;
  Tagged &lt;a href=&quot;https://byorgey.github.io/tag/agda.html&quot; rel=&quot;tag&quot; title=&quot;All pages tagged 'agda'.&quot;&gt;agda&lt;/a&gt;, &lt;a href=&quot;https://byorgey.github.io/tag/arithmetic.html&quot; rel=&quot;tag&quot; title=&quot;All pages tagged 'arithmetic'.&quot;&gt;arithmetic&lt;/a&gt;, &lt;a href=&quot;https://byorgey.github.io/tag/theorem.html&quot; rel=&quot;tag&quot; title=&quot;All pages tagged 'theorem'.&quot;&gt;theorem&lt;/a&gt;, &lt;a href=&quot;https://byorgey.github.io/tag/proof.html&quot; rel=&quot;tag&quot; title=&quot;All pages tagged 'proof'.&quot;&gt;proof&lt;/a&gt;, &lt;a href=&quot;https://byorgey.github.io/tag/Agda.html&quot; rel=&quot;tag&quot; title=&quot;All pages tagged 'Agda'.&quot;&gt;Agda&lt;/a&gt;
  
&lt;/div&gt;

&lt;a href=&quot;https://share.joinmastodon.org/#text=Proving the Fundamental Theorem of Arithmetic in Agda https://byorgey.github.io/blog/posts/2026/06/26/FTA.lagda.html&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Share on &lt;/a&gt;
&lt;section&gt;
&lt;p&gt;&lt;strong&gt;tl;dr&lt;/strong&gt;: This is a fully commentated, from-scratch proof of the
Fundamental Theorem of Arithmetic in
&lt;a href=&quot;https://wiki.portal.chalmers.se/agda/pmwiki.php?n=Main.HomePage&quot;&gt;Agda&lt;/a&gt;,
intended for those who already know a bit of Agda but might benefit
from reading and working through a larger example. See the
Introduction and the &lt;a href=&quot;https://byorgey.github.io/blog/rss#table-of-contents&quot;&gt;Table of Contents&lt;/a&gt; below for more details.&lt;/p&gt;
&lt;section class=&quot;level2&quot; id=&quot;introduction&quot;&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Earlier this spring, I was idly brainstorming potential final projects
for my &lt;a href=&quot;https://hendrix-cs.github.io/csci365/&quot;&gt;Functional Programming&lt;/a&gt;
students. Having just &lt;a href=&quot;http://ozark.hendrix.edu/~yorgey/forest/00EG/index.xml&quot;&gt;taught my Discrete Math students the
Fundamental Theorem of
Arithmetic&lt;/a&gt;, I
wondered whether formalizing&lt;span class=&quot;sidenote-wrapper&quot;&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;sn-0&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;sn-0&quot; type=&quot;checkbox&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;I mean formalizing it &lt;em&gt;from scratch&lt;/em&gt;: of
course, the FTA is &lt;a href=&quot;https://agda.github.io/agda-stdlib/v2.3/Data.Nat.Primality.Factorisation.html&quot;&gt;already in the Agda standard library&lt;/a&gt;. As I later
learned, it was added to the standard library by &lt;a href=&quot;https://github.com/Taneb&quot;&gt;Nathan van Doorn,
aka Taneb&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt; it in
&lt;a href=&quot;https://wiki.portal.chalmers.se/agda/pmwiki.php?n=Main.HomePage&quot;&gt;Agda&lt;/a&gt;
could make a nice project.&lt;/p&gt;
&lt;p&gt;So I decided to spend about an hour trying to prove it in Agda,
to gauge the level of the project. At the end of an hour, I had
learned two things: (1) proving the Fundamental Theorem of Arithmetic is &lt;em&gt;not&lt;/em&gt; an appropriate project for
my students (who had only had a few weeks’ practice with Agda); (2) I
was not going to be able to stop until I finished the proof myself!&lt;/p&gt;
&lt;p&gt;Over the next week or so, I finished the proof completely from
scratch—without using anything from the standard library, and without
looking up any reference material. I based it only on my experience
in Agda, knowledge of the relevant proofs on an informal level, and
Agda techniques I’ve picked up along the way (from &lt;em&gt;e.g.&lt;/em&gt; Conor McBride, Jacques
Carette, colleagues at Penn, and elsewhere).&lt;/p&gt;
&lt;p&gt;I decided to publish the proof, with extra commentary, in the hopes
that it can be useful as an intermediate-level reference. That is,
perhaps you’ve learned some basic Agda (if not, I suggest &lt;a href=&quot;https://agda.readthedocs.io/en/latest/getting-started/a-taste-of-agda.html&quot;&gt;this
tutorial to
start&lt;/a&gt;)
and have some basic familiarity
with the Curry-Howard correspondence, but would benefit from seeing an
example of a fully worked out, medium-sized proof.&lt;span class=&quot;sidenote-wrapper&quot;&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;sn-1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;sn-1&quot; type=&quot;checkbox&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;Another good
source of information along these lines is &lt;a href=&quot;https://jesper.sikanda.be/posts/formalize-all-the-things.html&quot;&gt;this post by Jesper
Cockx&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt; The resulting blog
post is extremely long, but I make no apologies for that—if you want
an entertaining 5-minute read, you should look elsewhere!&lt;/p&gt;
&lt;p&gt;The entire blog post and proof is &lt;a href=&quot;https://github.com/byorgey/blog/blob/main/posts/2026/06/26/FTA.lagda.md&quot;&gt;available as a literate Agda
document&lt;/a&gt;. &lt;strong&gt;Even better, I have also published &lt;a href=&quot;http://ozark.hendrix.edu/~yorgey/pub/FTA-holes.lagda.md&quot;&gt;another version of this
blog post with holes in place of almost all the proofs&lt;/a&gt;.&lt;/strong&gt; For a
maximal learning experience, I suggest downloading it and trying to
fill in the holes yourself as you go along.&lt;/p&gt;
&lt;p&gt;Below is a table of contents. Depending on your background, you may
of course choose to skip some sections. For example, if you have
already had a good deal of practice dealing with basic natural number
arithmetic, equality, and inequality in Agda, you might wish to skip
over those sections.&lt;/p&gt;
&lt;/section&gt;
&lt;section class=&quot;level2&quot; id=&quot;table-of-contents&quot;&gt;
&lt;h2&gt;Table of Contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#half-of-the-fundamental-theorem-of-arithmetic-constructively&quot;&gt;(Half of) The Fundamental Theorem of Arithmetic (Constructively)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#preliminaries&quot;&gt;Preliminaries&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#basic-logic&quot;&gt;Basic logic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#equality&quot;&gt;Equality&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#natural-numbers&quot;&gt;Natural numbers&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#no-confusion&quot;&gt;No confusion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#decidable-equality&quot;&gt;Decidable equality&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#addition&quot;&gt;Addition&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#multiplication&quot;&gt;Multiplication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#inequality&quot;&gt;Inequality&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#relationships-among-equality-and-inequality&quot;&gt;Relationships among equality and inequality&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#arithmetic-and-inequality&quot;&gt;Arithmetic and inequality&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#divisibility-primes-and-composites&quot;&gt;Divisibility, primes, and composites&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#nontrivial-divisors-come-in-pairs&quot;&gt;Nontrivial divisors come in pairs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#division&quot;&gt;Division&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#absolute-difference&quot;&gt;Absolute difference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#quotient-and-remainder-are-unique&quot;&gt;Quotient and remainder are unique&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#the-division-algorithm-take-1&quot;&gt;The division algorithm, take 1&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#construct-the-evidence-you-would-like-to-pattern-match-on&quot;&gt;Construct the evidence you would like to pattern-match on&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#well-founded-induction&quot;&gt;Well-founded induction&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#accessibility&quot;&gt;Accessibility&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#well-founded-induction-defined&quot;&gt;Well-founded induction, defined&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#less-than-is-well-founded&quot;&gt;Less-than is well-founded&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#the-division-algorithm&quot;&gt;The division algorithm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#primality-testing&quot;&gt;Primality testing&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#counting-up&quot;&gt;Counting up&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#primality-testing-by-trial-division&quot;&gt;Primality testing by trial division&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#lists&quot;&gt;Lists&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#the-fundamental-theorem-of-arithmetic&quot;&gt;The Fundamental Theorem of Arithmetic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#further-directions&quot;&gt;Further Directions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section class=&quot;level2&quot; id=&quot;half-of-the-fundamental-theorem-of-arithmetic-constructively&quot;&gt;
&lt;h2&gt;(Half of) The Fundamental Theorem of Arithmetic (Constructively)&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://en.wikipedia.org/wiki/Fundamental_theorem_of_arithmetic&quot;&gt;Fundamental Theorem of
Arithmetic&lt;/a&gt;
(&lt;em&gt;FTA&lt;/em&gt; for short) states that any natural number &lt;span class=&quot;math inline&quot;&gt;\(n \geq 1\)&lt;/span&gt; can be
written as a product of zero or more primes, and moreover that this
product is unique up to permutation.&lt;/p&gt;
&lt;p&gt;For now, we are only going to prove the &lt;em&gt;existence&lt;/em&gt; part (I may write
another blog post with the uniqueness proof later). Since a &lt;em&gt;constructive&lt;/em&gt;
existence proof is really an algorithm for constructing the thing that
is claimed to exist, this can also be seen as a &lt;em&gt;formally verified
factorization program&lt;/em&gt;: put any number in, get a prime factorization
out. Writing a prime factorization program is not hard, of course;
it’s the formal verification part that is interesting!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Stop!&lt;/strong&gt; Before reading on, if you want to get the most out of this tutorial, I
&lt;strong&gt;strongly recommend &lt;a href=&quot;http://ozark.hendrix.edu/~yorgey/pub/FTA-holes.lagda.md&quot;&gt;downloading the version with
holes&lt;/a&gt;&lt;/strong&gt;
and trying to complete as many of the proofs as you can before reading mine!&lt;/p&gt;
&lt;/section&gt;
&lt;section class=&quot;level2&quot; id=&quot;preliminaries&quot;&gt;
&lt;h2&gt;Preliminaries&lt;/h2&gt;
&lt;p&gt;We will often make use of &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;B&lt;/code&gt; to stand for arbitrary
sets/types, so we use a &lt;code&gt;variable&lt;/code&gt; declaration to tell Agda that it
should implicitly quantify them whenever they show up as free
variables. That way we don’t have to write &lt;code&gt;{A B : Set} → ...&lt;/code&gt; all the time.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb1-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;variable&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb1-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  A B &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;level2&quot; id=&quot;basic-logic&quot;&gt;
&lt;h2&gt;Basic logic&lt;/h2&gt;
&lt;p&gt;Since we’re building this completely from scratch, we start with some
types to represent basic logical building blocks (via the
&lt;a href=&quot;https://en.wikipedia.org/wiki/Curry%E2%80%93Howard_correspondence&quot;&gt;Curry-Howard correspondence&lt;/a&gt;). First, the “top” type &lt;code&gt;⊤&lt;/code&gt; to stand for truth, &lt;em&gt;i.e.&lt;/em&gt; a proposition with trivial evidence:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb2-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb2-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; ⊤ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb2-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  tt &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ⊤&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;tt&lt;/code&gt; is declared to be the one and only value of type &lt;code&gt;⊤&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Note that some things we define here—such as &lt;code&gt;⊤&lt;/code&gt;—will have the same
names as they do in the &lt;a href=&quot;https://agda.github.io/agda-stdlib/v2.3/&quot;&gt;Agda standard library&lt;/a&gt;. However, many things
won’t, since I either didn’t know the standard name and made up my
own, or (in a few cases) did know the standard name but didn’t like
it, and made up my own anyway.&lt;/p&gt;
&lt;p&gt;Next, the “bottom” type &lt;code&gt;⊥&lt;/code&gt; with no constructors, representing
falsity, along with a corresponding elimination principle, &lt;code&gt;absurd&lt;/code&gt;. The elimination
principle says that anything follows from &lt;code&gt;⊥&lt;/code&gt; (“&lt;em&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Principle_of_explosion&quot;&gt;ex falso
quodlibet&lt;/a&gt;&lt;/em&gt;”), and is implemented using Agda’s absurd pattern,
written &lt;code&gt;()&lt;/code&gt;. If Agda can tell that there are no possible
constructors which could give rise to a value of a certain type, we
can pattern-match on it with &lt;code&gt;()&lt;/code&gt;, and are absolved of providing a right-hand side for the definition in that case.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb3&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb3-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb3-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; ⊥ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb3-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb3-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;absurd &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ⊥ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; A&lt;/span&gt;
&lt;span id=&quot;cb3-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb3-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;absurd &lt;span class=&quot;ot&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can now define negation as an implication to &lt;code&gt;⊥&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb4&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb4-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb4-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;¬ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb4-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;¬ P &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; P &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ⊥&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Dependent pairs are next: a pair of values where the &lt;em&gt;type&lt;/em&gt; of the
second component can depend on the &lt;em&gt;value&lt;/em&gt; of the first. That is, a value of type &lt;code&gt;Σ A B&lt;/code&gt; is a value &lt;code&gt;a&lt;/code&gt; of type
&lt;code&gt;A&lt;/code&gt; paired with a value of type &lt;code&gt;B a&lt;/code&gt;. Via Curry-Howard, this is used
to represent existential quantification: a (constructive) proof of
&lt;span class=&quot;math inline&quot;&gt;\(\exists a : A.\; B(a)\)&lt;/span&gt; is a value &lt;span class=&quot;math inline&quot;&gt;\(a\)&lt;/span&gt; of type &lt;span class=&quot;math inline&quot;&gt;\(A\)&lt;/span&gt; (the &lt;em&gt;witness&lt;/em&gt;)
paired with a proof that &lt;span class=&quot;math inline&quot;&gt;\(a\)&lt;/span&gt; has property &lt;span class=&quot;math inline&quot;&gt;\(B\)&lt;/span&gt; (&lt;em&gt;i.e.&lt;/em&gt; a value of type &lt;span class=&quot;math inline&quot;&gt;\(B(a)\)&lt;/span&gt;).&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb5&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb5-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb5-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;infixr&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;,&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb5-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; Σ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;A &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;B &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb5-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;,&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;a &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; B a &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Σ A B&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We also define a projection function (we only end up needing &lt;code&gt;fst&lt;/code&gt;;
defining &lt;code&gt;snd&lt;/code&gt; is left as an exercise for the reader&lt;span class=&quot;sidenote-wrapper&quot;&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;sn-2&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;sn-2&quot; type=&quot;checkbox&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;The &lt;em&gt;definition&lt;/em&gt;
of &lt;code&gt;snd&lt;/code&gt; is trivial; writing down its &lt;em&gt;type&lt;/em&gt; is a worthwhile
exercise.&lt;br /&gt;
&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt;), along with a type of non-dependent pairs, corresponding
to logical conjunction (and).&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb6&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb6-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb6-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;fst &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;∀&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;A B&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Σ A B &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; A&lt;/span&gt;
&lt;span id=&quot;cb6-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb6-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;fst &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;a , &lt;span class=&quot;ot&quot;&gt;_)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; a&lt;/span&gt;
&lt;span id=&quot;cb6-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb6-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb6-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;infixr&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;×&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb6-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;×&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;A B &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb6-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;A × B &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; Σ A &lt;span class=&quot;ot&quot;&gt;(λ&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; B&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally, we define a disjoint (tagged) union type corresponding to
logical disjunction (or).&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb7&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb7-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb7-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;infixr&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;⊎&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb7-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;⊎&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;A B &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb7-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  inj₁ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; A ⊎ B&lt;/span&gt;
&lt;span id=&quot;cb7-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb7-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  inj₂ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; B &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; A ⊎ B&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;level2&quot; id=&quot;equality&quot;&gt;
&lt;h2&gt;Equality&lt;/h2&gt;
&lt;p&gt;Next, we write down the standard equality (&lt;em&gt;aka&lt;/em&gt; identity, &lt;em&gt;aka&lt;/em&gt; path) type, with a single
constructor &lt;code&gt;refl&lt;/code&gt; that witnesses when its two arguments are
identical.&lt;span class=&quot;sidenote-wrapper&quot;&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;sn-3&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;sn-3&quot; type=&quot;checkbox&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;It still seems somewhat magical to me that this seemingly
too-simple definition encapsulates everything we want in an equality
relation (well, &lt;a href=&quot;https://martinescardo.github.io/TypeTopology/UnivalenceFromScratch.html&quot;&gt;almost everything&lt;/a&gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt; We also define a convenient
synonym for inequality.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb8&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb8-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb8-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;infix&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≡&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb8-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≡&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;a &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb8-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  refl &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; a ≡ a&lt;/span&gt;
&lt;span id=&quot;cb8-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb8-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb8-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≢&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; A &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb8-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;x ≢ y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ¬ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x ≡ y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Besides reflexivity, equality enjoys various properties that we will
need: symmetry, transitivity, and congruence (&lt;em&gt;i.e.&lt;/em&gt;, we can apply any
function to both sides of an equation).&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb9&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb9-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb9-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sym &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≡ y &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; y ≡ x&lt;/span&gt;
&lt;span id=&quot;cb9-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb9-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sym refl &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb9-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb9-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb9-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;trans &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≡ y &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; y ≡ z &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≡ z&lt;/span&gt;
&lt;span id=&quot;cb9-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb9-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;trans refl y≡z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; y≡z&lt;/span&gt;
&lt;span id=&quot;cb9-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb9-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb9-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;cong &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;f &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; B&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≡ y &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; f x ≡ f y&lt;/span&gt;
&lt;span id=&quot;cb9-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb9-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;cong &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; refl &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Since we will spend a good amount of time reasoning about equality, it
is worthwhile building up some machinery for writing more readable
equality proofs. Instead of writing, say,&lt;/p&gt;
&lt;pre class=&quot;text&quot;&gt;&lt;code&gt;trans p (trans q (trans (sym r) s))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;we will be able to instead write equality proofs like so:&lt;/p&gt;
&lt;pre class=&quot;text&quot;&gt;&lt;code&gt;begin
  v      ≡[ p ⟩≡
  w      ≡[ q ⟩≡
  x      ≡⟨ r ]≡
  y      ≡[ s ⟩≡
  z      ∎&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The intention is that this proof shows &lt;code&gt;v ≡ z&lt;/code&gt;, by first using &lt;code&gt;p&lt;/code&gt; to
show that &lt;code&gt;v ≡ w&lt;/code&gt;, then &lt;code&gt;q&lt;/code&gt; to show &lt;code&gt;w ≡ x&lt;/code&gt;, and so on. This notation
is one of my favorite applications of Agda’s &lt;a href=&quot;https://agda.readthedocs.io/en/latest/language/mixfix-operators.html&quot;&gt;mixfix operator
syntax&lt;/a&gt;,
and has several benefits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We can avoid nested parentheses when chaining uses of transitivity.&lt;/li&gt;
&lt;li&gt;We can automatically apply symmetry by using a left-pointing
instead of right-pointing operator.&lt;/li&gt;
&lt;li&gt;We get to explicitly mention (and have Agda check for us) all the
intermediate values, making it easier to write the proof
incrementally, and much easier for humans to read.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is one of the places where I deliberately chose different
operator names than the standard library, which uses &lt;code&gt;_≡⟨_⟩_&lt;/code&gt; and
&lt;code&gt;_≡⟨_⟨_&lt;/code&gt;. The operator names I decided to use are &lt;a href=&quot;https://personal.cis.strath.ac.uk/conor.mcbride/PolyTest.pdf&quot;&gt;inspired by Conor
McBride&lt;/a&gt;. I just like the way they look better.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb12&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb12-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb12-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;infix&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt; begin&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb12-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;begin&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≡ y &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≡ y&lt;/span&gt;
&lt;span id=&quot;cb12-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb12-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;begin x≡y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; x≡y&lt;/span&gt;
&lt;span id=&quot;cb12-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb12-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb12-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;infixr&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≡[&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;⟩≡&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb12-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≡[&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;⟩≡&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;y z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x ≡ y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y ≡ z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x ≡ z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb12-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ≡[ x≡y ⟩≡ y≡z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; trans x≡y y≡z&lt;/span&gt;
&lt;span id=&quot;cb12-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb12-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-9&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb12-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;infixr&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≡⟨&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;]≡&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-10&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb12-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≡⟨&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;]≡&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;y z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y ≡ x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y ≡ z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x ≡ z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-11&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb12-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ≡⟨ y≡x ]≡ y≡z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sym y≡x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; y≡z&lt;/span&gt;
&lt;span id=&quot;cb12-12&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb12-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-13&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb12-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;infixr&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;∎&lt;/span&gt;
&lt;span id=&quot;cb12-14&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb12-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;∎ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≡ x&lt;/span&gt;
&lt;span id=&quot;cb12-15&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb12-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ∎ &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally, a few &lt;a href=&quot;https://hackage-content.haskell.org/package/base-4.22.0.0/docs/Prelude.html#t:Applicative&quot;&gt;Applicative&lt;/a&gt;-like operators for more conveniently
writing common forms of congruence. For example, instead of writing
&lt;code&gt;cong f x≡y&lt;/code&gt;, we can write &lt;code&gt;f $≡ x≡y&lt;/code&gt;; or to use congruence on both
arguments of a two-place function at once, we can write &lt;code&gt;f $≡ x≡y ≡$≡ z≡w&lt;/code&gt;. (These operators were also inspired by Conor.)&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb13&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb13-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb13-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;infixl&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;$≡&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb13-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;$≡&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;f &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; B&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≡ y &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; f x ≡ f y&lt;/span&gt;
&lt;span id=&quot;cb13-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb13-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;f $≡ x≡y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; cong f x≡y&lt;/span&gt;
&lt;span id=&quot;cb13-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb13-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb13-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;infixl&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≡$&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb13-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≡$&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;f g &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; B&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; f ≡ g &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; f x ≡ g x&lt;/span&gt;
&lt;span id=&quot;cb13-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb13-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;f≡g ≡$ x &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; cong &lt;span class=&quot;ot&quot;&gt;(λ&lt;/span&gt; h &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; h x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; f≡g&lt;/span&gt;
&lt;span id=&quot;cb13-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb13-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-9&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb13-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;infixl&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≡$≡&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-10&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb13-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≡$≡&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;f g &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; B&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; f ≡ g &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≡ y &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; f x ≡ g y&lt;/span&gt;
&lt;span id=&quot;cb13-11&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb13-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;f≡g ≡$≡ x≡y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;f≡g ≡$ &lt;span class=&quot;ot&quot;&gt;_)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(_&lt;/span&gt; $≡ x≡y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;level2&quot; id=&quot;natural-numbers&quot;&gt;
&lt;h2&gt;Natural numbers&lt;/h2&gt;
&lt;p&gt;Of course, we will need a type to represent the natural numbers. We
can also tell Agda that our natural number type should correspond to its
built-in notion of natural numbers, so we can use numeric literals
like &lt;code&gt;2 : ℕ&lt;/code&gt; instead of having to write &lt;code&gt;suc (suc zero)&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb14&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb14-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb14-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb14-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  zero &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;/span&gt;
&lt;span id=&quot;cb14-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb14-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  suc &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ℕ&lt;/span&gt;
&lt;span id=&quot;cb14-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb14-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;pp&quot;&gt;{-# BUILTIN NATURAL ℕ #-}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;section class=&quot;level3&quot; id=&quot;no-confusion&quot;&gt;
&lt;h3&gt;No confusion&lt;/h3&gt;
&lt;p&gt;For our natural number type—and often, for any algebraic data type—we
need to know that the constructors are&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;&lt;em&gt;disjoint&lt;/em&gt;, meaning that different constructors always generate
different values (so it’s a contradiction to have an equality
between values built with different constructors); and&lt;/li&gt;
&lt;li&gt;&lt;em&gt;injective&lt;/em&gt;, meaning that if we have an equality between values built
with the same constructor, we can decompose it into equalities between
the components.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We can prove both of these simultaneously using a property called “no
confusion”. This property and its name is well-known in the
literature; for example, see
&lt;a href=&quot;http://strictlypositive.org/concon.ps.gz&quot;&gt;McBridge&lt;/a&gt; or &lt;a href=&quot;https://link.springer.com/chapter/10.1007/3-540-61780-9_64&quot;&gt;Cornes +
Terrasse&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For natural numbers &lt;code&gt;m&lt;/code&gt; and &lt;code&gt;n&lt;/code&gt;, the type &lt;code&gt;NoConf m n&lt;/code&gt; should be
thought of as the type of evidence that &lt;code&gt;m ≡ n&lt;/code&gt;, based on looking at
the top-level constructors of &lt;code&gt;m&lt;/code&gt; and &lt;code&gt;n&lt;/code&gt;. If &lt;code&gt;m&lt;/code&gt; and &lt;code&gt;n&lt;/code&gt; have different
constructors, then no evidence can possibly show that they are equal,
so &lt;code&gt;NoConf m n = ⊥&lt;/code&gt; in that case. If &lt;code&gt;m&lt;/code&gt; and &lt;code&gt;n&lt;/code&gt; are both zero, then
they are evidently equal, so &lt;code&gt;NoConf 0 0 = ⊤&lt;/code&gt;. Otherwise, if &lt;code&gt;m&lt;/code&gt; and
&lt;code&gt;n&lt;/code&gt; are both successors, &lt;code&gt;NoConf m n&lt;/code&gt; reduces to a proof of equality
between their predecessors.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb15&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb15-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb15-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;NoConf &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb15-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb15-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;NoConf zero zero &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ⊤&lt;/span&gt;
&lt;span id=&quot;cb15-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb15-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;NoConf zero &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ⊥&lt;/span&gt;
&lt;span id=&quot;cb15-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb15-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;NoConf &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc m&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; zero &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ⊥&lt;/span&gt;
&lt;span id=&quot;cb15-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb15-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;NoConf &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc m&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; m ≡ n&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we can prove the no confusion lemma for our natural number type,
which says that &lt;code&gt;NoConf m n&lt;/code&gt; always holds whenever &lt;code&gt;m ≡ n&lt;/code&gt;.
Since &lt;code&gt;m ≡ n&lt;/code&gt;, we only have to deal with the cases when &lt;code&gt;m&lt;/code&gt; and &lt;code&gt;n&lt;/code&gt;
are both zero or both a successor—but this also justifies assigning a
type of &lt;code&gt;⊥&lt;/code&gt; to the cases when the constructors do not match. &lt;code&gt;noConf&lt;/code&gt;
can therefore be used to strip &lt;code&gt;suc&lt;/code&gt; from both sides of an equation,
&lt;em&gt;or&lt;/em&gt; to derive a contradiction when we have an equation between
non-matching constructors.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb16&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb16-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb16-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;noConf &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;m n &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; m ≡ n &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; NoConf m n&lt;/span&gt;
&lt;span id=&quot;cb16-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb16-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;noConf &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;zero&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; refl &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; tt&lt;/span&gt;
&lt;span id=&quot;cb16-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb16-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;noConf &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc m&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; refl &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As an aside, this definition of the no confusion property uses a
technique I like: defining a &lt;em&gt;type&lt;/em&gt; starting with a capital letter,
then defining a &lt;em&gt;term&lt;/em&gt; that returns that type starting with a
lowercase letter. This pattern will come up again later. Sometimes
we define named types in this way just for convenience, say, to be
able to refer to the type multiple times in a concise way; or, as in
the above case, sometimes the type is actually defined via some
nontrivial computation.&lt;/p&gt;
&lt;/section&gt;
&lt;section class=&quot;level3&quot; id=&quot;decidable-equality&quot;&gt;
&lt;h3&gt;Decidable equality&lt;/h3&gt;
&lt;p&gt;We can now show how to decide equality of natural numbers. We first
define a simple type representing decidability in general: &lt;code&gt;Dec P&lt;/code&gt; represents
either a proof of &lt;code&gt;P&lt;/code&gt;, or a proof of &lt;code&gt;¬ P&lt;/code&gt;.&lt;span class=&quot;sidenote-wrapper&quot;&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;sn-4&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;sn-4&quot; type=&quot;checkbox&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;You may be aware that the
&lt;a href=&quot;https://en.wikipedia.org/wiki/Law_of_excluded_middle&quot;&gt;law of excluded middle&lt;/a&gt;, which
says that &lt;span class=&quot;math inline&quot;&gt;\(P \lor \neg P\)&lt;/span&gt; for all propositions &lt;span class=&quot;math inline&quot;&gt;\(P\)&lt;/span&gt;, is rejected in constructive logic. However, even
though &lt;span class=&quot;math inline&quot;&gt;\(P \lor \neg P\)&lt;/span&gt; does not hold for &lt;em&gt;all&lt;/em&gt; &lt;span class=&quot;math inline&quot;&gt;\(P\)&lt;/span&gt;, it can still hold
for certain specific propositions. Propositions &lt;span class=&quot;math inline&quot;&gt;\(P\)&lt;/span&gt; for which &lt;span class=&quot;math inline&quot;&gt;\(P \lor
\neg P\)&lt;/span&gt; holds constructively are called &lt;em&gt;decidable&lt;/em&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt; (The &lt;a href=&quot;https://agda.github.io/agda-stdlib/v2.3/Relation.Nullary.Decidable.Core.html#1966&quot;&gt;standard library
version is much more sophisticated&lt;/a&gt;, but this simple version will do
just fine.)&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb17&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb17-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb17-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; Dec &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;P &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb17-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  yes &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; P &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Dec P&lt;/span&gt;
&lt;span id=&quot;cb17-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb17-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  no &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ¬ P &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Dec P&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can then prove that for any natural numbers &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt;, we can decide
whether &lt;code&gt;x ≡ y&lt;/code&gt;. Notice the several different uses of the no
confusion lemma: two to handle impossible situations, and one to strip
&lt;code&gt;suc&lt;/code&gt; off both sides of an equality.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb18&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb18-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb18-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≟&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Dec &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x ≡ y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb18-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb18-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;zero ≟ zero &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; yes refl&lt;/span&gt;
&lt;span id=&quot;cb18-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb18-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;zero ≟ suc y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; no noConf&lt;/span&gt;
&lt;span id=&quot;cb18-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb18-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;suc x ≟ zero &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; no noConf&lt;/span&gt;
&lt;span id=&quot;cb18-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb18-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;suc x ≟ suc y &lt;span class=&quot;kw&quot;&gt;with&lt;/span&gt; x ≟ y&lt;/span&gt;
&lt;span id=&quot;cb18-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb18-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;|&lt;/span&gt; yes x≡y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; yes &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc $≡ x≡y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb18-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb18-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;|&lt;/span&gt; no x≢y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; no &lt;span class=&quot;ot&quot;&gt;(λ&lt;/span&gt; sx≡sy &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x≢y &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;noConf sx≡sy&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section class=&quot;level2&quot; id=&quot;addition&quot;&gt;
&lt;h2&gt;Addition&lt;/h2&gt;
&lt;p&gt;We next turn to defining addition (by pattern-matching on the
left-hand argument), along with several properties of
addition we will need: zero is a right identity for addition; we can
pull out a &lt;code&gt;suc&lt;/code&gt; from the right-hand argument; and addition is
commutative, associative, and left-cancellable.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb19&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb19-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;infixl&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;+&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;+&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ℕ&lt;/span&gt;
&lt;span id=&quot;cb19-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;zero + y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; y&lt;/span&gt;
&lt;span id=&quot;cb19-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;suc x + y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; suc &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x + y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;+0 &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n + &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; ≡ n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;zero +0 &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb19-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; +0 &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; suc $≡ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n +0&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-9&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-10&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;+suc&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x + suc y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; ≡ suc &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x + y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-11&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;zero +suc y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb19-12&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; +suc y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; suc $≡ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x +suc y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-13&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-14&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;+-comm &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x + y ≡ y + x&lt;/span&gt;
&lt;span id=&quot;cb19-15&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;+-comm zero y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sym &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y +0&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-16&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;+-comm &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc $≡ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;+-comm x y&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sym &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y +suc x&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-17&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-18&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;+-assoc &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x y z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x + y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; + z ≡ x + &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y + z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-19&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;+-assoc zero y z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb19-20&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;+-assoc &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; y z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; suc $≡ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;+-assoc x y z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-21&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-22&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;+-cancelˡ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x y z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x + y ≡ x + z &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; y ≡ z&lt;/span&gt;
&lt;span id=&quot;cb19-23&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;+-cancelˡ zero y z x+y≡x+z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; x+y≡x+z&lt;/span&gt;
&lt;span id=&quot;cb19-24&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;+-cancelˡ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; y z x+y≡x+z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; +-cancelˡ x y z &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;noConf x+y≡x+z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;level2&quot; id=&quot;multiplication&quot;&gt;
&lt;h2&gt;Multiplication&lt;/h2&gt;
&lt;p&gt;Multiplication is next: we start by defining the multiplication
operation (by pattern-matching on the left-hand argument) and proving
a few lemmas about multiplying by known arguments on the right. The
proof of &lt;code&gt;*suc&lt;/code&gt; is the most involved proof we have seen yet, but it
ultimately just comes down to algebra, and we can make good use of our
notation for writing chained equality proofs.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb20&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb20-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;infixl&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;*&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;*&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ℕ&lt;/span&gt;
&lt;span id=&quot;cb20-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;zero * y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; zero&lt;/span&gt;
&lt;span id=&quot;cb20-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;suc x * y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; y + x * y&lt;/span&gt;
&lt;span id=&quot;cb20-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;*0 &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n * &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; ≡ &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;zero *0 &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb20-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; *0 &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; n *0&lt;/span&gt;
&lt;span id=&quot;cb20-9&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-10&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;*1 &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n * &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt; ≡ n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-11&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; *1 &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb20-12&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; *1 &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; suc $≡ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n *1&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-13&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-14&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;*suc&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x * suc y ≡ x + x * y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-15&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;zero *suc y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb20-16&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; *suc y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; suc $≡ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-17&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  begin&lt;/span&gt;
&lt;span id=&quot;cb20-18&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  y + x * suc y               ≡[ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y +&lt;span class=&quot;ot&quot;&gt;_)&lt;/span&gt; $≡ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x *suc y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb20-19&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  y + &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x + x * y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;             ≡⟨ +-assoc y x &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x * y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; ]≡&lt;/span&gt;
&lt;span id=&quot;cb20-20&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y + x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; + x * y             ≡[ &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;+&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; $≡ +-comm y x ≡$ x * y ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb20-21&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x + y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; + x * y             ≡[ +-assoc x &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb20-22&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  x + &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y + x * y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;             ∎&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We prove some standard properties of multiplication: commutativity,
distributivity over addition, associativity. Again, the proofs mostly
consist of a whole bunch of algebra, using the special notation for
building chained equality proofs.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb21&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb21-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*-comm &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x * y ≡ y * x&lt;/span&gt;
&lt;span id=&quot;cb21-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*-comm zero y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sym &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y *0&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*-comm &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; begin&lt;/span&gt;
&lt;span id=&quot;cb21-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  y + x * y                   ≡[ y +&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; $≡ *-comm x y ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb21-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  y + y * x                   ≡⟨ y *suc x ]≡&lt;/span&gt;
&lt;span id=&quot;cb21-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  y * suc x                   ∎&lt;/span&gt;
&lt;span id=&quot;cb21-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*-distribˡ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x y z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x * &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y + z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; ≡ x * y + x * z&lt;/span&gt;
&lt;span id=&quot;cb21-9&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*-distribˡ zero y z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb21-10&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*-distribˡ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; y z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; begin&lt;/span&gt;
&lt;span id=&quot;cb21-11&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  y + z + x * &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y + z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;         ≡[ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y + z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; +&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; $≡ *-distribˡ x y z ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb21-12&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  y + z + &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x * y + x * z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;     ≡[ +-assoc y &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb21-13&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  y + &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;z + &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x * y + x * z&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt;   ≡⟨ y +&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; $≡ +-assoc z &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ]≡&lt;/span&gt;
&lt;span id=&quot;cb21-14&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  y + &lt;span class=&quot;ot&quot;&gt;((&lt;/span&gt;z + x * y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; + x * z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;   ≡[ y +&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; $≡ &lt;span class=&quot;ot&quot;&gt;(_&lt;/span&gt;+&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; $≡ +-comm z &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ≡$ x * z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb21-15&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  y + &lt;span class=&quot;ot&quot;&gt;((&lt;/span&gt;x * y + z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; + x * z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;   ≡[ y +&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; $≡ +-assoc &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x * y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb21-16&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  y + &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x * y + &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;z + x * z&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt;   ≡⟨ +-assoc y &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ]≡&lt;/span&gt;
&lt;span id=&quot;cb21-17&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  y + x * y + &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;z + x * z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;     ∎&lt;/span&gt;
&lt;span id=&quot;cb21-18&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-19&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*-distribʳ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x y z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x + y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; * z ≡ x * z + y * z&lt;/span&gt;
&lt;span id=&quot;cb21-20&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*-distribʳ x y z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; begin&lt;/span&gt;
&lt;span id=&quot;cb21-21&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x + y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; * z                 ≡[ *-comm &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x + y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb21-22&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  z * &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x + y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;                 ≡[ *-distribˡ z &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb21-23&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  z * x + z * y               ≡[ &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;+&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; $≡ *-comm z &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ≡$≡ *-comm z &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb21-24&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  x * z + y * z               ∎&lt;/span&gt;
&lt;span id=&quot;cb21-25&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-26&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-26&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*-assoc &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x y z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x * y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; * z ≡ x * &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y * z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-27&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-27&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*-assoc zero y z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb21-28&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-28&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*-assoc &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; y z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; begin&lt;/span&gt;
&lt;span id=&quot;cb21-29&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-29&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y + x * y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; * z             ≡[ *-distribʳ y &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb21-30&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-30&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  y * z + &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x * y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; * z         ≡[ y * z +&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; $≡ *-assoc x &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb21-31&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-31&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  y * z + x * &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y * z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;         ∎&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally, we prove that multiplication is left-cancellative. This
proof is somewhat tricky—in the case that &lt;code&gt;x&lt;/code&gt;, &lt;code&gt;y&lt;/code&gt;, and &lt;code&gt;z&lt;/code&gt; are all
successors, we need to use the induction hypothesis (&lt;em&gt;i.e.&lt;/em&gt; a
recursive call to &lt;code&gt;*-cancelˡ&lt;/code&gt;) on &lt;code&gt;x&lt;/code&gt; and the
predecessors of &lt;code&gt;y&lt;/code&gt; and &lt;code&gt;z&lt;/code&gt;, using the fact that + is
left-cancellative to construct the required input equality.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb22&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb22-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb22-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*-cancelˡ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x y z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; ≢ x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x * y ≡ x * z &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; y ≡ z&lt;/span&gt;
&lt;span id=&quot;cb22-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb22-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*-cancelˡ zero y z x≢0 xy≡xz &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; absurd &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x≢0 refl&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb22-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb22-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*-cancelˡ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; zero zero x≢0 xy≡xz &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb22-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb22-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*-cancelˡ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; zero &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; x≢0 xy≡xz &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; absurd &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;noConf &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sym &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x *0&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt; xy≡xz&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb22-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb22-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*-cancelˡ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; zero x≢0 xy≡xz &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; absurd &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;noConf &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;trans xy≡xz &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x *0&lt;span class=&quot;ot&quot;&gt;)))&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb22-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb22-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*-cancelˡ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; x≢0 xy≡xz &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; suc $≡&lt;/span&gt;
&lt;span id=&quot;cb22-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb22-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt; *-cancelˡ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; y z x≢0&lt;/span&gt;
&lt;span id=&quot;cb22-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb22-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt; +-cancelˡ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x * y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x * z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb22-9&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb22-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt; begin&lt;/span&gt;
&lt;span id=&quot;cb22-10&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb22-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          suc x + suc x * y   ≡⟨ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; *suc y ]≡&lt;/span&gt;
&lt;span id=&quot;cb22-11&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb22-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          suc x * suc y       ≡[ xy≡xz ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb22-12&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb22-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          suc x * suc z       ≡[ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; *suc z ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb22-13&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb22-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          suc x + suc x * z   ∎&lt;/span&gt;
&lt;span id=&quot;cb22-14&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb22-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb22-15&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb22-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb22-16&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb22-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;level2&quot; id=&quot;inequality&quot;&gt;
&lt;h2&gt;Inequality&lt;/h2&gt;
&lt;p&gt;Next, we give a standard definition of the “less than or equal to”
relation on natural numbers. Note that the structure of a proof of &lt;span class=&quot;math inline&quot;&gt;\(x \leq
y\)&lt;/span&gt; exactly matches the structure of &lt;span class=&quot;math inline&quot;&gt;\(x\)&lt;/span&gt; itself.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb23&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb23-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb23-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≤&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb23-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb23-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  zle &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;n &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; zero ≤ n&lt;/span&gt;
&lt;span id=&quot;cb23-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb23-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  sle &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;m n &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; m ≤ n &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; suc m ≤ suc n&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We also prove some standard properties of &lt;span class=&quot;math inline&quot;&gt;\(\leq\)&lt;/span&gt;: it is reflexive and
transitive, and is related to &lt;code&gt;suc&lt;/code&gt; in various ways.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb24&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb24-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb24-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤-refl &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;m &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; m ≤ m&lt;/span&gt;
&lt;span id=&quot;cb24-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb24-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤-refl &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;zero&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; zle&lt;/span&gt;
&lt;span id=&quot;cb24-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb24-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤-refl &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc m&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sle ≤-refl&lt;/span&gt;
&lt;span id=&quot;cb24-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb24-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb24-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤-trans &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≤ y &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; y ≤ z &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≤ z&lt;/span&gt;
&lt;span id=&quot;cb24-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb24-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤-trans zle y≤z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; zle&lt;/span&gt;
&lt;span id=&quot;cb24-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb24-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤-trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle x≤y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle y≤z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sle &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;≤-trans x≤y y≤z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb24-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-9&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb24-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤-sucr &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;m n &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; m ≤ n &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; m ≤ suc n&lt;/span&gt;
&lt;span id=&quot;cb24-10&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb24-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤-sucr zle &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; zle&lt;/span&gt;
&lt;span id=&quot;cb24-11&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb24-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤-sucr &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle m≤n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sle &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;≤-sucr m≤n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-12&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb24-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-13&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb24-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤-sucl &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;m n &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; suc m ≤ n &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; m ≤ n&lt;/span&gt;
&lt;span id=&quot;cb24-14&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb24-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤-sucl &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle sm≤n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ≤-sucr sm≤n&lt;/span&gt;
&lt;span id=&quot;cb24-15&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb24-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-16&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb24-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤-pred &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; suc x ≤ suc y &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≤ y&lt;/span&gt;
&lt;span id=&quot;cb24-17&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb24-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤-pred &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle sx≤sy&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sx≤sy&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For convenience, we define &lt;span class=&quot;math inline&quot;&gt;\(&amp;lt;\)&lt;/span&gt; in terms of &lt;span class=&quot;math inline&quot;&gt;\(\leq\)&lt;/span&gt;, and prove a few
properties: any number is less than its successor, and &lt;span class=&quot;math inline&quot;&gt;\(&amp;lt;\)&lt;/span&gt; is
transitive and non-reflexive.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb25&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb25-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb25-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&amp;lt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb25-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb25-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;x &amp;lt; y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; suc x ≤ y&lt;/span&gt;
&lt;span id=&quot;cb25-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb25-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb25-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb25-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&amp;lt;suc &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x &amp;lt; suc x&lt;/span&gt;
&lt;span id=&quot;cb25-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb25-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&amp;lt;suc zero &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sle zle&lt;/span&gt;
&lt;span id=&quot;cb25-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb25-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&amp;lt;suc &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sle &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x &amp;lt;suc&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb25-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb25-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb25-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb25-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&amp;lt;-trans &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x &amp;lt; y &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; y &amp;lt; z &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x &amp;lt; z&lt;/span&gt;
&lt;span id=&quot;cb25-9&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb25-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&amp;lt;-trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle x&amp;lt;y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle y&amp;lt;z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ≤-trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle x&amp;lt;y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;≤-sucr y&amp;lt;z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb25-10&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb25-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb25-11&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb25-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;x≮x &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ¬ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x &amp;lt; x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb25-12&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb25-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;x≮x &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;zero&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb25-13&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb25-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;x≮x &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle x&amp;lt;x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x≮x x&amp;lt;x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;section class=&quot;level3&quot; id=&quot;relationships-among-equality-and-inequality&quot;&gt;
&lt;h3&gt;Relationships among equality and inequality&lt;/h3&gt;
&lt;p&gt;Of course, equality, &lt;span class=&quot;math inline&quot;&gt;\(&amp;lt;\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(\leq\)&lt;/span&gt; have various relationships that we
will need. First, equality implies &lt;span class=&quot;math inline&quot;&gt;\(\leq\)&lt;/span&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb26&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb26-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb26-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≡→≤ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≡ y &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≤ y&lt;/span&gt;
&lt;span id=&quot;cb26-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb26-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≡→≤ refl &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ≤-refl&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next, &lt;span class=&quot;math inline&quot;&gt;\(x &amp;lt; y\)&lt;/span&gt; implies that &lt;span class=&quot;math inline&quot;&gt;\(x\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(y\)&lt;/span&gt; are &lt;em&gt;not&lt;/em&gt; related by &lt;span class=&quot;math inline&quot;&gt;\(\equiv\)&lt;/span&gt; or
&lt;span class=&quot;math inline&quot;&gt;\(\geq\)&lt;/span&gt;. The first lemma in particular—that &lt;span class=&quot;math inline&quot;&gt;\(&amp;lt;\)&lt;/span&gt; implies &lt;span class=&quot;math inline&quot;&gt;\(\not\equiv\)&lt;/span&gt;—gets used quite a bit. Note that it can be read in two equivalent
ways: on the surface, it is a way to turn a proof of &lt;span class=&quot;math inline&quot;&gt;\(x &amp;lt; y\)&lt;/span&gt; into a
proof of &lt;span class=&quot;math inline&quot;&gt;\(x \not\equiv y\)&lt;/span&gt;; but
since &lt;span class=&quot;math inline&quot;&gt;\(x \not\equiv y\)&lt;/span&gt; is really an abbreviation for &lt;span class=&quot;math inline&quot;&gt;\((x \equiv y) \to \bot\)&lt;/span&gt;, it can be
used to derive a contradiction if we have proofs that &lt;span class=&quot;math inline&quot;&gt;\(x &amp;lt; y\)&lt;/span&gt; and
also &lt;span class=&quot;math inline&quot;&gt;\(x \equiv y\)&lt;/span&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb27&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb27-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb27-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&amp;lt;→≢ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x &amp;lt; y &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≢ y&lt;/span&gt;
&lt;span id=&quot;cb27-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb27-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&amp;lt;→≢ x&amp;lt;y refl &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; x≮x x&amp;lt;y&lt;/span&gt;
&lt;span id=&quot;cb27-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb27-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb27-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb27-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&amp;lt;→≱ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x &amp;lt; y &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ¬ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y ≤ x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb27-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb27-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&amp;lt;→≱ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle x&amp;lt;y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle y≤x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &amp;lt;→≱ x&amp;lt;y y≤x&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If &lt;span class=&quot;math inline&quot;&gt;\(x \leq y\)&lt;/span&gt; but they are not equal, then &lt;span class=&quot;math inline&quot;&gt;\(x &amp;lt; y\)&lt;/span&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb28&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb28-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb28-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤≢→&amp;lt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≤ y &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≢ y &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x &amp;lt; y&lt;/span&gt;
&lt;span id=&quot;cb28-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb28-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤≢→&amp;lt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; zero&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; zle x≢y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; absurd &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x≢y refl&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb28-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤≢→&amp;lt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; suc y&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; zle x≢y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sle zle&lt;/span&gt;
&lt;span id=&quot;cb28-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb28-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤≢→&amp;lt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle x≤y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; x≢y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sle &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;≤≢→&amp;lt; x≤y &lt;span class=&quot;ot&quot;&gt;(λ&lt;/span&gt; m≡n &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x≢y &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc $≡ m≡n&lt;span class=&quot;ot&quot;&gt;)))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We will need a form of transitivity that says if &lt;span class=&quot;math inline&quot;&gt;\(x \leq y\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(y &amp;lt;
z\)&lt;/span&gt;, then &lt;span class=&quot;math inline&quot;&gt;\(x &amp;lt; z\)&lt;/span&gt;, as well as the other way around.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb29&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb29-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb29-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤-&amp;lt;-trans &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≤ y &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; y &amp;lt; z &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x &amp;lt; z&lt;/span&gt;
&lt;span id=&quot;cb29-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb29-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤-&amp;lt;-trans x≤y &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle y&amp;lt;z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ≤-trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle x≤y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle y&amp;lt;z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb29-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb29-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb29-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb29-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&amp;lt;-≤-trans &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x &amp;lt; y &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; y ≤ z &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x &amp;lt; z&lt;/span&gt;
&lt;span id=&quot;cb29-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb29-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&amp;lt;-≤-trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle x&amp;lt;y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; y≤z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ≤-trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle x&amp;lt;y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; y≤z&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally, a very specific lemma we will need: if a number is not
equal to either 0 or 1, then it must be greater than or equal to 2.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb30&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb30-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb30-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;¬01-is-≥2 &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;a &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;a ≢ &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;a ≢ &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; ≤ a&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb30-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb30-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;¬01-is-≥2 zero a≢0 a≢1 &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; absurd &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;a≢0 refl&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb30-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb30-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;¬01-is-≥2 &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc zero&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; a≢0 a≢1 &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; absurd &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;a≢1 refl&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb30-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb30-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;¬01-is-≥2 &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc a&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt; a≢0 a≢1 &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sle &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle zle&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;level3&quot; id=&quot;arithmetic-and-inequality&quot;&gt;
&lt;h3&gt;Arithmetic and inequality&lt;/h3&gt;
&lt;p&gt;The last lemmas we need relate arithmetic operations and inequality.
First, adding and multiplying cannot make anything smaller (unless we
multiply by zero, of course).&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb31&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb31-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb31-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤+ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≤ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x + y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb31-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb31-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤+ &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;zero&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; zle&lt;/span&gt;
&lt;span id=&quot;cb31-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb31-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤+ &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sle ≤+&lt;/span&gt;
&lt;span id=&quot;cb31-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb31-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb31-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb31-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤* &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x ≢ &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; y ≤ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x * y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb31-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb31-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤* &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;zero&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; x≢0 &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; absurd &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x≢0 refl&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb31-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb31-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤* &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; x≢0 &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ≤+&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As a result, if we know that one thing is equal to a sum or product of
other things, we can conclude something about their relative sizes.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb32&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb32-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb32-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;+→≤ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x + y ≡ z &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≤ z&lt;/span&gt;
&lt;span id=&quot;cb32-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb32-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;+→≤ refl &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ≤+&lt;/span&gt;
&lt;span id=&quot;cb32-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb32-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb32-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;+→&amp;lt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; &amp;lt; y &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x + y ≡ z &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x &amp;lt; z&lt;/span&gt;
&lt;span id=&quot;cb32-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb32-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;+→&amp;lt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc y&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; x+y≡z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; +→≤ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sym &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x +suc y&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt; x+y≡z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb32-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb32-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*→≤ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y ≢ &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; y * x ≡ z &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≤ z&lt;/span&gt;
&lt;span id=&quot;cb32-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb32-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*→≤ &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;y&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; y≢0 refl &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ≤* y≢0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section class=&quot;level2&quot; id=&quot;divisibility-primes-and-composites&quot;&gt;
&lt;h2&gt;Divisibility, primes, and composites&lt;/h2&gt;
&lt;p&gt;With the preliminaries out of the way, we can finally get on with the
meat of the problem—and we finally get to make use of a dependent pair! A &lt;em&gt;constructive&lt;/em&gt; proof that &lt;code&gt;a&lt;/code&gt; divides
&lt;code&gt;b&lt;/code&gt; is a specific natural number witness &lt;code&gt;k&lt;/code&gt;, along with a proof that &lt;code&gt;k * a ≡ b&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb33&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb33-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb33-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;∣&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb33-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;a ∣ b &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; Σ ℕ &lt;span class=&quot;ot&quot;&gt;(λ&lt;/span&gt; k &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; k * a ≡ b&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Proofs of divisibility are unique—that is, for given &lt;span class=&quot;math inline&quot;&gt;\(a\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(b\)&lt;/span&gt; there
is at most one value of &lt;span class=&quot;math inline&quot;&gt;\(k\)&lt;/span&gt; such that &lt;span class=&quot;math inline&quot;&gt;\(ka = b\)&lt;/span&gt;. We won’t need this,
but it follows easily from the fact that multiplication is
cancellative. More interesting is the fact that divisibility is
&lt;em&gt;decidable&lt;/em&gt;—that is, for given numbers &lt;span class=&quot;math inline&quot;&gt;\(a\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(b\)&lt;/span&gt; we can calculate
either a proof that &lt;span class=&quot;math inline&quot;&gt;\(a \mid b\)&lt;/span&gt;, or a proof that &lt;span class=&quot;math inline&quot;&gt;\(\neg (a \mid b)\)&lt;/span&gt;.
This will play a starring role later on—to factor a number we need to
be able to try potential divisors and find out whether they work—but proving it is not easy!
It will take us several hundred more lines of Agda to get there.&lt;/p&gt;
&lt;p&gt;In any case, using this notion of divisibility, we can now define prime and
composite numbers. A number &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; is defined to be prime if it is at
least two, and every &lt;span class=&quot;math inline&quot;&gt;\(2 \leq d &amp;lt; n\)&lt;/span&gt; does &lt;em&gt;not&lt;/em&gt; divide &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb34&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb34-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb34-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;Prime &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb34-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;Prime n &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; ≤ n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; × &lt;span class=&quot;ot&quot;&gt;(∀&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;d &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;d &amp;lt; n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; ≤ d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ¬ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;d ∣ n&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;One could equivalently define primality by saying that any divisor of
&lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; must be equal to &lt;span class=&quot;math inline&quot;&gt;\(1\)&lt;/span&gt; or &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt;; I just decided I liked this
formulation better, especially because it directly matches up with the
way we will test a number for primality later.&lt;/p&gt;
&lt;p&gt;A composite number is one that has a nontrivial divisor—that is, a number &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt;
such that &lt;span class=&quot;math inline&quot;&gt;\(2 \leq d &amp;lt; n\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt; divides &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt;.&lt;span class=&quot;sidenote-wrapper&quot;&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;sn-5&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;sn-5&quot; type=&quot;checkbox&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;Note
that we could easily prove that if &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; is prime then &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; is not
composite, and likewise if &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; is composite then it is not prime, but
we won’t end up needing these lemmas.&lt;br /&gt;
&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb35&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb35-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb35-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;Composite &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb35-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb35-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;Composite n &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; Σ ℕ &lt;span class=&quot;ot&quot;&gt;(λ&lt;/span&gt; d &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; ≤ d × d &amp;lt; n × d ∣ n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Unlike proofs of divisibility, proofs of &lt;code&gt;Composite n&lt;/code&gt; are &lt;em&gt;not&lt;/em&gt;
unique. For example, we could prove &lt;code&gt;Composite 12&lt;/code&gt; by showing that
&lt;span class=&quot;math inline&quot;&gt;\(2\)&lt;/span&gt; is a nontrivial divisor of &lt;span class=&quot;math inline&quot;&gt;\(12\)&lt;/span&gt;, or by showing that &lt;span class=&quot;math inline&quot;&gt;\(3\)&lt;/span&gt; is.
Although this does not matter from a purely logical point of view, it
matters computationally; in general, we care which specific proof of
&lt;code&gt;Composite n&lt;/code&gt; we have.&lt;/p&gt;
&lt;section class=&quot;level3&quot; id=&quot;nontrivial-divisors-come-in-pairs&quot;&gt;
&lt;h3&gt;Nontrivial divisors come in pairs&lt;/h3&gt;
&lt;p&gt;Before moving on to other things, we will prove a lemma about
composite numbers. If &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; is composite, by definition it has a
nontrivial divisor &lt;span class=&quot;math inline&quot;&gt;\(a\)&lt;/span&gt;; but this means it must also have a second
nontrivial divisor &lt;span class=&quot;math inline&quot;&gt;\(b\)&lt;/span&gt; such that &lt;span class=&quot;math inline&quot;&gt;\(ab = n\)&lt;/span&gt;. This fact seems almost
trivial to us. Indeed, it’s easy to show that if &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; has a divisor
&lt;span class=&quot;math inline&quot;&gt;\(a\)&lt;/span&gt;, then it must have another divisor &lt;span class=&quot;math inline&quot;&gt;\(b\)&lt;/span&gt; such that &lt;span class=&quot;math inline&quot;&gt;\(ab = n\)&lt;/span&gt;. The
tricky part is showing that if &lt;span class=&quot;math inline&quot;&gt;\(a\)&lt;/span&gt; is a &lt;em&gt;nontrivial&lt;/em&gt; divisor, then &lt;span class=&quot;math inline&quot;&gt;\(b\)&lt;/span&gt;
is &lt;em&gt;also&lt;/em&gt; nontrivial. The proof relies on much of the infrastructure
we have built up about natural numbers, multiplication, and
inequality.&lt;/p&gt;
&lt;p&gt;First, we define a type representing two factors of a number &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt;: a
pair of proofs that &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; is composite (&lt;em&gt;i.e.&lt;/em&gt; two nontrivial divisors
of &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt;), along with a proof that the product of those divisors is &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb36&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb36-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb36-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;FactorsOf &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb36-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb36-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;FactorsOf n &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; Σ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;Composite n × Composite n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(λ&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{(&lt;/span&gt;f₁ , f₂&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; fst f₁ * fst f₂ ≡ n&lt;span class=&quot;ot&quot;&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now, we prove that if &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; is composite, then it has two nontrivial
factors. We begin by pattern-matching on the proof that &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; is
composite, which consists of a divisor &lt;span class=&quot;math inline&quot;&gt;\(a\)&lt;/span&gt;, evidence that &lt;span class=&quot;math inline&quot;&gt;\(a\)&lt;/span&gt; is
nontrivial (&lt;em&gt;i.e.&lt;/em&gt; &lt;span class=&quot;math inline&quot;&gt;\(2 \leq a\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(a &amp;lt; n\)&lt;/span&gt;), and a proof that &lt;span class=&quot;math inline&quot;&gt;\(a\)&lt;/span&gt; is a
divisor of &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt;, which itself consists of a number &lt;span class=&quot;math inline&quot;&gt;\(b\)&lt;/span&gt; paired with a
proof that &lt;span class=&quot;math inline&quot;&gt;\(ba = n\)&lt;/span&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb37&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb37-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb37-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;factorsOf &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Composite n &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; FactorsOf n&lt;/span&gt;
&lt;span id=&quot;cb37-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb37-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;factorsOf n &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;a , 2≤a , a&amp;lt;n , b , ba≡n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To construct the proof of &lt;code&gt;FactorsOf n&lt;/code&gt;, we need two proofs of
&lt;code&gt;Composite n&lt;/code&gt; along with a proof that the product of the two divisors
is &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt;. We already have a proof that &lt;span class=&quot;math inline&quot;&gt;\(ba = n\)&lt;/span&gt;, so we use that, with
&lt;span class=&quot;math inline&quot;&gt;\(a\)&lt;/span&gt; as the second divisor (replicating the corresponding proof of
&lt;code&gt;Composite n&lt;/code&gt;), and &lt;span class=&quot;math inline&quot;&gt;\(b\)&lt;/span&gt; as the first. Proving that &lt;span class=&quot;math inline&quot;&gt;\(b\)&lt;/span&gt; is a divisor of
&lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; is easy: &lt;span class=&quot;math inline&quot;&gt;\(a\)&lt;/span&gt; is the witness, and proving that &lt;span class=&quot;math inline&quot;&gt;\(ab = n\)&lt;/span&gt; is easy
since we already know &lt;span class=&quot;math inline&quot;&gt;\(ba = n\)&lt;/span&gt; and multiplication is commutative. The
only thing left is to prove that &lt;span class=&quot;math inline&quot;&gt;\(b\)&lt;/span&gt; is nontrivial, &lt;em&gt;i.e.&lt;/em&gt; that &lt;span class=&quot;math inline&quot;&gt;\(2
\leq b\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(b &amp;lt; n\)&lt;/span&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb38&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb38-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb38-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;((&lt;/span&gt;b , 2≤b , b&amp;lt;n , a , trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;*-comm a b&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; ba≡n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; , &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;a , 2≤a , a&amp;lt;n , b , ba≡n&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt; , ba≡n&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;First, we need a lemma that &lt;span class=&quot;math inline&quot;&gt;\(0 &amp;lt; n\)&lt;/span&gt;, which follows because &lt;span class=&quot;math inline&quot;&gt;\(0 &amp;lt; 1 &amp;lt; a
&amp;lt; n\)&lt;/span&gt; (remember that a proof of &lt;span class=&quot;math inline&quot;&gt;\(1 &amp;lt; a\)&lt;/span&gt; is actually defined to be the
same thing as a proof of &lt;span class=&quot;math inline&quot;&gt;\(2 \leq a\)&lt;/span&gt;).&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb39&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb39-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb39-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb39-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb39-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  0&amp;lt;n &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; &amp;lt; n&lt;/span&gt;
&lt;span id=&quot;cb39-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb39-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  0&amp;lt;n &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &amp;lt;-trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle zle&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;&amp;lt;-trans 2≤a a&amp;lt;n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next, we tackle &lt;span class=&quot;math inline&quot;&gt;\(2 \leq b\)&lt;/span&gt;, by showing that &lt;span class=&quot;math inline&quot;&gt;\(b\)&lt;/span&gt; can’t possibly be &lt;span class=&quot;math inline&quot;&gt;\(0\)&lt;/span&gt;
or &lt;span class=&quot;math inline&quot;&gt;\(1\)&lt;/span&gt; (using our previous lemma that anything not equal to 0 or 1
must be greater than or equal to 2).&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb40&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb40-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb40-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  2≤b &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; ≤ b&lt;/span&gt;
&lt;span id=&quot;cb40-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb40-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  2≤b &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ¬01-is-≥2 b&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If &lt;span class=&quot;math inline&quot;&gt;\(b\)&lt;/span&gt; were &lt;span class=&quot;math inline&quot;&gt;\(0\)&lt;/span&gt;, then &lt;span class=&quot;math inline&quot;&gt;\(ba = n\)&lt;/span&gt; would imply &lt;span class=&quot;math inline&quot;&gt;\(0 = n\)&lt;/span&gt;, but we know
&lt;span class=&quot;math inline&quot;&gt;\(0 &amp;lt; n\)&lt;/span&gt;, so this is a contradiction.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb41&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb41-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb41-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;(λ&lt;/span&gt; b≡0 &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &amp;lt;→≢ 0&amp;lt;n&lt;/span&gt;
&lt;span id=&quot;cb41-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb41-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;begin&lt;/span&gt;
&lt;span id=&quot;cb41-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb41-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;                     ≡[ refl ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb41-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb41-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; * a                 ≡⟨ &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;*&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; $≡ b≡0 ≡$ a ]≡&lt;/span&gt;
&lt;span id=&quot;cb41-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb41-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        b * a                 ≡[ ba≡n ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb41-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb41-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        n                     ∎&lt;/span&gt;
&lt;span id=&quot;cb41-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb41-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb41-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb41-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If &lt;span class=&quot;math inline&quot;&gt;\(b\)&lt;/span&gt; were &lt;span class=&quot;math inline&quot;&gt;\(1\)&lt;/span&gt;, then &lt;span class=&quot;math inline&quot;&gt;\(ba = n\)&lt;/span&gt; would imply &lt;span class=&quot;math inline&quot;&gt;\(a = n\)&lt;/span&gt;, but we know
&lt;span class=&quot;math inline&quot;&gt;\(a &amp;lt; n\)&lt;/span&gt;, so this is also a contradiction.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb42&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb42-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb42-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;(λ&lt;/span&gt; b≡1 &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &amp;lt;→≢ a&amp;lt;n&lt;/span&gt;
&lt;span id=&quot;cb42-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb42-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;begin&lt;/span&gt;
&lt;span id=&quot;cb42-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb42-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        a                     ≡⟨ a *1 ]≡&lt;/span&gt;
&lt;span id=&quot;cb42-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb42-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        a * &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;                 ≡[ *-comm a &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt; ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb42-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb42-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt; * a                 ≡⟨ &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;*&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; $≡ b≡1 ≡$ a ]≡&lt;/span&gt;
&lt;span id=&quot;cb42-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb42-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        b * a                 ≡[ ba≡n ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb42-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb42-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        n                     ∎&lt;/span&gt;
&lt;span id=&quot;cb42-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb42-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb42-9&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb42-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally, we prove &lt;span class=&quot;math inline&quot;&gt;\(b &amp;lt; n\)&lt;/span&gt;, by showing &lt;span class=&quot;math inline&quot;&gt;\(b \leq n\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(b \neq n\)&lt;/span&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb43&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb43-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb43-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  b&amp;lt;n &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; b &amp;lt; n&lt;/span&gt;
&lt;span id=&quot;cb43-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb43-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  b&amp;lt;n &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ≤≢→&amp;lt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;span class=&quot;math inline&quot;&gt;\(b \leq n\)&lt;/span&gt; since &lt;span class=&quot;math inline&quot;&gt;\(ba = n\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(a\)&lt;/span&gt; is not zero (if &lt;span class=&quot;math inline&quot;&gt;\(a\)&lt;/span&gt; were zero it
would contradict the fact that &lt;span class=&quot;math inline&quot;&gt;\(2 \leq a\)&lt;/span&gt;).&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb44&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb44-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb44-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;*→≤ &lt;span class=&quot;ot&quot;&gt;(λ&lt;/span&gt; a≡0 &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &amp;lt;→≢ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;&amp;lt;-trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle zle&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; 2≤a&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sym a≡0&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;*-comm a b&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; ba≡n&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;span class=&quot;math inline&quot;&gt;\(b \neq n\)&lt;/span&gt;, since &lt;span class=&quot;math inline&quot;&gt;\(b = n\)&lt;/span&gt; together with &lt;span class=&quot;math inline&quot;&gt;\(ba = n\)&lt;/span&gt; would imply &lt;span class=&quot;math inline&quot;&gt;\(a = 1\)&lt;/span&gt;
(since multiplication is cancellative), but &lt;span class=&quot;math inline&quot;&gt;\(2 \leq a\)&lt;/span&gt; so it cannot
equal 1.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb45&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb45-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb45-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;(λ&lt;/span&gt; b≡n &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &amp;lt;→≢ 2≤a&lt;/span&gt;
&lt;span id=&quot;cb45-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb45-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sym&lt;/span&gt;
&lt;span id=&quot;cb45-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb45-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;*-cancelˡ n a &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;&amp;lt;→≢ 0&amp;lt;n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb45-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb45-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;begin&lt;/span&gt;
&lt;span id=&quot;cb45-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb45-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            n * a             ≡⟨ &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;*&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; $≡ b≡n ≡$ a ]≡&lt;/span&gt;
&lt;span id=&quot;cb45-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb45-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            b * a             ≡[ ba≡n ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb45-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb45-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            n                 ≡⟨ n *1 ]≡&lt;/span&gt;
&lt;span id=&quot;cb45-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb45-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            n * &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;             ∎&lt;/span&gt;
&lt;span id=&quot;cb45-9&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb45-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb45-10&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb45-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb45-11&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb45-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb45-12&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb45-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section class=&quot;level2&quot; id=&quot;division&quot;&gt;
&lt;h2&gt;Division&lt;/h2&gt;
&lt;p&gt;Let’s start working our way towards proving that divisibility is
decidable. To check whether &lt;span class=&quot;math inline&quot;&gt;\(d \mid n\)&lt;/span&gt;, the usual idea would be to
divide &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; by &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt; and check whether we get a remainder of zero. So we
need to formalize this notion of division with remainder.&lt;/p&gt;
&lt;p&gt;Specifically, when we divide &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; by &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt;, we expect to get a &lt;em&gt;quotient&lt;/em&gt; &lt;span class=&quot;math inline&quot;&gt;\(q\)&lt;/span&gt;
and a &lt;em&gt;remainder&lt;/em&gt; &lt;span class=&quot;math inline&quot;&gt;\(r\)&lt;/span&gt;, such that &lt;span class=&quot;math inline&quot;&gt;\(r + qd = n\)&lt;/span&gt;, and &lt;span class=&quot;math inline&quot;&gt;\(0 \leq r &amp;lt; d\)&lt;/span&gt;.
The first condition, &lt;span class=&quot;math inline&quot;&gt;\(r + qd = n\)&lt;/span&gt;, just defines what we mean by division: &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; is
&lt;span class=&quot;math inline&quot;&gt;\(q\)&lt;/span&gt; times &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt;, plus a remainder of &lt;span class=&quot;math inline&quot;&gt;\(r\)&lt;/span&gt;. The second condition will ensure
that the result is unique. We wouldn’t want to divide &lt;span class=&quot;math inline&quot;&gt;\(17\)&lt;/span&gt; by &lt;span class=&quot;math inline&quot;&gt;\(2\)&lt;/span&gt; and
end up with a quotient of &lt;span class=&quot;math inline&quot;&gt;\(6\)&lt;/span&gt; and a remainder of &lt;span class=&quot;math inline&quot;&gt;\(5\)&lt;/span&gt;; the remainder should be as small as possible.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;DivMod&lt;/code&gt; type simply encodes these requirements.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb46&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb46-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb46-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; DivMod &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n d q r &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb46-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb46-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  DM &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;r + q * d ≡ n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;r &amp;lt; d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; DivMod n d q r&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can prove a few lemmas about &lt;code&gt;DivMod&lt;/code&gt;. First, whenever we have
&lt;code&gt;DivMod n d q r&lt;/code&gt;, then &lt;code&gt;d&lt;/code&gt; must be positive, since &lt;span class=&quot;math inline&quot;&gt;\(r &amp;lt; d\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(r\)&lt;/span&gt; is
a natural number.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb47&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb47-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb47-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;divMod→0&amp;lt;d &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;n d q r &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; DivMod n d q r &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; &amp;lt; d&lt;/span&gt;
&lt;span id=&quot;cb47-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb47-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;divMod→0&amp;lt;d &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;DM &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; r&amp;lt;d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ≤-&amp;lt;-trans zle r&amp;lt;d&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can also show that for nonzero &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt;, the remainder is zero if and only if &lt;span class=&quot;math inline&quot;&gt;\(d
\mid n\)&lt;/span&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb48&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb48-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb48-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;mod0→divides &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n d &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;q &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; DivMod n d q &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; d ∣ n&lt;/span&gt;
&lt;span id=&quot;cb48-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb48-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;mod0→divides n d &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;q&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;DM eq &lt;span class=&quot;ot&quot;&gt;_)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; q , eq&lt;/span&gt;
&lt;span id=&quot;cb48-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb48-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb48-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb48-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;divides→mod0 &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n d &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; &amp;lt; d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; d ∣ n &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Σ ℕ &lt;span class=&quot;ot&quot;&gt;(λ&lt;/span&gt; q &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; DivMod n d q &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb48-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb48-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;divides→mod0 n d 0&amp;lt;d &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;q , qd≡n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; q , &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;DM qd≡n 0&amp;lt;d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We would also like to show that if the remainder when dividing &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; by
&lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt; is &lt;em&gt;not&lt;/em&gt; zero, then &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt; does &lt;em&gt;not&lt;/em&gt; divide &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt;. This is &lt;em&gt;almost&lt;/em&gt;
the contrapositive of &lt;code&gt;divides→mod0&lt;/code&gt;—which would be trivial to
show—but not quite: I said “the” remainder, but actually we don’t yet
know that the quotient and remainder are unique! Perhaps we could get
a remainder of 0 and some other remainder for the same &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt;, by
choosing different quotients?&lt;/p&gt;
&lt;p&gt;Of course, quotients and remainders &lt;em&gt;are&lt;/em&gt; unique: that is, if &lt;span class=&quot;math inline&quot;&gt;\(q_1,
r_1\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(q_2, r_2\)&lt;/span&gt; both satisfy the properties to be the quotient and
remainder of &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; divided by &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt;, then in fact &lt;span class=&quot;math inline&quot;&gt;\(q_1 = q_2\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(r_1 =
r_2\)&lt;/span&gt;. But how can we prove this? The usual idea is to look at the
difference &lt;span class=&quot;math inline&quot;&gt;\(r_1 - r_2 = dq_1 - dq_2\)&lt;/span&gt;, which is divisible by &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt;; but
since &lt;span class=&quot;math inline&quot;&gt;\(r_1 &amp;lt; d\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(r_2 &amp;lt; d\)&lt;/span&gt;, the only way for the difference &lt;span class=&quot;math inline&quot;&gt;\(r_1 -
r_2\)&lt;/span&gt; to be divisible by &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt; is if in fact &lt;span class=&quot;math inline&quot;&gt;\(r_1 - r_2 = 0\)&lt;/span&gt;. From here
we can also derive &lt;span class=&quot;math inline&quot;&gt;\(q_1 = q_2\)&lt;/span&gt; via algebra.&lt;/p&gt;
&lt;p&gt;Subtraction, eh? In order to formalize this, it seems as though we might
need to define the integers… but there is a better way!&lt;/p&gt;
&lt;/section&gt;
&lt;section class=&quot;level2&quot; id=&quot;absolute-difference&quot;&gt;
&lt;h2&gt;Absolute difference&lt;/h2&gt;
&lt;p&gt;The previous informal argument mentioned the difference &lt;span class=&quot;math inline&quot;&gt;\(r_1 - r_2\)&lt;/span&gt;.
But we could just as easily have talked about &lt;span class=&quot;math inline&quot;&gt;\(r_2 - r_1\)&lt;/span&gt; instead, and
the same argument would work just as well. This observation shows
that we do not actually care about the (signed) &lt;em&gt;difference&lt;/em&gt; between
&lt;span class=&quot;math inline&quot;&gt;\(r_1\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(r_2\)&lt;/span&gt;, but only the &lt;em&gt;distance&lt;/em&gt; between them. This means we
can just stick to our well-loved natural numbers, and define a commutative
&lt;em&gt;absolute difference&lt;/em&gt; function which computes the nonnegative distance
between its two arguments, like so:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb49&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb49-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb49-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;∥&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;-&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;∥ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ℕ&lt;/span&gt;
&lt;span id=&quot;cb49-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb49-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;∥ zero - y ∥ &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; y&lt;/span&gt;
&lt;span id=&quot;cb49-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb49-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;∥ suc x - zero ∥ &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; suc x&lt;/span&gt;
&lt;span id=&quot;cb49-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb49-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;∥ suc x - suc y ∥ &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ∥ x - y ∥&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Of course, we will need a lot of small lemmas about the properties of
this operation. We can start by proving that the distance between two
numbers is 0 if and only if they are equal:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb50&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb50-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb50-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff0 &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; ≡ ∥ x - x ∥&lt;/span&gt;
&lt;span id=&quot;cb50-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb50-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff0 zero &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb50-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb50-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff0 &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; diff0 x&lt;/span&gt;
&lt;span id=&quot;cb50-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb50-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb50-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb50-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff0→≡ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; ≡ ∥ x - y ∥ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≡ y&lt;/span&gt;
&lt;span id=&quot;cb50-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb50-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff0→≡ &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;zero&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;zero&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; eq &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; eq&lt;/span&gt;
&lt;span id=&quot;cb50-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb50-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff0→≡ &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc y&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; eq &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; suc $≡ diff0→≡ eq&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next, the distance between any number and 0 is the number itself, and
the distance function is commutative.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb51&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb51-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb51-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;∥x-0∥≡x &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ∥ x - &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; ∥ ≡ x&lt;/span&gt;
&lt;span id=&quot;cb51-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb51-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;∥x-0∥≡x zero &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb51-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb51-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;∥x-0∥≡x &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb51-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb51-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb51-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb51-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff-comm &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ∥ x - y ∥ ≡ ∥ y - x ∥&lt;/span&gt;
&lt;span id=&quot;cb51-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb51-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff-comm &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;zero&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;zero&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb51-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb51-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff-comm &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;zero&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc y&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb51-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb51-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff-comm &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;zero&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb51-9&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb51-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff-comm &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc y&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; diff-comm &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;y&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A key lemma supporting the argument outlined in the previous section
is that if &lt;span class=&quot;math inline&quot;&gt;\(x\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(y\)&lt;/span&gt; are both less than &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt;, so is their absolute difference.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb52&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb52-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb52-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff-&amp;lt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y d &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x &amp;lt; d &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; y &amp;lt; d &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ∥ x - y ∥ &amp;lt; d&lt;/span&gt;
&lt;span id=&quot;cb52-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb52-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff-&amp;lt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;zero&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;y&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; x&amp;lt;d y&amp;lt;d &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; y&amp;lt;d&lt;/span&gt;
&lt;span id=&quot;cb52-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb52-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff-&amp;lt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;zero&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; x&amp;lt;d y&amp;lt;d &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; x&amp;lt;d&lt;/span&gt;
&lt;span id=&quot;cb52-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb52-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff-&amp;lt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc y&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; x&amp;lt;d y&amp;lt;d &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; diff-&amp;lt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;y&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;&amp;lt;-trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x &amp;lt;suc&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; x&amp;lt;d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;&amp;lt;-trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y &amp;lt;suc&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; y&amp;lt;d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can also cancel the same thing being added to both sides, or factor out
the same thing being multiplied on both sides.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb53&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb53-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb53-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff-cancelˡ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;a b c &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ∥ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;a + b&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; - &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;a + c&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; ∥ ≡ ∥ b - c ∥&lt;/span&gt;
&lt;span id=&quot;cb53-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb53-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff-cancelˡ zero b c &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb53-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb53-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff-cancelˡ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc a&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; b c &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; diff-cancelˡ a b c&lt;/span&gt;
&lt;span id=&quot;cb53-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb53-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb53-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb53-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff-distribʳ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x y d &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ∥ x * d - y * d ∥ ≡ ∥ x - y ∥ * d&lt;/span&gt;
&lt;span id=&quot;cb53-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb53-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff-distribʳ zero y d &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb53-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb53-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff-distribʳ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; zero d &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ∥x-0∥≡x &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;d + x * d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb53-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb53-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff-distribʳ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; d &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; begin&lt;/span&gt;
&lt;span id=&quot;cb53-9&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb53-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ∥ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;d + x * d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; - &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;d + y * d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; ∥         ≡[ diff-cancelˡ d &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x * d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y * d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb53-10&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb53-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ∥ x * d - y * d ∥                     ≡[ diff-distribʳ x y d ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb53-11&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb53-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ∥ x - y ∥ * d                         ∎&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Another key lemma is that if &lt;span class=&quot;math inline&quot;&gt;\(w + x = y + z\)&lt;/span&gt;, then &lt;span class=&quot;math inline&quot;&gt;\(\|w - y\| = \|x -
z\|\)&lt;/span&gt; (&lt;code&gt;sub₂&lt;/code&gt; below). Personally, I found this quite tricky to prove.
The best approach I found was to first prove the simpler lemma that
&lt;span class=&quot;math inline&quot;&gt;\(x + y = z\)&lt;/span&gt; implies &lt;span class=&quot;math inline&quot;&gt;\(x = \| z - y \|\)&lt;/span&gt; (&lt;code&gt;sub₁&lt;/code&gt;), which can then be used
in several places in the proof of &lt;code&gt;sub₂&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb54&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb54-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb54-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sub₁ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x + y ≡ z &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≡ ∥ z - y ∥&lt;/span&gt;
&lt;span id=&quot;cb54-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb54-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sub₁ &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;zero&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;y&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;z&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; refl &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; diff0 y&lt;/span&gt;
&lt;span id=&quot;cb54-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb54-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sub₁ &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;zero&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc z&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; x+y≡z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb54-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb54-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  begin&lt;/span&gt;
&lt;span id=&quot;cb54-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb54-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    suc x                     ≡⟨ suc $≡ x +0 ]≡&lt;/span&gt;
&lt;span id=&quot;cb54-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb54-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    suc &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x + &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;               ≡[ x+y≡z ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb54-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb54-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    suc z                     ∎&lt;/span&gt;
&lt;span id=&quot;cb54-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb54-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sub₁ &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc y&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc z&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; x+y≡z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb54-9&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb54-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  sub₁ &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;y&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;z&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb54-10&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb54-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;noConf &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc $≡ sym &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x +suc y&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt; x+y≡z&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb54-11&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb54-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb54-12&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb54-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sub₂ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;w x y z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; w + x ≡ y + z &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ∥ w - y ∥ ≡ ∥ x - z ∥&lt;/span&gt;
&lt;span id=&quot;cb54-13&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb54-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sub₂ &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;zero&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;y&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;z&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; w+x≡y+z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sub₁ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sym w+x≡y+z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb54-14&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb54-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sub₂ &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc w&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;zero&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;z&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; w+x≡y+z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sub₁ w+x≡y+z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;diff-comm &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;z&lt;span class=&quot;ot&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb54-15&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb54-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sub₂ &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc w&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc y&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;z&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; w+x≡y+z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sub₂ &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;w&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;noConf w+x≡y+z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;level2&quot; id=&quot;quotient-and-remainder-are-unique&quot;&gt;
&lt;h2&gt;Quotient and remainder are unique&lt;/h2&gt;
&lt;p&gt;We can now return to prove that quotient and remainder are unique.
First, we show that zero is the only multiple of &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt; which is less than &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb55&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb55-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb55-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;∣&amp;lt;→0 &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;d x &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; d ∣ x &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x &amp;lt; d &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; ≡ x&lt;/span&gt;
&lt;span id=&quot;cb55-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb55-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;∣&amp;lt;→0 &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;zero , ad≡x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; x&amp;lt;d &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ad≡x&lt;/span&gt;
&lt;span id=&quot;cb55-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb55-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;∣&amp;lt;→0 &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc a , ad≡x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; x&amp;lt;d &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; absurd &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;&amp;lt;→≱ x&amp;lt;d &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;+→≤ ad≡x&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And now for the main event: if we have both &lt;code&gt;DivMod n d q₁ r₁&lt;/code&gt; and
&lt;code&gt;DivMod n d q₂ r₂&lt;/code&gt;, then in fact the &lt;code&gt;q&lt;/code&gt;s and &lt;code&gt;r&lt;/code&gt;s must be the same.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb56&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb56-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb56-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;divModUnique &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;n d q₁ r₁ q₂ r₂ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; DivMod n d q₁ r₁ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; DivMod n d q₂ r₂ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;q₁ ≡ q₂&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; × &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;r₁ ≡ r₂&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb56-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb56-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;divModUnique &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;n&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;d&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;q₁&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;r₁&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;q₂&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;r₂&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; dm&lt;span class=&quot;ot&quot;&gt;@(&lt;/span&gt;DM r₁+q₁d≡n r₁&amp;lt;d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;DM r₂+q₂d≡n r₂&amp;lt;d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; q₁≡q₂ , r₁≡r₂&lt;/span&gt;
&lt;span id=&quot;cb56-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb56-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Since &lt;span class=&quot;math inline&quot;&gt;\(r_1 + q_1d = n\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(r_2 + q_2d = n\)&lt;/span&gt;, by transitivity and
symmetry we have &lt;span class=&quot;math inline&quot;&gt;\(r_1 + q_1d = r_2 + q_2d\)&lt;/span&gt;; then by the &lt;code&gt;sub₂&lt;/code&gt; lemma,
&lt;span class=&quot;math inline&quot;&gt;\(\|r_1 - r_2\| = \|q_1d - q_2d\|\)&lt;/span&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb57&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb57-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb57-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  rem-diff &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ∥ r₁ - r₂ ∥ ≡ ∥ q₁ * d - q₂ * d ∥&lt;/span&gt;
&lt;span id=&quot;cb57-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb57-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  rem-diff &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sub₂ &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;r₁&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;trans r₁+q₁d≡n &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sym r₂+q₂d≡n&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next, we can show that &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt; divides the absolute difference &lt;span class=&quot;math inline&quot;&gt;\(\|r_1 -
  r_2\|\)&lt;/span&gt;, by factoring it out of &lt;span class=&quot;math inline&quot;&gt;\(\|q_1 d - q_2 d\|\)&lt;/span&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb58&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb58-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb58-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  d∣r₁-r₂ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; d ∣ ∥ r₁ - r₂ ∥&lt;/span&gt;
&lt;span id=&quot;cb58-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb58-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  d∣r₁-r₂ &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ∥ q₁ - q₂ ∥ ,&lt;/span&gt;
&lt;span id=&quot;cb58-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb58-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;begin&lt;/span&gt;
&lt;span id=&quot;cb58-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb58-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      ∥ q₁ - q₂ ∥ * d         ≡⟨ diff-distribʳ q₁ q₂ d ]≡&lt;/span&gt;
&lt;span id=&quot;cb58-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb58-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      ∥ q₁ * d - q₂ * d ∥     ≡⟨ rem-diff ]≡&lt;/span&gt;
&lt;span id=&quot;cb58-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb58-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      ∥ r₁ - r₂ ∥             ∎&lt;/span&gt;
&lt;span id=&quot;cb58-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb58-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can then put three lemmas together to conclude &lt;span class=&quot;math inline&quot;&gt;\(r_1 = r_2\)&lt;/span&gt;: first,
since &lt;span class=&quot;math inline&quot;&gt;\(r_1\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(r_2\)&lt;/span&gt; are both less than &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt;, so is their absolute
difference; since &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt; also divides the absolute difference, the
absolute difference must be zero; and finally, an absolute difference
of zero means &lt;span class=&quot;math inline&quot;&gt;\(r_1\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(r_2\)&lt;/span&gt; must be equal.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb59&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb59-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb59-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  r₁≡r₂ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; r₁ ≡ r₂&lt;/span&gt;
&lt;span id=&quot;cb59-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb59-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  r₁≡r₂ &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; diff0→≡ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;∣&amp;lt;→0 d∣r₁-r₂ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;diff-&amp;lt; r₁&amp;lt;d r₂&amp;lt;d&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;From here, proving &lt;span class=&quot;math inline&quot;&gt;\(q_1 = q_2\)&lt;/span&gt; just requires some algebra.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb60&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb60-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb60-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  dq₁≡dq₂ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; d * q₁ ≡ d * q₂&lt;/span&gt;
&lt;span id=&quot;cb60-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb60-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  dq₁≡dq₂ &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; +-cancelˡ r₁ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;d * q₁&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;d * q₂&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb60-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;begin&lt;/span&gt;
&lt;span id=&quot;cb60-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb60-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      r₁ + d * q₁             ≡[ r₁ +&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; $≡ *-comm d q₁ ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb60-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb60-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      r₁ + q₁ * d             ≡[ r₁+q₁d≡n ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb60-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb60-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      n                       ≡⟨ r₂+q₂d≡n ]≡&lt;/span&gt;
&lt;span id=&quot;cb60-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb60-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      r₂ + q₂ * d             ≡[ &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;+&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; $≡ sym r₁≡r₂ ≡$≡ *-comm q₂ d ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb60-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb60-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      r₁ + d * q₂             ∎&lt;/span&gt;
&lt;span id=&quot;cb60-9&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb60-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-10&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb60-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-11&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb60-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  q₁≡q₂ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; q₁ ≡ q₂&lt;/span&gt;
&lt;span id=&quot;cb60-12&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb60-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  q₁≡q₂ &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; *-cancelˡ d q₁ q₂ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;&amp;lt;→≢ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;divMod→0&amp;lt;d dm&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt; dq₁≡dq₂&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally, we can use uniqueness of quotients and remainders to show the
lemma we wanted about divisibility and remainders: if &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; divided by
&lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt; has some nonzero number as remainder, then &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt; does not divide
&lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt;. If &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt; did divide &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt;, then we know we would get a remainder of
&lt;span class=&quot;math inline&quot;&gt;\(0\)&lt;/span&gt;; but since remainders are unique, we can’t have both a zero and
nonzero remainder.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb61&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb61-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb61-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;modS→¬divides &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n d &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;q r &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; DivMod n d q &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc r&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ¬ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;d ∣ n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb61-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb61-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;modS→¬divides n d dm d∣n &lt;span class=&quot;kw&quot;&gt;with&lt;/span&gt; divides→mod0 n d &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;divMod→0&amp;lt;d dm&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; d∣n&lt;/span&gt;
&lt;span id=&quot;cb61-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb61-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;|&lt;/span&gt; q₂ , dm₂ &lt;span class=&quot;kw&quot;&gt;with&lt;/span&gt; divModUnique dm dm₂&lt;/span&gt;
&lt;span id=&quot;cb61-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb61-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;|&lt;/span&gt; q₁≡q₂ , &lt;span class=&quot;ot&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;level2&quot; id=&quot;the-division-algorithm-take-1&quot;&gt;
&lt;h2&gt;The division algorithm, take 1&lt;/h2&gt;
&lt;p&gt;So, given natural numbers &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt;, how do we compute the quotient
and remainder? We can write down a type &lt;code&gt;DivAlg&lt;/code&gt; that expresses what
we want: given some &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt;, &lt;code&gt;DivAlg n d&lt;/code&gt; represents the result of
the division algorithm, that is, a pair of numbers &lt;span class=&quot;math inline&quot;&gt;\((q,r)\)&lt;/span&gt; such that
&lt;code&gt;DivMod n d q r&lt;/code&gt; holds.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb62&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb62-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb62-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;DivAlg &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb62-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb62-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;DivAlg n d &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; Σ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;ℕ × ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(λ&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;q , r&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; DivMod n d q r &lt;span class=&quot;ot&quot;&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then we want a function with a type something like &lt;code&gt;(n d : ℕ) → DivAlg n d&lt;/code&gt; (actually this type is not quite correct—can you see why?).
How can we write something with this type?&lt;/p&gt;
&lt;p&gt;One simple idea, expressed imperatively, is to start with &lt;span class=&quot;math inline&quot;&gt;\(q = 0\)&lt;/span&gt;.
Now, as long as &lt;span class=&quot;math inline&quot;&gt;\(n \geq d\)&lt;/span&gt;, subtract &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt; from &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; and add one to
&lt;span class=&quot;math inline&quot;&gt;\(q\)&lt;/span&gt;—if we can find &lt;span class=&quot;math inline&quot;&gt;\(q\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(r\)&lt;/span&gt; such that &lt;span class=&quot;math inline&quot;&gt;\(r + qd = n - d\)&lt;/span&gt;, then &lt;span class=&quot;math inline&quot;&gt;\(r +
(q+1)d = n\)&lt;/span&gt;. Eventually, &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; must land in the range &lt;span class=&quot;math inline&quot;&gt;\(0 \leq n &amp;lt; d\)&lt;/span&gt;,
in which case it will be the remainder, and the current value of &lt;span class=&quot;math inline&quot;&gt;\(q\)&lt;/span&gt;
will be the quotient.&lt;/p&gt;
&lt;section class=&quot;level3&quot; id=&quot;construct-the-evidence-you-would-like-to-pattern-match-on&quot;&gt;
&lt;h3&gt;Construct the evidence you would like to pattern-match on&lt;/h3&gt;
&lt;p&gt;That’s the idea, but turning this into a verified constructive algorithm will take some
work. First, let’s formalize the idea of testing whether &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; is less
than &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt;, and decreasing it by &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt; if not. We’d rather not actually
deal with subtraction, so the idea is to generate either a proof that
&lt;span class=&quot;math inline&quot;&gt;\(n &amp;lt; d\)&lt;/span&gt;, or another number &lt;span class=&quot;math inline&quot;&gt;\(n'\)&lt;/span&gt; along with a proof that &lt;span class=&quot;math inline&quot;&gt;\(n' + d = n\)&lt;/span&gt;.
We encapsulate this in the following type &lt;code&gt;Cmp&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb63&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb63-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb63-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; Cmp &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n d &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb63-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb63-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  LT &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; n &amp;lt; d &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Cmp n d&lt;/span&gt;
&lt;span id=&quot;cb63-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb63-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  GE &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n′ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n′ + d ≡ n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Cmp n d&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;Cmp n d&lt;/code&gt; represents the result of comparing &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt;, and is
equivalent to having either &lt;span class=&quot;math inline&quot;&gt;\(n &amp;lt; d\)&lt;/span&gt; or &lt;span class=&quot;math inline&quot;&gt;\(n \geq d\)&lt;/span&gt;, but expressed in a
form that is more directly useful to us. &lt;strong&gt;Construct the evidence you
would like to pattern-match on!&lt;/strong&gt; That is, in general, evidence for a
proposition &lt;span class=&quot;math inline&quot;&gt;\(P\)&lt;/span&gt; can take many logically equivalent forms, and you
should pick the form that will make your life easiest at the &lt;em&gt;use
site&lt;/em&gt;, even if it means you have to work harder to &lt;em&gt;construct&lt;/em&gt; it in
the first place. You can write standalone lemmas for constructing
your evidence; but pattern-matching it will happen in the middle of
some bigger proof which ought not to be cluttered by calls to
conversion lemmas.&lt;/p&gt;
&lt;p&gt;To construct evidence for &lt;code&gt;Cmp n d&lt;/code&gt;, we write the function
&lt;code&gt;decreaseBy?&lt;/code&gt; which decides whether we can decrease &lt;code&gt;n&lt;/code&gt; by &lt;code&gt;d&lt;/code&gt; or not.
Writing this function is a bit more work than writing something
of type &lt;code&gt;(n d : ℕ) → (n &amp;lt; d) ⊎ (d ≤ n)&lt;/code&gt;, but our work will pay off later!&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb64&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb64-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb64-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;decreaseBy?&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n d &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Cmp n d&lt;/span&gt;
&lt;span id=&quot;cb64-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb64-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;zero decreaseBy? zero &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; GE &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb64-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb64-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;zero decreaseBy? suc d &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; LT &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle zle&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb64-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb64-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;suc n decreaseBy? zero &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; GE &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;((&lt;/span&gt;suc n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; +0&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb64-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb64-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;suc n decreaseBy? suc d &lt;span class=&quot;kw&quot;&gt;with&lt;/span&gt; n decreaseBy? d&lt;/span&gt;
&lt;span id=&quot;cb64-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb64-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;|&lt;/span&gt; LT n&amp;lt;d &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; LT &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle n&amp;lt;d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb64-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb64-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;|&lt;/span&gt; GE n′ n′+d≡n &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; GE n′ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n′ +suc d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc $≡ n′+d≡n&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can also write a helper function &lt;code&gt;incDivMod&lt;/code&gt; which encodes the
observation from before, that if &lt;span class=&quot;math inline&quot;&gt;\(r + qd = n-d\)&lt;/span&gt;, then &lt;span class=&quot;math inline&quot;&gt;\(r + (q+1)d =
n\)&lt;/span&gt;. Of course we don’t actually want to use subtraction, so instead
of writing &lt;span class=&quot;math inline&quot;&gt;\(n-d\)&lt;/span&gt;, we work in terms of an &lt;span class=&quot;math inline&quot;&gt;\(n'\)&lt;/span&gt; such that &lt;span class=&quot;math inline&quot;&gt;\(n' + d = n\)&lt;/span&gt;.
Proving this requires only some straightforward algebra.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb65&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb65-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb65-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;incDivMod &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;n′ n d q r &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; n′ + d ≡ n &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; DivMod n′ d q r &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; DivMod n d &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc q&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; r&lt;/span&gt;
&lt;span id=&quot;cb65-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb65-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;incDivMod &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;n′&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;n&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;d&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;q&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;r&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; n′+d≡n &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;DM r+qd≡n′ r&amp;lt;d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; DM r+d+qd≡n r&amp;lt;d&lt;/span&gt;
&lt;span id=&quot;cb65-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb65-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb65-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb65-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  r+d+qd≡n &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; r + &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;d + q * d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; ≡ n&lt;/span&gt;
&lt;span id=&quot;cb65-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb65-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  r+d+qd≡n &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; begin&lt;/span&gt;
&lt;span id=&quot;cb65-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb65-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    r + &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;d + q * d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;           ≡⟨ +-assoc r &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ]≡&lt;/span&gt;
&lt;span id=&quot;cb65-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb65-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;r + d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; + q * d           ≡[ &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;+&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; $≡ +-comm r &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ≡$ q * d ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb65-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb65-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;d + r&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; + q * d           ≡[ +-assoc d &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb65-9&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb65-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    d + &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;r + q * d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;           ≡[ d +&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; $≡ r+qd≡n′ ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb65-10&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb65-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    d + n′                    ≡[ +-comm d &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb65-11&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb65-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    n′ + d                    ≡[ n′+d≡n ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb65-12&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb65-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    n                         ∎&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now it seems like we have everything we need to write the division
algorithm as a recursive algorithm: given &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt;, check whether
&lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; can be decreased by &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt; or not. If not, we can return &lt;span class=&quot;math inline&quot;&gt;\(q = 0\)&lt;/span&gt; and
&lt;span class=&quot;math inline&quot;&gt;\(r = n\)&lt;/span&gt;. Otherwise, recurse on &lt;span class=&quot;math inline&quot;&gt;\(n - d\)&lt;/span&gt;, returning the same remainder
and an incremented quotient from whatever the recursive call returns, using
&lt;code&gt;incDivMod&lt;/code&gt; to discharge the proof obligation. It’s just a few lines
of code, right?&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb66&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb66-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb66-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;module&lt;/span&gt; DivModBad &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb66-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb66-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;pp&quot;&gt;{-# NON_TERMINATING #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb66-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  divAlg &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n d &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; DivAlg n d&lt;/span&gt;
&lt;span id=&quot;cb66-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb66-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  divAlg n d &lt;span class=&quot;kw&quot;&gt;with&lt;/span&gt; n decreaseBy? d&lt;/span&gt;
&lt;span id=&quot;cb66-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb66-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;|&lt;/span&gt; LT n&amp;lt;d &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; , n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; , &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;DM &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n +0&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; n&amp;lt;d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb66-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;|&lt;/span&gt; GE n′ n′+d≡n &lt;span class=&quot;kw&quot;&gt;with&lt;/span&gt; divAlg n′ d&lt;/span&gt;
&lt;span id=&quot;cb66-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb66-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;q , r&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; , dm &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc q , r&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; , &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;incDivMod n′+d≡n dm&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Well, as you can see, it &lt;em&gt;is&lt;/em&gt; just a few lines of code, but all is not
well: although this function typechecks, Agda can’t tell that it is
terminating! (I added the &lt;code&gt;NON_TERMINATING&lt;/code&gt; pragma so I could include
this bad version of &lt;code&gt;divAlg&lt;/code&gt; in the code without causing an error.)
The problem is that the recursive call to &lt;code&gt;divAlg&lt;/code&gt; is on &lt;code&gt;n′&lt;/code&gt;,
which is not a subterm of &lt;code&gt;n&lt;/code&gt;, but instead comes from the call to
&lt;code&gt;decreaseBy?&lt;/code&gt;. Agda has no way of knowing whether the result from
some random function call is going to end up being smaller than the
original input.&lt;/p&gt;
&lt;p&gt;Now, you and I can both see that this function does indeed terminate,
but we just need a way to convince Agda of this fact… right?&lt;/p&gt;
&lt;p&gt;…have you spotted the flaw? Remember how I mentioned that the type &lt;code&gt;(n d : ℕ) → DivAlg n d&lt;/code&gt; is not quite right? In fact, the above bad
implementation of &lt;code&gt;divMod&lt;/code&gt; is &lt;em&gt;not&lt;/em&gt; terminating, and Agda is quite right to
be worried! In particular, the function recurses infinitely when given an input of &lt;span class=&quot;math inline&quot;&gt;\(d
= 0\)&lt;/span&gt;, since it will keep subtracting &lt;span class=&quot;math inline&quot;&gt;\(0\)&lt;/span&gt; from &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; forever. This makes sense, of
course: everyone knows you can’t divide by zero &lt;em&gt;because it makes the
universe go into infinite recursion&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The correct type for &lt;code&gt;divAlg&lt;/code&gt; is &lt;code&gt;(n d : ℕ) → (0 &amp;lt; d) → DivAlg n d&lt;/code&gt;,
but we’re still going to have trouble convincing Agda that our
algorithm is terminating. In order to do so, we need to take a detour
through &lt;em&gt;well-founded induction&lt;/em&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section class=&quot;level2&quot; id=&quot;well-founded-induction&quot;&gt;
&lt;h2&gt;Well-founded induction&lt;/h2&gt;
&lt;p&gt;Normally, Agda only allows functions that are &lt;em&gt;structurally
recursive&lt;/em&gt;—that is, functions which make recursive calls on syntactic
subterms of their inputs. (Agda’s termination checking is a bit more
sophisticated than that, but that’s the basic idea.) However, we can
use basic structural induction to bootstrap our way into more exotic
forms. In particular, we are going to define something called
&lt;em&gt;well-founded induction&lt;/em&gt;.&lt;span class=&quot;sidenote-wrapper&quot;&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;sn-6&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;sn-6&quot; type=&quot;checkbox&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;Note that I will use the terms “recursion”
and “induction” more or less interchangeably. In some contexts, people
make a distinction between the terms (typically a &lt;em&gt;recursion
principle&lt;/em&gt; is a less-dependently-typed version of an &lt;em&gt;induction
principle&lt;/em&gt;), but in this context, &lt;em&gt;inductive proofs&lt;/em&gt; correspond, via
Curry-Howard, to (suitably restricted) &lt;em&gt;recursive functions&lt;/em&gt;, so
“induction” and “recursion” describe the same thing from a logical and
computational viewpoint, respectively.&lt;br /&gt;
&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The idea of well-founded induction starts with the general idea of a
&lt;em&gt;relation&lt;/em&gt;. A relation on &lt;code&gt;A&lt;/code&gt; is just a function that takes two
values of type &lt;code&gt;A&lt;/code&gt; and produces a type, representing evidence that the
two values are related (according to whatever kind of relationship we
have in mind).&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb67&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb67-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb67-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;Rel &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set₁&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb67-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;Rel A &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; A &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; A &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We have already seen quite a few relations, such as equality, &lt;span class=&quot;math inline&quot;&gt;\(&amp;lt;\)&lt;/span&gt;,
&lt;span class=&quot;math inline&quot;&gt;\(\leq\)&lt;/span&gt;, and divisibility.&lt;/p&gt;
&lt;p&gt;Suppose we’re writing a recursive function, with some relation &lt;span class=&quot;math inline&quot;&gt;\(\prec\)&lt;/span&gt;
in mind, and for a given input &lt;span class=&quot;math inline&quot;&gt;\(x\)&lt;/span&gt; we’re only allowed to make
recursive calls on values &lt;span class=&quot;math inline&quot;&gt;\(y\)&lt;/span&gt; such that &lt;span class=&quot;math inline&quot;&gt;\(y \prec x\)&lt;/span&gt;. If &lt;span class=&quot;math inline&quot;&gt;\(\prec\)&lt;/span&gt; is the
“is a syntactic subterm of” relation, then we get structural
recursion as usual. But what if &lt;span class=&quot;math inline&quot;&gt;\(\prec\)&lt;/span&gt; is some other relation? What
needs to be true about &lt;span class=&quot;math inline&quot;&gt;\(\prec\)&lt;/span&gt; for this to make sense? In particular, how
can we be sure that the function won’t get stuck in infinite recursion?&lt;/p&gt;
&lt;p&gt;One’s first instinct might be to say that &lt;span class=&quot;math inline&quot;&gt;\(y \prec x\)&lt;/span&gt; needs to imply that
&lt;span class=&quot;math inline&quot;&gt;\(y\)&lt;/span&gt; is “smaller than” &lt;span class=&quot;math inline&quot;&gt;\(x\)&lt;/span&gt; somehow. But what does “smaller than” mean?
And in fact, “smaller than” doesn’t always work: for example, if we are
writing a function over the rational numbers, or even just the
integers, the usual “smaller than” relation does &lt;em&gt;not&lt;/em&gt; guarantee our
function will terminate; it’s possible to continue choosing smaller
and smaller rational numbers or integers forever.&lt;/p&gt;
&lt;p&gt;The key idea is exactly that this can’t happen: it’s not possible to
have an infinite chain of values where each is related to the
previous. That is, there should be no left-infinite chains &lt;span class=&quot;math inline&quot;&gt;\(\dots
\prec y_3 \prec y_2 \prec y_1 \prec x\)&lt;/span&gt;. Then we are guaranteed that if we keep making
recursive calls on values that are related by &lt;span class=&quot;math inline&quot;&gt;\(\prec\)&lt;/span&gt; to the previous
value, we will have to stop eventually: after some finite number of calls
we will hit a value with nothing else related to it.&lt;/p&gt;
&lt;p&gt;A relation &lt;span class=&quot;math inline&quot;&gt;\(\prec\)&lt;/span&gt; with this “no left-infinite chains” property is
called &lt;em&gt;well-founded&lt;/em&gt;. But how do we encode this idea in Agda?&lt;/p&gt;
&lt;section class=&quot;level3&quot; id=&quot;accessibility&quot;&gt;
&lt;h3&gt;Accessibility&lt;/h3&gt;
&lt;p&gt;Instead of thinking negatively (&lt;em&gt;no&lt;/em&gt; left-infinite
chains), the key is to think positively: &lt;em&gt;all&lt;/em&gt; chains to the left of
&lt;em&gt;every&lt;/em&gt; value are finite. Call a value &lt;em&gt;accessible&lt;/em&gt; if all chains
leading to it are finite. Another way to say this is that a value is
accessible if every value related to it is also accessible:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb68&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb68-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb68-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; Acc &lt;span class=&quot;ot&quot;&gt;(_&lt;/span&gt;≺&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; Rel A&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb68-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb68-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  acc &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;((&lt;/span&gt;y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; y ≺ x &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Acc &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≺&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Acc &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≺&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; x&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;Acc _≺_ x&lt;/code&gt; defines what it means for a particular value &lt;code&gt;x&lt;/code&gt; to be
accessible with respect to a relation &lt;span class=&quot;math inline&quot;&gt;\(\prec\)&lt;/span&gt;. There is only one
constructor, &lt;code&gt;acc&lt;/code&gt;, which requires &lt;code&gt;(y : A) → y ≺ x → Acc _≺_ y&lt;/code&gt;—that
is, for every value &lt;code&gt;y&lt;/code&gt; of type &lt;code&gt;A&lt;/code&gt;, if &lt;code&gt;y&lt;/code&gt; is related to &lt;code&gt;x&lt;/code&gt;, then
&lt;code&gt;y&lt;/code&gt; is accessible. In other words, &lt;code&gt;x&lt;/code&gt; is accessible if and only if every &lt;code&gt;y ≺ x&lt;/code&gt;
is accessible.&lt;/p&gt;
&lt;p&gt;This is definitely tricky to wrap your head around! At this point
you may have two objections:&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;&lt;p&gt;What about base cases? Shouldn’t we have another constructor which
says &lt;code&gt;x&lt;/code&gt; is accessible if &lt;em&gt;nothing&lt;/em&gt; is related to it? Actually,
the &lt;code&gt;acc&lt;/code&gt; constructor already says that! If nothing is related to
&lt;code&gt;x&lt;/code&gt;, then &lt;code&gt;(y : A) → y ≺ x → Acc _≺_ y&lt;/code&gt; is trivially true: we can
easily promise anything we want as the output of a function if we
know it can never be called. Every natural number less than zero is a
purple flying weasel.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Doesn’t this just run into the same problem as before with
left-infinite chains? If we consider the “is one less than”
relation on the integers, isn’t &lt;span class=&quot;math inline&quot;&gt;\(2\)&lt;/span&gt; accessible because &lt;span class=&quot;math inline&quot;&gt;\(1\)&lt;/span&gt; is
accessible because &lt;span class=&quot;math inline&quot;&gt;\(0\)&lt;/span&gt; is accessible because &lt;span class=&quot;math inline&quot;&gt;\(-1\)&lt;/span&gt; is accessible
because … ?&lt;/p&gt;
&lt;p&gt;There is something a bit subtle going on here: recursive data types
in Agda (unlike Haskell) are interpreted according to a
&lt;em&gt;least fixed point&lt;/em&gt; semantics. Put in plain terms, the only values
of a data type are those which can be built by applications of a
&lt;em&gt;finite&lt;/em&gt; number of constructors. So in fact, the “no left-infinite
chain” condition is foundationally built into the way Agda data
types work!&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The idea is that we can turn well-founded induction into structural
induction by &lt;em&gt;pattern-matching on &lt;code&gt;Acc&lt;/code&gt; proofs&lt;/em&gt;! Starting with some
&lt;span class=&quot;math inline&quot;&gt;\(x\)&lt;/span&gt;, any &lt;span class=&quot;math inline&quot;&gt;\(y \prec x\)&lt;/span&gt; has an accessibility proof which is a subterm of
the accessibility proof for &lt;span class=&quot;math inline&quot;&gt;\(x\)&lt;/span&gt;. This is a bit exotic though: if we
pattern-match on the &lt;code&gt;acc&lt;/code&gt; for &lt;span class=&quot;math inline&quot;&gt;\(x\)&lt;/span&gt; we get a &lt;em&gt;function&lt;/em&gt; that yields an
accessibility proof for each &lt;span class=&quot;math inline&quot;&gt;\(y \prec x\)&lt;/span&gt;; calling that function
produces another accessibility proof, which &lt;em&gt;counts as a structural
subterm of the original&lt;/em&gt;. This seems a bit strange until you think of
a value of type &lt;code&gt;Acc&lt;/code&gt; like an big, arbitrarily-branching tree of
finite depth; each node contains a function which really just stores
all the subtrees. In other words, a function of type &lt;code&gt;(y : A) → y ≺ x → Acc _≺_ y&lt;/code&gt; can be thought of as a giant tuple of &lt;code&gt;Acc&lt;/code&gt; values, one
for each &lt;code&gt;y \prec x&lt;/code&gt;.&lt;span class=&quot;sidenote-wrapper&quot;&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;sn-7&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;sn-7&quot; type=&quot;checkbox&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;I am not sure exactly how Agda handles this
internally, but I assume this is well-trodden ground for designers of
proof assistants.&lt;br /&gt;
&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;section class=&quot;level3&quot; id=&quot;well-founded-induction-defined&quot;&gt;
&lt;h3&gt;Well-founded induction, defined&lt;/h3&gt;
&lt;p&gt;Given the definition of accessible elements, we can now give the
definition of a well-founded relation: a relation on &lt;code&gt;A&lt;/code&gt; is well-founded if
&lt;em&gt;every&lt;/em&gt; value of type &lt;code&gt;A&lt;/code&gt; is accessible.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb69&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb69-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb69-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;WellFounded &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; Rel A &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb69-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb69-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;WellFounded &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;A&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≺&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;a &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Acc &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≺&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; a&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can now write down the &lt;em&gt;principle of well-founded induction&lt;/em&gt;. This
is also quite tricky to wrap your brain around, so we’ll go through it
slowly. Previously, we were just talking about whether functions terminated or
not; but the reason this is important is that a function might be
calculating a &lt;em&gt;proof&lt;/em&gt;. A function which purports to calculate a proof
but sometimes goes into infinite recursion is a charlatan, and not
really a proof at all.&lt;/p&gt;
&lt;p&gt;So instead of thinking about termination, let’s switch to thinking
about proofs. Given a proposition &lt;span class=&quot;math inline&quot;&gt;\(P\)&lt;/span&gt;, we want to prove that
&lt;span class=&quot;math inline&quot;&gt;\(P\)&lt;/span&gt; holds for every value of type &lt;span class=&quot;math inline&quot;&gt;\(A\)&lt;/span&gt;. The idea is that when trying to
prove &lt;span class=&quot;math inline&quot;&gt;\(P(y)\)&lt;/span&gt; for a particular &lt;span class=&quot;math inline&quot;&gt;\(y\)&lt;/span&gt;, we get to assume that &lt;span class=&quot;math inline&quot;&gt;\(P(z)\)&lt;/span&gt; holds
(&lt;em&gt;i.e.&lt;/em&gt; we get to make recursive calls) for all &lt;span class=&quot;math inline&quot;&gt;\(z \prec y\)&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Here, then, is the statement of the principle of well-founded induction, with
each argument broken out on a separate line so we can explain them as
we go.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb70&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb70-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb70-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;wf-ind &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb70-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb70-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;P &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;P&lt;/code&gt; represents an arbitrary proposition on &lt;code&gt;A&lt;/code&gt;; our goal is to show &lt;code&gt;P&lt;/code&gt; holds for
every value of type &lt;code&gt;A&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb71&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb71-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb71-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;{_&lt;/span&gt;≺&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; Rel A&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;An arbitrary relation.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb72&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb72-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb72-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  WellFounded &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≺&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;A proof that &lt;code&gt;≺&lt;/code&gt; is a well-founded relation.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb73&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb73-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb73-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;((&lt;/span&gt;y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;((&lt;/span&gt;z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; z ≺ y &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; P z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; P y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;This is the trickiest
argument to understand. Intuitively, it says “For any
&lt;code&gt;y&lt;/code&gt;, if we know &lt;code&gt;P z&lt;/code&gt; holds for all &lt;code&gt;z ≺ y&lt;/code&gt;, then we can show &lt;code&gt;P y&lt;/code&gt;
also holds.”&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb74&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb74-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb74-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; P x&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;The principle of well-founded induction says that all of this is
enough to show that &lt;code&gt;P x&lt;/code&gt; holds for &lt;em&gt;all&lt;/em&gt; &lt;code&gt;x : A&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, how do we implement this? If we try something
straightforward, as in &lt;code&gt;wf-ind-bad&lt;/code&gt; below—just call &lt;code&gt;ind&lt;/code&gt; on &lt;code&gt;x&lt;/code&gt;, then call &lt;code&gt;wf-ind&lt;/code&gt; recursively
to fill in the proofs for &lt;code&gt;P z&lt;/code&gt;—of course it does not work; Agda cannot
tell that this is terminating.&lt;span class=&quot;sidenote-wrapper&quot;&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;sn-8&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;sn-8&quot; type=&quot;checkbox&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;As an aside, Agda complains that this definition of &lt;code&gt;wf-ind-bad&lt;/code&gt;
is not terminating—which makes sense—but it continues to complain even
when I include the &lt;code&gt;NON_TERMINATING&lt;/code&gt; pragma, which I don’t
understand. Perhaps this has been fixed in a more recent version of Agda.&lt;br /&gt;
&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt; And this makes sense, because we are
not even using the fact that the relation is well-founded at all!&lt;/p&gt;
&lt;pre class=&quot;plain&quot;&gt;&lt;code&gt;module WFIndBad where

  {-# NON_TERMINATING #-}
  wf-ind-bad : {P : A → Set} {_≺_ : Rel A} → WellFounded _≺_ → ((y : A) → ((z : A) → z ≺ y → P z) → P y) → (x : A) → P x
  wf-ind-bad wf ind x = ind x (λ z Rzx → wf-ind-bad wf ind z)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Instead, the right idea is to use the fact that &lt;span class=&quot;math inline&quot;&gt;\(\prec\)&lt;/span&gt; is
well-founded to generate an initial proof of accessibility for the
input &lt;span class=&quot;math inline&quot;&gt;\(x\)&lt;/span&gt;, and then &lt;em&gt;pattern match on accessibility proofs&lt;/em&gt; alongside
the values as we recurse. Every time we make a recursive call on some
&lt;span class=&quot;math inline&quot;&gt;\(y \prec x\)&lt;/span&gt;, we can just pattern-match on the accessibility proof for
&lt;span class=&quot;math inline&quot;&gt;\(x\)&lt;/span&gt; to get an accessibility proof for &lt;span class=&quot;math inline&quot;&gt;\(y\)&lt;/span&gt;, so Agda will be able to see
that the whole thing is &lt;em&gt;structurally&lt;/em&gt; recursive on the accessibility
proofs.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb76&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb76-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb76-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;wf-ind &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;A&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;P&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{_&lt;/span&gt;≺&lt;span class=&quot;ot&quot;&gt;_}&lt;/span&gt; wf ind x &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; go x &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;wf x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb76-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb76-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb76-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb76-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  go &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Acc &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≺&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; x &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; P x&lt;/span&gt;
&lt;span id=&quot;cb76-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb76-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  go x &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;acc f&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ind x &lt;span class=&quot;ot&quot;&gt;(λ&lt;/span&gt; z z≺x &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; go z &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;f z z≺x&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;level3&quot; id=&quot;less-than-is-well-founded&quot;&gt;
&lt;h3&gt;Less-than is well-founded&lt;/h3&gt;
&lt;p&gt;Now that we have well-founded induction under our belts, let’s show
that the less-than relation on natural numbers is well-founded. This
corresponds to what is often called “strong induction”.&lt;span class=&quot;sidenote-wrapper&quot;&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;sn-9&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;sn-9&quot; type=&quot;checkbox&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;Incidentally,
we could probably have gotten away with directly defining a principle
of strong natural number induction, without bothering with the full
generality of well-founded induction, but this way is more fun and
interesting!&lt;br /&gt;
&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt; To prove that &lt;span class=&quot;math inline&quot;&gt;\(&amp;lt;\)&lt;/span&gt; is well-founded, we of course must
show that every natural number is accessible under &lt;span class=&quot;math inline&quot;&gt;\(&amp;lt;\)&lt;/span&gt;. However, if
we directly try to prove &lt;code&gt;(m : ℕ) → (Acc _&amp;lt;_) m&lt;/code&gt;, we run into a
variant of the exact same problem we have been dealing with: to prove
that &lt;span class=&quot;math inline&quot;&gt;\(m\)&lt;/span&gt; is accessible we need to know that &lt;em&gt;every&lt;/em&gt; &lt;span class=&quot;math inline&quot;&gt;\(k &amp;lt; m\)&lt;/span&gt; is also
accessible, but again, we cannot show this directly by
recursion/induction, since &lt;span class=&quot;math inline&quot;&gt;\(k\)&lt;/span&gt; may not be a structural subterm of &lt;span class=&quot;math inline&quot;&gt;\(m\)&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;What we need is the usual trick for proving strong induction from weak
induction: instead of proving that &lt;span class=&quot;math inline&quot;&gt;\(P(x)\)&lt;/span&gt; holds for all &lt;span class=&quot;math inline&quot;&gt;\(x\)&lt;/span&gt;, we prove
that &lt;span class=&quot;math inline&quot;&gt;\((\downarrow P)(x)\)&lt;/span&gt; holds for all &lt;span class=&quot;math inline&quot;&gt;\(x\)&lt;/span&gt;, where &lt;span class=&quot;math inline&quot;&gt;\(\downarrow P\)&lt;/span&gt; is
the “downward closure” of &lt;span class=&quot;math inline&quot;&gt;\(P\)&lt;/span&gt;. That is, &lt;span class=&quot;math inline&quot;&gt;\((\downarrow P)(x)\)&lt;/span&gt; says that
&lt;span class=&quot;math inline&quot;&gt;\(P(x)\)&lt;/span&gt; holds for &lt;em&gt;all&lt;/em&gt; &lt;span class=&quot;math inline&quot;&gt;\(y &amp;lt; x\)&lt;/span&gt;.&lt;span class=&quot;sidenote-wrapper&quot;&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;sn-10&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;sn-10&quot; type=&quot;checkbox&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;Note that another way to define
&lt;span class=&quot;math inline&quot;&gt;\((\downarrow P)(x)\)&lt;/span&gt; is that &lt;span class=&quot;math inline&quot;&gt;\(P(y)\)&lt;/span&gt; holds for all &lt;span class=&quot;math inline&quot;&gt;\(y \sim x\)&lt;/span&gt;, where &lt;span class=&quot;math inline&quot;&gt;\(\sim\)&lt;/span&gt;
is the &lt;em&gt;transitive closure&lt;/em&gt; of the predecessor relation. As an
advanced exercise, generalize &lt;span class=&quot;math inline&quot;&gt;\(\downarrow_\prec P\)&lt;/span&gt; to be defined relative to
the transitive closure of any relation &lt;span class=&quot;math inline&quot;&gt;\(\prec\)&lt;/span&gt;, and then prove that &lt;span class=&quot;math inline&quot;&gt;\(\prec\)&lt;/span&gt; is well-founded
if and only if its transitive closure is. For more along
these lines, see this &lt;a href=&quot;https://boarders.github.io/posts/well_founded_induction.html&quot;&gt;very cool (but much more abstract) post on
well-founded induction by Callan McGill&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb77&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb77-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb77-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;↓ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb77-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;↓ P n &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;k &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;k &amp;lt; n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; P k&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we can prove, for all natural numbers &lt;span class=&quot;math inline&quot;&gt;\(m\)&lt;/span&gt;, that every natural
number up to and including &lt;span class=&quot;math inline&quot;&gt;\(m\)&lt;/span&gt; is accessible under the &lt;span class=&quot;math inline&quot;&gt;\(&amp;lt;\)&lt;/span&gt; relation. Zero is accessible
because nothing is less than it; everything up to the successor of &lt;span class=&quot;math inline&quot;&gt;\(m\)&lt;/span&gt; is accessible because by induction we know everything up to &lt;span class=&quot;math inline&quot;&gt;\(m\)&lt;/span&gt; is, and anything less than the successor of &lt;span class=&quot;math inline&quot;&gt;\(m\)&lt;/span&gt; must in fact be &lt;span class=&quot;math inline&quot;&gt;\(\leq m\)&lt;/span&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb78&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb78-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb78-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&amp;lt;-acc &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;m &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ↓ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;Acc &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&amp;lt;&lt;span class=&quot;ot&quot;&gt;_)&lt;/span&gt; m&lt;/span&gt;
&lt;span id=&quot;cb78-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb78-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&amp;lt;-acc zero &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;λ&lt;/span&gt; k &lt;span class=&quot;ot&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb78-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb78-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&amp;lt;-acc &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc m&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; zero &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle le&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; acc &lt;span class=&quot;ot&quot;&gt;(λ&lt;/span&gt; y &lt;span class=&quot;ot&quot;&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb78-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb78-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&amp;lt;-acc &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc m&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc k&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle le&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; acc &lt;span class=&quot;ot&quot;&gt;(λ&lt;/span&gt; y y&amp;lt;sk &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &amp;lt;-acc m y &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;&amp;lt;-≤-trans y&amp;lt;sk le&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally, to show that any natural number &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; is accessible—&lt;em&gt;i.e.&lt;/em&gt; that &lt;span class=&quot;math inline&quot;&gt;\(&amp;lt;\)&lt;/span&gt;
is well-founded—we can use the fact that all numbers less than the successor of &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt;
are accessible, and just project out accessibility for &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; itself.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb79&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb79-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb79-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&amp;lt;-wf &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; WellFounded &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&amp;lt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb79-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb79-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&amp;lt;-wf n &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &amp;lt;-acc &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; n &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n &amp;lt;suc&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section class=&quot;level2&quot; id=&quot;the-division-algorithm&quot;&gt;
&lt;h2&gt;The division algorithm&lt;/h2&gt;
&lt;p&gt;Finally, we can define the division algorithm, via well-founded
induction! The definition is very similar to our first attempt, but we use the principle of well-founded induction with &lt;span class=&quot;math inline&quot;&gt;\(&amp;lt;\)&lt;/span&gt;. Note that neither &lt;code&gt;divAlg&lt;/code&gt; nor its helper function &lt;code&gt;go&lt;/code&gt; is directly recursive. Instead, &lt;code&gt;go&lt;/code&gt; takes an induction hypothesis as an argument, which we call instead, providing an extra proof that the subject of the induction hypothesis is in fact less than the original input. &lt;code&gt;wf-ind&lt;/code&gt; takes care of the actual recursion.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb80&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb80-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb80-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;divAlg &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n d &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; &amp;lt; d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; DivAlg n d&lt;/span&gt;
&lt;span id=&quot;cb80-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb80-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;divAlg n d 0&amp;lt;d &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; wf-ind &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;P &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;λ&lt;/span&gt; n &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; DivAlg n d&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &amp;lt;-wf go n&lt;/span&gt;
&lt;span id=&quot;cb80-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb80-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb80-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb80-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  go &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;((&lt;/span&gt;n′ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; n′ &amp;lt; n &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; DivAlg n′ d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; DivAlg n d&lt;/span&gt;
&lt;span id=&quot;cb80-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb80-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  go n IH &lt;span class=&quot;kw&quot;&gt;with&lt;/span&gt; n decreaseBy? d&lt;/span&gt;
&lt;span id=&quot;cb80-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb80-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;|&lt;/span&gt; LT n&amp;lt;d &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; , n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; , DM &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n +0&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; n&amp;lt;d&lt;/span&gt;
&lt;span id=&quot;cb80-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb80-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;|&lt;/span&gt; GE n′ n′+d≡n &lt;span class=&quot;kw&quot;&gt;with&lt;/span&gt; IH n′ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;+→&amp;lt; 0&amp;lt;d n′+d≡n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb80-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb80-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;q , r&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; , dm &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc q , r&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; , incDivMod n′+d≡n dm&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Using the division algorithm, we can also finally decide whether one
number divides another: zero divides zero; zero does not divide any
successor since that would imply there is some &lt;span class=&quot;math inline&quot;&gt;\(k\)&lt;/span&gt; such that &lt;span class=&quot;math inline&quot;&gt;\(k\)&lt;/span&gt; times
zero is nonzero, which is absurd; and if &lt;span class=&quot;math inline&quot;&gt;\(x\)&lt;/span&gt; is a successor, we can
apply the division algorithm and check the remainder, applying some
previous lemmas that say what zero and nonzero remainders tells us
about divisibility.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb81&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb81-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb81-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;∣?&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Dec &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x ∣ y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb81-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb81-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;zero ∣? zero &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; yes &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; , refl&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb81-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb81-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;zero ∣? &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; no &lt;span class=&quot;ot&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;a , eq&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; absurd &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;noConf &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sym &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;*-comm a zero&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt; eq&lt;span class=&quot;ot&quot;&gt;))}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb81-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb81-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; ∣? y &lt;span class=&quot;kw&quot;&gt;with&lt;/span&gt; divAlg y &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle zle&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb81-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb81-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;q , zero&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; , dm &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; yes &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;mod0→divides y &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; dm&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb81-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb81-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;q , suc r&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; , dm &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; no &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;modS→¬divides y &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; dm&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;level2&quot; id=&quot;primality-testing&quot;&gt;
&lt;h2&gt;Primality testing&lt;/h2&gt;
&lt;p&gt;To test a number for primality, we are just going to use
straightforward, naive trial division. The straightforward way of
doing this is by starting at &lt;span class=&quot;math inline&quot;&gt;\(2\)&lt;/span&gt; and counting &lt;em&gt;up&lt;/em&gt;—but this is a
problem, because when pattern-matching on natural numbers we most
naturally count &lt;em&gt;down&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Well, remember—build the evidence you want to pattern-match on! Let’s
develop some machinery for counting up instead of down.&lt;/p&gt;
&lt;section class=&quot;level3&quot; id=&quot;counting-up&quot;&gt;
&lt;h3&gt;Counting up&lt;/h3&gt;
&lt;p&gt;The problem starts with &lt;span class=&quot;math inline&quot;&gt;\(\leq\)&lt;/span&gt;: a proof of &lt;span class=&quot;math inline&quot;&gt;\(m \leq n\)&lt;/span&gt; starts with a
base case representing evidence that &lt;span class=&quot;math inline&quot;&gt;\(0 \leq k\)&lt;/span&gt;, then every
constructor application of &lt;code&gt;sle&lt;/code&gt; increments both sides by one.
Pattern-matching on a proof of &lt;span class=&quot;math inline&quot;&gt;\(m \leq n\)&lt;/span&gt; thus either reveals that &lt;span class=&quot;math inline&quot;&gt;\(m
= 0\)&lt;/span&gt;, or that &lt;span class=&quot;math inline&quot;&gt;\(m' \leq n'\)&lt;/span&gt; where &lt;span class=&quot;math inline&quot;&gt;\(m'\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(n'\)&lt;/span&gt; are the predecessors of
&lt;span class=&quot;math inline&quot;&gt;\(m\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt;: in other words, it facilitates counting &lt;em&gt;down&lt;/em&gt;, just
like matching directly on &lt;span class=&quot;math inline&quot;&gt;\(m\)&lt;/span&gt; would.&lt;/p&gt;
&lt;p&gt;However, there is an alternative way to define the &lt;span class=&quot;math inline&quot;&gt;\(\leq\)&lt;/span&gt; relation,
which we will call &lt;span class=&quot;math inline&quot;&gt;\(\leq'\)&lt;/span&gt;.
We can choose &lt;em&gt;reflexivity&lt;/em&gt; of &lt;span class=&quot;math inline&quot;&gt;\(\leq'\)&lt;/span&gt; as a base case, that is, &lt;span class=&quot;math inline&quot;&gt;\(n \leq'
n\)&lt;/span&gt; for any &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt;. We can then &lt;em&gt;decrement&lt;/em&gt; the left-hand side every time
we apply another constructor. Like so:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb82&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb82-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb82-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≤′&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb82-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb82-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  lerefl &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;n &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; n ≤′ n&lt;/span&gt;
&lt;span id=&quot;cb82-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb82-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  lesuc &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;m n &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; suc m ≤′ n &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; m ≤′ n&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Pattern-matching on a proof of &lt;span class=&quot;math inline&quot;&gt;\(m \leq' n\)&lt;/span&gt; thus facilitates counting
&lt;em&gt;up&lt;/em&gt; from &lt;span class=&quot;math inline&quot;&gt;\(m\)&lt;/span&gt; to &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt;, just like we wanted!&lt;/p&gt;
&lt;p&gt;We can also prove a few lemmas about properties of &lt;span class=&quot;math inline&quot;&gt;\(\leq'\)&lt;/span&gt;. For
example, the two axioms that define the usual &lt;span class=&quot;math inline&quot;&gt;\(\leq\)&lt;/span&gt; can be proved as
lemmas.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb83&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb83-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb83-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤′-suc &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;m n &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; m ≤′ n &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; suc m ≤′ suc n&lt;/span&gt;
&lt;span id=&quot;cb83-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb83-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤′-suc lerefl &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; lerefl&lt;/span&gt;
&lt;span id=&quot;cb83-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb83-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤′-suc &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;lesuc m≤′n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; lesuc &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;≤′-suc m≤′n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb83-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb83-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb83-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb83-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;0≤′ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; ≤′ n&lt;/span&gt;
&lt;span id=&quot;cb83-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb83-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;0≤′ zero &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; lerefl&lt;/span&gt;
&lt;span id=&quot;cb83-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb83-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;0≤′ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; lesuc &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;≤′-suc &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;0≤′ n&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can also prove that &lt;span class=&quot;math inline&quot;&gt;\(m \leq n\)&lt;/span&gt; implies &lt;span class=&quot;math inline&quot;&gt;\(m \leq' n\)&lt;/span&gt;. (The converse
is true as well, and can be proved as an easy exercise, but we won’t need it.)&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb84&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb84-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb84-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤→≤′ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;m n &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; m ≤ n &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; m ≤′ n&lt;/span&gt;
&lt;span id=&quot;cb84-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb84-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤→≤′ &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;n &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; n&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; zle &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; 0≤′ n&lt;/span&gt;
&lt;span id=&quot;cb84-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb84-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤→≤′ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle m≤n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ≤′-suc &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;≤→≤′ m≤n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So, we can pattern-match on a proof of &lt;span class=&quot;math inline&quot;&gt;\(m \leq' n\)&lt;/span&gt; to count up from &lt;span class=&quot;math inline&quot;&gt;\(m\)&lt;/span&gt; to
&lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt;, but this isn’t quite good enough: while counting, we won’t remember the relationship of the
intermediate values to the original &lt;span class=&quot;math inline&quot;&gt;\(m\)&lt;/span&gt;. We would like to be able to
count up through some interval, from some starting &lt;span class=&quot;math inline&quot;&gt;\(a\)&lt;/span&gt; to ending &lt;span class=&quot;math inline&quot;&gt;\(b\)&lt;/span&gt;,
knowing all along the way that the values we count are contained in
the interval.&lt;/p&gt;
&lt;p&gt;To this end, we can create a data
type &lt;code&gt;i ∈[ a ⋯ b ]&lt;/code&gt; which represents a stage in counting from &lt;span class=&quot;math inline&quot;&gt;\(a\)&lt;/span&gt; to
&lt;span class=&quot;math inline&quot;&gt;\(b\)&lt;/span&gt;. The base case is when &lt;span class=&quot;math inline&quot;&gt;\(i = b\)&lt;/span&gt;; otherwise &lt;code&gt;i ∈[ a ⋯ b ]&lt;/code&gt; when &lt;span class=&quot;math inline&quot;&gt;\(a
\leq i\)&lt;/span&gt; and also &lt;code&gt;suc i ∈[ a ⋯ b ]&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb85&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb85-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb85-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;∈[&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;⋯&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;] &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb85-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb85-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  stop &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;a b &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; a ≤ b &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; b ∈[ a ⋯ b ]&lt;/span&gt;
&lt;span id=&quot;cb85-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb85-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  step &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;a i b &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; a ≤ i &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; suc i ∈[ a ⋯ b ] &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; i ∈[ a ⋯ b ]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can then write a function which “constructs a loop”—that is,
starting from a proof of &lt;span class=&quot;math inline&quot;&gt;\(a \leq' b\)&lt;/span&gt;, it builds
a value of type &lt;code&gt;a ∈[ a ⋯ b ]&lt;/code&gt; which represents a reified loop from
&lt;span class=&quot;math inline&quot;&gt;\(a\)&lt;/span&gt; to &lt;span class=&quot;math inline&quot;&gt;\(b\)&lt;/span&gt;. By pattern-matching on this value we can successively
increment from &lt;span class=&quot;math inline&quot;&gt;\(a\)&lt;/span&gt; up to &lt;span class=&quot;math inline&quot;&gt;\(b\)&lt;/span&gt;, with the appropriate guarantees along
the way.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb86&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb86-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb86-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;loop &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;a b &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;a ≤′ b&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; a ∈[ a ⋯ b ]&lt;/span&gt;
&lt;span id=&quot;cb86-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb86-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;loop a b a≤′b &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; mid a a b ≤-refl a≤′b&lt;/span&gt;
&lt;span id=&quot;cb86-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb86-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb86-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb86-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  mid &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;a i b &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;a ≤ i&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;i ≤′ b&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; i ∈[ a ⋯ b ]&lt;/span&gt;
&lt;span id=&quot;cb86-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb86-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  mid a i b a≤i lerefl &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; stop a≤i&lt;/span&gt;
&lt;span id=&quot;cb86-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb86-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  mid a i b a≤i &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;lesuc i≤′b&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; step a≤i &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;mid a &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc i&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;≤-sucr a≤i&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; i≤′b&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally, we need as a simple lemma the fact that if &lt;code&gt;i ∈[ a ⋯ b ]&lt;/code&gt;
then in fact &lt;span class=&quot;math inline&quot;&gt;\(i \leq b\)&lt;/span&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb87&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb87-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb87-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;top &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;i a b &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; i ∈[ a ⋯ b ] &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; i ≤ b&lt;/span&gt;
&lt;span id=&quot;cb87-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb87-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;top &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;stop &lt;span class=&quot;ot&quot;&gt;_)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ≤-refl&lt;/span&gt;
&lt;span id=&quot;cb87-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb87-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;top &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;step &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; s&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ≤-sucl &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;top s&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;level3&quot; id=&quot;primality-testing-by-trial-division&quot;&gt;
&lt;h3&gt;Primality testing by trial division&lt;/h3&gt;
&lt;p&gt;First, a lemma about downward closure: if we know &lt;span class=&quot;math inline&quot;&gt;\((\downarrow P)(m)\)&lt;/span&gt;,
and we know &lt;span class=&quot;math inline&quot;&gt;\(P(m)\)&lt;/span&gt;, then we know &lt;span class=&quot;math inline&quot;&gt;\((\downarrow P)(1 + m)\)&lt;/span&gt;. In other
words, if &lt;span class=&quot;math inline&quot;&gt;\(P\)&lt;/span&gt; holds for everything less than &lt;span class=&quot;math inline&quot;&gt;\(m\)&lt;/span&gt;, we can extend it by
one by providing a proof that &lt;span class=&quot;math inline&quot;&gt;\(P\)&lt;/span&gt; also holds for &lt;span class=&quot;math inline&quot;&gt;\(m\)&lt;/span&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb88&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb88-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb88-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;extend &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;P &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;m &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;↓ P&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; m &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; P m &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;↓ P&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc m&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb88-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb88-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;extend &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;m &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; m&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; soFar Pm j &lt;span class=&quot;kw&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;j ≟ m&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb88-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb88-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;|&lt;/span&gt; yes refl &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Pm&lt;/span&gt;
&lt;span id=&quot;cb88-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb88-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;|&lt;/span&gt; no j≢m &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle j≤m&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; soFar j &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;≤≢→&amp;lt; j≤m j≢m&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we can define primality testing itself, via trial division. We
&lt;code&gt;loop&lt;/code&gt; from &lt;span class=&quot;math inline&quot;&gt;\(2\)&lt;/span&gt; up to &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt;, testing each number to see if it divides
&lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt;, keeping track along the way of the fact that all the numbers less
than our current trial divisor do not divide &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt;. If the next divisor
does divide &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt;, we return it as proof that &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; is composite. If it
does not, we &lt;code&gt;extend&lt;/code&gt; our accumulating proof of all the numbers that do
not divide &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt;, and proceed to the next. If we reach &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt;, our
accumulated proof tells us that none of the numbers less than &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt;
divide it, which is proof that &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; is prime.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb89&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb89-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb89-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;prime? &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; ≤ n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Prime n ⊎ Composite n&lt;/span&gt;
&lt;span id=&quot;cb89-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb89-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;prime? n 2≤n &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; trialDiv &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;loop &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; n &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;≤→≤′ 2≤n&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt; noDivisorsUpTo2&lt;/span&gt;
&lt;span id=&quot;cb89-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb89-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb89-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb89-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  NoDivisorsUpTo &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb89-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb89-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  NoDivisorsUpTo &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ↓ &lt;span class=&quot;ot&quot;&gt;(λ&lt;/span&gt; # &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; ≤ #&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ¬ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;# ∣ n&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb89-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb89-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb89-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb89-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  noDivisorsUpTo2 &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; NoDivisorsUpTo &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb89-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb89-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  noDivisorsUpTo2 &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc zero&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle &lt;span class=&quot;ot&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb89-9&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb89-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  noDivisorsUpTo2 &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc j&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle &lt;span class=&quot;ot&quot;&gt;()))&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb89-10&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb89-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb89-11&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb89-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  trialDiv &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;m &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; m ∈[ &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; ⋯ n ] &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; NoDivisorsUpTo m &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Prime n ⊎ Composite n&lt;/span&gt;
&lt;span id=&quot;cb89-12&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb89-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  trialDiv &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;stop 2≤n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; soFar &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; inj₁ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;2≤n , soFar&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb89-13&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb89-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  trialDiv &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;m&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;step 2≤m next&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; soFar &lt;span class=&quot;kw&quot;&gt;with&lt;/span&gt; m ∣? n&lt;/span&gt;
&lt;span id=&quot;cb89-14&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb89-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;|&lt;/span&gt; yes m∣n &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; inj₂ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;m , 2≤m , top next , m∣n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb89-15&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb89-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;|&lt;/span&gt; no pf &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; trialDiv next &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;extend soFar &lt;span class=&quot;ot&quot;&gt;(λ&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; pf&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section class=&quot;level2&quot; id=&quot;lists&quot;&gt;
&lt;h2&gt;Lists&lt;/h2&gt;
&lt;p&gt;Before we are able to state the Fundamental Theorem of Arithmetic, we need to build up a data type for lists, along with some standard list manipulation functions. First, we define the type of lists and the standard &lt;code&gt;foldr&lt;/code&gt; function.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb90&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb90-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb90-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; List &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;A &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb90-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb90-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  [] &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; List A&lt;/span&gt;
&lt;span id=&quot;cb90-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb90-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;∷&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; List A &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; List A&lt;/span&gt;
&lt;span id=&quot;cb90-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb90-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb90-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb90-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;foldr &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;A &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; B &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; B&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; B &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; List A &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; B&lt;/span&gt;
&lt;span id=&quot;cb90-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb90-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;foldr &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&amp;amp;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; z [] &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; z&lt;/span&gt;
&lt;span id=&quot;cb90-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb90-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;foldr &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&amp;amp;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; z &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x ∷ xs&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; x &amp;amp; foldr &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&amp;amp;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; z xs&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we can define concatenation and product via &lt;code&gt;foldr&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb91&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb91-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb91-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;++&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; List A &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; List A &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; List A&lt;/span&gt;
&lt;span id=&quot;cb91-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb91-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;xs ++ ys &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; foldr &lt;span class=&quot;ot&quot;&gt;(_&lt;/span&gt;∷&lt;span class=&quot;ot&quot;&gt;_)&lt;/span&gt; ys xs&lt;/span&gt;
&lt;span id=&quot;cb91-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb91-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb91-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb91-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;product &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; List ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ℕ&lt;/span&gt;
&lt;span id=&quot;cb91-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb91-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;product &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; foldr &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;*&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We will need &lt;code&gt;All&lt;/code&gt;, which expresses that some predicate holds of all
the elements of a list. In fact, &lt;code&gt;All&lt;/code&gt; is manifestly an instance of
&lt;code&gt;foldr&lt;/code&gt; as well, but we would need a universe-polymorphic version of &lt;code&gt;foldr&lt;/code&gt; for that, so we just write it manually.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb92&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb92-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb92-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;All &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;P &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; List A &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb92-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb92-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;All P [] &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ⊤&lt;/span&gt;
&lt;span id=&quot;cb92-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb92-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;All P &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x ∷ xs&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; P x × All P xs&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now, we just need a couple lemmas about concatenation: first, that if &lt;code&gt;P&lt;/code&gt; holds for all the elements in &lt;code&gt;xs&lt;/code&gt; and all the elements in &lt;code&gt;ys&lt;/code&gt;, then it holds for all the elements in &lt;code&gt;xs ++ ys&lt;/code&gt;; and second, that &lt;code&gt;product&lt;/code&gt; distributes over concatenation (&lt;em&gt;i.e.&lt;/em&gt; it is a homomorphism from the monoid of lists under concatenation to the monoid of natural numbers under multiplication).&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb93&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb93-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb93-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;All-++ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;P &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;xs ys &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; List A&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; All P xs &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; All P ys &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; All P &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;xs ++ ys&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb93-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb93-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;All-++ &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;xs &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; []&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; Pxs Pys &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; Pys&lt;/span&gt;
&lt;span id=&quot;cb93-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb93-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;All-++ &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;xs &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ∷ &lt;span class=&quot;ot&quot;&gt;_}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;Px , Pxs&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; Pys &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; Px , All-++ Pxs Pys&lt;/span&gt;
&lt;span id=&quot;cb93-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb93-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb93-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb93-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;product-++ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;xs ys &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; List ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; product &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;xs ++ ys&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; ≡ product xs * product ys&lt;/span&gt;
&lt;span id=&quot;cb93-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb93-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;product-++ [] ys &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sym &lt;span class=&quot;ot&quot;&gt;(_&lt;/span&gt; +0&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb93-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb93-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;product-++ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x ∷ xs&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; ys &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x *&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; $≡ product-++ xs ys&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sym &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;*-assoc x &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;product xs&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;product ys&lt;span class=&quot;ot&quot;&gt;)))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;level2&quot; id=&quot;the-fundamental-theorem-of-arithmetic&quot;&gt;
&lt;h2&gt;The Fundamental Theorem of Arithmetic&lt;/h2&gt;
&lt;p&gt;Finally, we can put all the pieces together to state and prove (one
half of) the Fundamental Theorem of Arithmetic! &lt;code&gt;FTA n&lt;/code&gt; says that for
some positive integer &lt;code&gt;n&lt;/code&gt;, we can find a list of natural numbers which
are all prime, and whose product is &lt;code&gt;n&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb94&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb94-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb94-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;FTA &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb94-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb94-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;FTA n &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; Σ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;List ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(λ&lt;/span&gt; ps &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; All Prime ps × product ps ≡ n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To prove that this holds for all positive integers, we can again use
well-founded induction: in the base case, if &lt;span class=&quot;math inline&quot;&gt;\(n = 1\)&lt;/span&gt;, the empty list
suffices. Otherwise, we can decide whether &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; is prime. If so, the
singleton list containing &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; fits the bill. Otherwise, &lt;span class=&quot;math inline&quot;&gt;\(n = ab\)&lt;/span&gt; where
&lt;span class=&quot;math inline&quot;&gt;\(a\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(b\)&lt;/span&gt; are both nontrivial divisors of &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt;; by the induction
hypothesis, both can be factored into primes, and the list we want for
&lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; is simply the concatenation of the factorizations for &lt;span class=&quot;math inline&quot;&gt;\(a\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(b\)&lt;/span&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb95&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb95-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb95-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;fta &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; &amp;lt; n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; FTA n&lt;/span&gt;
&lt;span id=&quot;cb95-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb95-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;fta n &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; wf-ind &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;P &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(λ&lt;/span&gt; n &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; &amp;lt; n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; FTA n&lt;span class=&quot;ot&quot;&gt;)}&lt;/span&gt; &amp;lt;-wf go n&lt;/span&gt;
&lt;span id=&quot;cb95-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb95-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb95-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb95-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  go &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;((&lt;/span&gt;n′ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; n′ &amp;lt; n &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; &amp;lt; n′ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; FTA n′&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; &amp;lt; n &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; FTA n&lt;/span&gt;
&lt;span id=&quot;cb95-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb95-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  go &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc zero&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; IH 0&amp;lt;n &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; [] , &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;tt , refl&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb95-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb95-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  go &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc n&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt; IH 0&amp;lt;n &lt;span class=&quot;kw&quot;&gt;with&lt;/span&gt; prime? &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc n&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle zle&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb95-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb95-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;|&lt;/span&gt; inj₁ P &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; ∷ []&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; , &lt;span class=&quot;ot&quot;&gt;((&lt;/span&gt;P , tt&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; , &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc $≡ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc $≡ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n *1&lt;span class=&quot;ot&quot;&gt;))))&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb95-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb95-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;|&lt;/span&gt; inj₂ C &lt;span class=&quot;kw&quot;&gt;with&lt;/span&gt; factorsOf &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; C&lt;/span&gt;
&lt;span id=&quot;cb95-9&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb95-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;((&lt;/span&gt;a , sle &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; , a&amp;lt;n , &lt;span class=&quot;ot&quot;&gt;_)&lt;/span&gt; , &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;b , sle &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; , b&amp;lt;n , &lt;span class=&quot;ot&quot;&gt;_))&lt;/span&gt; , ab≡n&lt;/span&gt;
&lt;span id=&quot;cb95-10&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb95-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;kw&quot;&gt;with&lt;/span&gt; IH a a&amp;lt;n &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle zle&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb95-11&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb95-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;         &lt;span class=&quot;ot&quot;&gt;|&lt;/span&gt; IH b b&amp;lt;n &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle zle&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb95-12&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb95-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;|&lt;/span&gt; ps₁ , Pps₁ , prod₁ &lt;span class=&quot;ot&quot;&gt;|&lt;/span&gt; ps₂ , Pps₂ , prod₂ &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;ps₁ ++ ps₂&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; , &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;All-++ Pps₁ Pps₂&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; ,&lt;/span&gt;
&lt;span id=&quot;cb95-13&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb95-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    begin&lt;/span&gt;
&lt;span id=&quot;cb95-14&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb95-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      product &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;ps₁ ++ ps₂&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;      ≡[ product-++ ps₁ ps₂ ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb95-15&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb95-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      product ps₁ * product ps₂ ≡[ &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;*&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; $≡ prod₁ ≡$≡ prod₂ ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb95-16&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb95-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      a * b                     ≡[ ab≡n ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb95-17&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb95-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      suc &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;               ∎&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;level2&quot; id=&quot;further-directions&quot;&gt;
&lt;h2&gt;Further Directions&lt;/h2&gt;
&lt;p&gt;That concludes our tour of the Fundamental Theorem of Arithmetic in Agda! If you’ve worked through the whole thing and
completed the proofs mostly on your own, congratulations! If you want
more practice, there are a lot of directions you could take this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Doing trial division all the way up to &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; is silly; we can stop
when we get to &lt;span class=&quot;math inline&quot;&gt;\(\sqrt n\)&lt;/span&gt;. I think this would make for a nice
exercise (in fact, Taneb’s version in the Agda stdlib does this).&lt;/li&gt;
&lt;li&gt;Define “&lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt; is a proper divisor of &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt;” to mean that that &lt;span class=&quot;math inline&quot;&gt;\(d \mid n\)&lt;/span&gt;
and &lt;span class=&quot;math inline&quot;&gt;\(2 \leq d &amp;lt; n\)&lt;/span&gt;, then show that the “is a proper divisor of” relation
is well-founded, and prove &lt;code&gt;fta&lt;/code&gt; via well-founded induction on that
relation instead. This might streamline some parts of the proof;
I’m not sure.&lt;/li&gt;
&lt;li&gt;The other half of the FTA says that the prime factorization is
&lt;em&gt;unique up to permutation&lt;/em&gt;. To prove this, one has to define
what it means for one list to be a permutation of another, and show that
if there are two different prime factorizations then one must be a
permutation of the other (if &lt;span class=&quot;math inline&quot;&gt;\(p\)&lt;/span&gt; is a prime from the first
factorization, then it divides the other factorization as well,
which means it must be equal to one of the primes in the other
factorization). I may write up this proof in a follow-up post.&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;

&lt;/section&gt;


&lt;section id=&quot;isso-thread&quot;&gt;
  &amp;lt;noscript&amp;gt;Javascript needs to be activated to view comments.&amp;lt;/noscript&amp;gt;
&lt;/section&gt;</description>
	<pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Philip Wadler: Crank GPT</title>
	<guid isPermaLink="false">tag:blogger.com,1999:blog-9757377.post-457312131270879658</guid>
	<link>https://wadler.blogspot.com/2026/06/crank-gpt.html</link>
	<description>&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEhw65gFzQ1T5o8PGOi0MfNtNDB5E1th9uZyXgPwDwpqhZM8h79NKXUM6_11g1RlSFi3cuUpDMQcAR2qRhDx7tYxjrfQdGmZ80g_WjRIPXqr0yxQJLh_LeliasFp7YaQMMZuYJCT-4cN9QwY5fNXCQUvIHXvBAX37mevRc0XwystJx7Nm4OrdTpO&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; height=&quot;372&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEhw65gFzQ1T5o8PGOi0MfNtNDB5E1th9uZyXgPwDwpqhZM8h79NKXUM6_11g1RlSFi3cuUpDMQcAR2qRhDx7tYxjrfQdGmZ80g_WjRIPXqr0yxQJLh_LeliasFp7YaQMMZuYJCT-4cN9QwY5fNXCQUvIHXvBAX37mevRc0XwystJx7Nm4OrdTpO=w640-h372&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt; Not a &lt;a href=&quot;https://crankgpt.com/&quot;&gt;crank&lt;/a&gt; project! Spotted via &lt;a href=&quot;https://www.robinsloan.com/winter-garden/june/&quot;&gt;Robin Sloan&lt;/a&gt;.&lt;p&gt;&lt;/p&gt;</description>
	<pubDate>Wed, 24 Jun 2026 20:01:41 +0000</pubDate>
	<author>noreply@blogger.com (Philip Wadler)</author>
</item>
<item>
	<title>Philip Wadler: Don't Let Them Block Our Indyref Mandate</title>
	<guid isPermaLink="false">tag:blogger.com,1999:blog-9757377.post-5369770487228486404</guid>
	<link>https://wadler.blogspot.com/2026/06/dont-let-them-block-our-indyref-mandate.html</link>
	<description>&lt;p&gt; &lt;img alt=&quot;Don’t let them ignore our indyref mandate.&quot; class=&quot;nm-image&quot; height=&quot;360&quot; src=&quot;https://base.newmode.net/sites/default/files/styles/large/public/2026-05/mandate%20petition%2016x9_1.jpg?itok=sKVWXw2y&quot; width=&quot;640&quot; /&gt;&lt;/p&gt;&lt;div style=&quot;color: #003680; font-family: Roboto; font-size: 20px;&quot;&gt;&lt;strong&gt;&lt;span&gt;Brought to you by &lt;/span&gt;&lt;a href=&quot;https://www.believeinscotland.org&quot;&gt;Believe in Scotland&lt;/a&gt;&lt;span&gt;. You can sign the petition &lt;/span&gt;&lt;a href=&quot;https://www.believeinscotland.org/indyref_petition&quot;&gt;here&lt;/a&gt;&lt;span&gt;.&lt;/span&gt;&lt;/strong&gt;&lt;/div&gt;&lt;div style=&quot;color: #003680; font-family: Roboto; font-size: 20px;&quot;&gt;&lt;strong&gt;&lt;br /&gt;&lt;/strong&gt;&lt;/div&gt;&lt;div style=&quot;color: #003680; font-family: Roboto; font-size: 20px;&quot;&gt;&lt;strong&gt;Tell your elected representatives and the Prime Minister that blocking our indyref mandate is unacceptable.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;color: #003680; font-family: Roboto; font-size: 20px;&quot;&gt;The Scottish Parliament elections in May 2026 returned the largest ever pro-independence majority in the history of the Scottish Parliament. That democratic majority provides an undeniable mandate for a second Scottish independence referendum, and the Parliament has now confirmed that mandate by demanding the UK Government transfer the powers required to hold that referendum.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;color: #003680; font-family: Roboto; font-size: 20px;&quot;&gt;Every one of those 73 MSPs stood on a manifesto platform supporting Scotland’s right to choose its own future and calling for a second independence referendum. The Scottish people have therefore elected a parliament with a clear democratic mandate to demand a referendum on Scottish independence.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;color: #003680; font-family: Roboto; font-size: 20px;&quot;&gt;All democrats must believe that the Scottish people have an inalienable right to choose their own future. The Scottish people have voted for a second independence referendum. Any attempt to deny them the right to choose their own future is an assault on Scottish parliamentary democracy and an affront to the people of Scotland - so that mandate must not be denied.&lt;/div&gt;&lt;div style=&quot;color: #003680; font-family: Roboto; font-size: 20px;&quot;&gt;&lt;br /&gt;&lt;/div&gt;</description>
	<pubDate>Wed, 24 Jun 2026 20:00:48 +0000</pubDate>
	<author>noreply@blogger.com (Philip Wadler)</author>
</item>
<item>
	<title>GHC Developer Blog: GHC 9.12.5-rc2 is now available</title>
	<guid isPermaLink="true">http://haskell.org/ghc/blog/20260624-ghc-9.12.5-rc2-released.html</guid>
	<link>http://haskell.org/ghc/blog/20260624-ghc-9.12.5-rc2-released.html</link>
	<description>&lt;h1&gt;GHC 9.12.5-rc2 is now available&lt;/h1&gt;
&lt;h4 class=&quot;text-muted&quot;&gt;mangoiv - 2026-06-24&lt;/h4&gt;

&lt;p&gt;The GHC developers are very pleased to announce the availability
of the second release candidate for GHC 9.12.5, ghc-9.12.5-rc2. The first release candidate did not receive an announcement since promptly after publishing it, an urgent issue with distribution of the process library on macos was discovered. This is now fixed.
Binary distributions, source distributions, and documentation are available at
&lt;a href=&quot;https://downloads.haskell.org/~ghc/9.12.5-rc2/&quot;&gt;downloads.haskell.org&lt;/a&gt; and via &lt;a href=&quot;https://www.haskell.org/ghcup/&quot;&gt;GHCup&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;GHC 9.12.5 is a bug-fix release fixing many issues of a variety of
severities and scopes, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Implement version 2 of the ghc &lt;code&gt;semaphore&lt;/code&gt; protocol for GHC’s &lt;code&gt;-jsem&lt;/code&gt; jobserver on Linux and other &lt;code&gt;POSIX&lt;/code&gt; platforms (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/25087&quot;&gt;&lt;span&gt;#25087&lt;/span&gt;&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/27253&quot;&gt;&lt;span&gt;#27253&lt;/span&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;several improvements to the pattern match checker (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/25926&quot;&gt;&lt;span&gt;#25926&lt;/span&gt;&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/27124&quot;&gt;&lt;span&gt;#27124&lt;/span&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;several improvements to the demand analyser (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/27261&quot;&gt;&lt;span&gt;#27261&lt;/span&gt;&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/27106&quot;&gt;&lt;span&gt;#27106&lt;/span&gt;&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26416&quot;&gt;&lt;span&gt;#26416&lt;/span&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;several fixes regarding the interaction of ticks and coercions (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/27121&quot;&gt;&lt;span&gt;#27121&lt;/span&gt;&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26929&quot;&gt;&lt;span&gt;#26929&lt;/span&gt;&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26642&quot;&gt;&lt;span&gt;#26642&lt;/span&gt;&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26693&quot;&gt;&lt;span&gt;#26693&lt;/span&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;several fixes for blackholes (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/27261&quot;&gt;&lt;span&gt;#27261&lt;/span&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;… and many more&lt;/p&gt;
&lt;p&gt;Mind that the very important overhaul of the semaphore-compat library to v2 is included in this release and that the semaphore feature will only start working with cabal-install 3.18 again, which is sadly a breaking but necessary change.&lt;/p&gt;
&lt;p&gt;A full accounting of these fixes can be found in the
release notes. As always, GHC’s release status, including planned future
releases, can be found on the GHC Wiki status.&lt;/p&gt;
&lt;p&gt;This release candidate will have a two-week testing period. If all goes well
the final release will be available the week of 8 July 2026.&lt;/p&gt;
&lt;p&gt;GHC development is sponsored by:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://juspay.com/&quot;&gt;Juspay&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://qbaylogic.com/&quot;&gt;QBayLogic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.channable.com/&quot;&gt;Channable&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://haskell.foundation/&quot;&gt;Haskell Foundation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://serokell.io/&quot;&gt;Serokell&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://well-typed.com/&quot;&gt;Well-Typed&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.tweag.io/&quot;&gt;Tweag&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.dotcom-monitor.com/&quot;&gt;Dotcom-Monitor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.loadview-testing.com/&quot;&gt;LoadView&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://webhostingbuddy.com/&quot;&gt;Web Hosting Buddy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.findmyelectric.com/&quot;&gt;Find My Electric&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.sc.com&quot;&gt;Standard Chartered&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://upcloud.com&quot;&gt;UpCloud&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mercury.com&quot;&gt;Mercury&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;As always, do give this release a try and open a ticket if you see
anything amiss.&lt;/p&gt;</description>
	<pubDate>Wed, 24 Jun 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Gabriella Gonzalez: Record type inference for dummies</title>
	<guid isPermaLink="true">https://haskellforall.com/2026/06/record-type-inference-for-dummies</guid>
	<link>https://haskellforall.com/2026/06/record-type-inference-for-dummies</link>
	<description>Gentle tour of type inference for records</description>
	<pubDate>Tue, 23 Jun 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Well-Typed.Com: Haskell ecosystem activities report: Marchâ€“May 2026</title>
	<guid isPermaLink="false">http://www.well-typed.com/blog/2026/06/haskell-ecosystem-report-march-may-2026</guid>
	<link>https://well-typed.com/blog/2026/06/haskell-ecosystem-report-march-may-2026</link>
	<description>&lt;p&gt;This is the thirty-first 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
March 2026 to May 2026.&lt;/p&gt;
&lt;p&gt;You can find the previous editions collected under the
&lt;a href=&quot;https://well-typed.com/blog/tags/haskell-ecosystem-report&quot;&gt;haskell-ecosystem-report tag&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;sponsorship&quot;&gt;Sponsorship&lt;/h2&gt;
&lt;p&gt;We offer &lt;a href=&quot;https://well-typed.com/ecosystem/&quot;&gt;Haskell Ecosystem Support Packages&lt;/a&gt; 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 &lt;a href=&quot;https://well-typed.com/blog/2025/06/haskell-ecosystem-support-packages&quot;&gt;announcement of these
packages&lt;/a&gt; in partnership with
the Haskell Foundation. We need funding to continue this essential maintenance work!&lt;/p&gt;
&lt;p&gt;Many thanks to our Haskell Ecosystem Supporters: &lt;a href=&quot;https://www.sc.com/&quot;&gt;Standard Chartered&lt;/a&gt;,
&lt;a href=&quot;https://www.channable.com/&quot;&gt;Channable&lt;/a&gt; and &lt;a href=&quot;https://qbaylogic.com/&quot;&gt;QBayLogic&lt;/a&gt;,
as well as to our other clients who also contribute to making this work possible:
&lt;a href=&quot;https://www.anduril.com/&quot;&gt;Anduril&lt;/a&gt;, &lt;a href=&quot;https://juspay.in/&quot;&gt;Juspay&lt;/a&gt; and &lt;a href=&quot;https://mercury.com/&quot;&gt;Mercury&lt;/a&gt;;
and to the &lt;a href=&quot;https://opencollective.com/haskell-language-server&quot;&gt;HLS Open Collective&lt;/a&gt; for
supporting HLS release management.&lt;/p&gt;
&lt;h2 id=&quot;highlights&quot;&gt;Highlights&lt;/h2&gt;

&lt;h3 id=&quot;reinstallable-base&quot;&gt;Reinstallable base&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/rodrigo&quot;&gt;Rodrigo&lt;/a&gt; and &lt;a href=&quot;https://well-typed.com/people/wolfgang&quot;&gt;Wolfgang&lt;/a&gt; have continued working to disentangle &lt;code&gt;base&lt;/code&gt; from GHC,
with the ultimate goal of being able to use different versions of &lt;code&gt;base&lt;/code&gt; with
a single GHC version. This is all part of a long-term project to make
GHC upgrades easier, documented in the
&lt;a href=&quot;https://github.com/well-typed/reinstallable-base&quot;&gt;reinstallable-base repo&lt;/a&gt;,
and recently described in an
&lt;a href=&quot;https://blog.haskell.org/making-ghc-upgrades-easy/&quot;&gt;excellent haskell.org blog article by Simon Peyton Jones&lt;/a&gt;.
Simon, &lt;a href=&quot;https://well-typed.com/people/rodrigo&quot;&gt;Rodrigo&lt;/a&gt; and &lt;a href=&quot;https://well-typed.com/people/wolfgang&quot;&gt;Wolfgang&lt;/a&gt; are working together to rethink GHC’s treatment of
“known-key names” so &lt;code&gt;base&lt;/code&gt; will be much less tightly coupled to &lt;code&gt;ghc-internal&lt;/code&gt; (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15899&quot;&gt;!15899&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;One big milestone was making the current &lt;code&gt;base&lt;/code&gt; buildable both with GHC 9.14
(&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/16070&quot;&gt;!16070&lt;/a&gt;) and with the upcoming GHC 10.0 (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/16035&quot;&gt;!16035&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Various other pieces of technical groundwork were required:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;moving most of the &lt;code&gt;System.IO&lt;/code&gt; implementation into &lt;code&gt;base&lt;/code&gt; (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15694&quot;&gt;!15694&lt;/a&gt;),&lt;/li&gt;
&lt;li&gt;similarly moving &lt;code&gt;Text.Read&lt;/code&gt; (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15693&quot;&gt;!15693&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15777&quot;&gt;!15777&lt;/a&gt;),&lt;/li&gt;
&lt;li&gt;making various SafeHaskell-related changes (&lt;a href=&quot;https://github.com/haskell/core-libraries-committee/issues/408&quot;&gt;CLC &lt;span&gt;#408&lt;/span&gt;&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/16034&quot;&gt;!16034&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/wolfgang&quot;&gt;Wolfgang&lt;/a&gt; also opened several CLC proposals identifying key areas that require further
work:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the deprecation of unstable &lt;code&gt;base&lt;/code&gt; modules (&lt;a href=&quot;https://github.com/haskell/core-libraries-committee/issues/392&quot;&gt;CLC &lt;span&gt;#392&lt;/span&gt;&lt;/a&gt;), and&lt;/li&gt;
&lt;li&gt;working towards making &lt;code&gt;bytestring&lt;/code&gt; and &lt;code&gt;text&lt;/code&gt; not depend on internal
I/O machinery (&lt;a href=&quot;https://github.com/haskell/core-libraries-committee/issues/410&quot;&gt;CLC &lt;span&gt;#410&lt;/span&gt;&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;semaphores-and--jsem&quot;&gt;Semaphores and &lt;code&gt;-jsem&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The implementation of semaphores used by &lt;code&gt;cabal-install&lt;/code&gt; and GHC to coordinate
concurrency suffered from a serious issue when GHC and &lt;code&gt;cabal-install&lt;/code&gt; were
linked against different libc implementations (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/issues/25087&quot;&gt;#25087&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/zubin&quot;&gt;Zubin&lt;/a&gt; remedied this issue with a new semaphore implementation on top
of Unix domain sockets (&lt;a href=&quot;https://gitlab.haskell.org/ghc/semaphore-compat/-/merge_requests/8&quot;&gt;&lt;span&gt;!8&lt;/span&gt;&lt;/a&gt;), described in &lt;a href=&quot;https://github.com/ghc-proposals/ghc-proposals/pull/673&quot;&gt;GHC proposal &lt;span&gt;#673&lt;/span&gt;&lt;/a&gt;. GHC (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15729&quot;&gt;&lt;span&gt;!15729&lt;/span&gt;&lt;/a&gt;) and
&lt;code&gt;cabal-install&lt;/code&gt; (&lt;a href=&quot;https://github.com/haskell/cabal/pull/11628&quot;&gt;&lt;span&gt;#11628&lt;/span&gt;&lt;/a&gt;) were then
switched to this new protocol version.&lt;/p&gt;
&lt;p&gt;As part of this work, &lt;a href=&quot;https://well-typed.com/people/zubin&quot;&gt;Zubin&lt;/a&gt; also identified some deficiencies in the semantics
of interruptible FFI (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/issues/27110&quot;&gt;#27110&lt;/a&gt;).&lt;/p&gt;
&lt;h3 id=&quot;cabal-modernisation&quot;&gt;Cabal modernisation&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/sam&quot;&gt;Sam&lt;/a&gt; worked to modernise the architecture of &lt;code&gt;cabal-install&lt;/code&gt; by making it directly call the Cabal library to build packages (&lt;a href=&quot;https://github.com/haskell/cabal/pull/11703&quot;&gt;&lt;span&gt;#11703&lt;/span&gt;&lt;/a&gt;).
This unlocked the performance optimisations described in &lt;a href=&quot;https://well-typed.com/blog/2026/05/faster-haskell-builds/&quot;&gt;a recent blog post&lt;/a&gt; (&lt;a href=&quot;https://github.com/haskell/cabal/pull/11767&quot;&gt;&lt;span&gt;#11767&lt;/span&gt;&lt;/a&gt;, &lt;a href=&quot;https://github.com/haskell/cabal/pull/11768&quot;&gt;&lt;span&gt;#11768&lt;/span&gt;&lt;/a&gt;), achieving
speed-ups of around 10-15% in certain situations.&lt;/p&gt;
&lt;p&gt;In the long term, we would like to move towards Cabal having a fine-grained build graph across the whole project, rather than using a component-level build graph and relying on GHC to orchestrate the compilation of all the modules in a component/package. This will unlock more parallelism and other developer experience improvements.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/sam&quot;&gt;Sam&lt;/a&gt; also implemented many improvements to &lt;code&gt;build-type: Hooks&lt;/code&gt;, the modern
replacement for &lt;code&gt;build-type: Custom&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;an improved API for &lt;code&gt;SetupHooks&lt;/code&gt; authors (&lt;a href=&quot;https://github.com/haskell/cabal/pull/11772&quot;&gt;&lt;span&gt;#11772&lt;/span&gt;&lt;/a&gt;),&lt;/li&gt;
&lt;li&gt;better documentation (&lt;a href=&quot;https://github.com/haskell/cabal/pull/11771&quot;&gt;&lt;span&gt;#11771&lt;/span&gt;&lt;/a&gt;),&lt;/li&gt;
&lt;li&gt;improved recompilation checking for pre-build rules (&lt;a href=&quot;https://github.com/haskell/cabal/pull/11731&quot;&gt;&lt;span&gt;#11731&lt;/span&gt;&lt;/a&gt;),&lt;/li&gt;
&lt;li&gt;support for generating non-Haskell files in pre-build rules (&lt;a href=&quot;https://github.com/haskell/cabal/pull/11573&quot;&gt;&lt;span&gt;#11573&lt;/span&gt;&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/tobias&quot;&gt;Tobias&lt;/a&gt; chimed in by adding support for recursive globs in file monitoring, which is useful for &lt;code&gt;SetupHooks&lt;/code&gt; (&lt;a href=&quot;https://github.com/haskell/cabal/pull/11658&quot;&gt;&lt;span&gt;#11658&lt;/span&gt;&lt;/a&gt;).&lt;/p&gt;
&lt;h3 id=&quot;windows-dll-support&quot;&gt;Windows DLL support&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/duncan&quot;&gt;Duncan&lt;/a&gt;, with the help of &lt;a href=&quot;https://well-typed.com/people/davide&quot;&gt;David&lt;/a&gt;, embarked on the project of adding proper dynamic
linking support to GHC on Windows. While this is still work-in-progress,
several important steps have already been taken:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;extending Cmm syntax to support symbols from external DSOs/DLLs (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15135&quot;&gt;!15135&lt;/a&gt;),&lt;/li&gt;
&lt;li&gt;solving the recursive DLL dependency between the RTS and &lt;code&gt;ghc-internal&lt;/code&gt;
(&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15907&quot;&gt;!15907&lt;/a&gt;),&lt;/li&gt;
&lt;li&gt;making GHC use &lt;code&gt;__attribute__((dllimport))&lt;/code&gt; for external symbol
declarations (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15914&quot;&gt;!15914&lt;/a&gt;),&lt;/li&gt;
&lt;li&gt;updating Hadrian to create individual &lt;code&gt;.def&lt;/code&gt; files per &lt;code&gt;ghc-internal&lt;/code&gt; DLL
(&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/16082&quot;&gt;!16082&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;critical-process-issue-on-macos&quot;&gt;Critical &lt;code&gt;process&lt;/code&gt; issue on macOS&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/magnus&quot;&gt;Magnus&lt;/a&gt; diagnosed a critical issue with &lt;code&gt;process&lt;/code&gt; on macOS
(&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/issues/27144&quot;&gt;#27144&lt;/a&gt;, &lt;a href=&quot;https://github.com/haskell/process/issues/356&quot;&gt;&lt;span&gt;#356&lt;/span&gt;&lt;/a&gt;), implementing a fix
in &lt;a href=&quot;https://github.com/haskell/process/pull/363&quot;&gt;&lt;span&gt;#363&lt;/span&gt;&lt;/a&gt;. As part of this work,
he discovered an issue with several uploaded versions of &lt;code&gt;process&lt;/code&gt;
(&lt;a href=&quot;https://github.com/haskell/process/issues/365&quot;&gt;&lt;span&gt;#365&lt;/span&gt;&lt;/a&gt;) which was resolved by
coordinating with the &lt;code&gt;process&lt;/code&gt; maintainers.&lt;/p&gt;
&lt;h2 id=&quot;ghc&quot;&gt;GHC&lt;/h2&gt;
&lt;h3 id=&quot;releases&quot;&gt;Releases&lt;/h3&gt;
&lt;p&gt;Keeping all of GHC’s active release branches in good shape is a demanding,
largely behind-the-scenes effort. Each release requires triaging and backporting
a steady stream of bugfixes, with patches that often don’t cleanly apply and
require careful reworking. Information about upcoming releases is available on the
&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/wikis/GHC-Status&quot;&gt;GHC release status page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;GHC currently has four (!) active branches. &lt;a href=&quot;https://well-typed.com/people/zubin&quot;&gt;Zubin&lt;/a&gt; worked towards the
10.0 release as well as on 9.14.2; &lt;a href=&quot;https://well-typed.com/people/magnus&quot;&gt;Magnus&lt;/a&gt; prepared 9.12.5, and &lt;a href=&quot;https://well-typed.com/people/andreask&quot;&gt;Andreas&lt;/a&gt;
took on 9.10.4.&lt;/p&gt;
&lt;h3 id=&quot;frontend&quot;&gt;Frontend&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/rodrigo&quot;&gt;Rodrigo&lt;/a&gt; bumped the default language edition to GHC2024 (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/issues/26039&quot;&gt;#26039&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/14420&quot;&gt;!14420&lt;/a&gt;).
Starting from GHC 10.0, code without an explicit language edition will
default to GHC2024. Compared to GHC2021, this adds the extensions &lt;code&gt;DataKinds&lt;/code&gt;,
&lt;code&gt;DerivingStrategies&lt;/code&gt;, &lt;code&gt;DisambiguateRecordFields&lt;/code&gt;, &lt;code&gt;ExplicitNamespaces&lt;/code&gt;,
&lt;code&gt;GADTs&lt;/code&gt;, &lt;code&gt;MonoLocalBinds&lt;/code&gt;, &lt;code&gt;LambdaCase&lt;/code&gt; and &lt;code&gt;RoleAnnotations&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/magnus&quot;&gt;Magnus&lt;/a&gt; fixed the documentation of &lt;code&gt;getSizeofMutableByteArray#&lt;/code&gt; (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/16065&quot;&gt;!16065&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/sam&quot;&gt;Sam&lt;/a&gt; fixed a loop with &lt;code&gt;-XDeepSubsumption&lt;/code&gt; on GHC 9.14 (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/issues/26823&quot;&gt;#26823&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15604&quot;&gt;!15604&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/wolfgang&quot;&gt;Wolfgang&lt;/a&gt; made several performance improvements to the driver, allowing
downsweep to use existing module graph nodes (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/16028&quot;&gt;!16028&lt;/a&gt;), introducing a cache
for hole modules (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15888&quot;&gt;!15888&lt;/a&gt;), and storing home unit dependencies as sets (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15849&quot;&gt;!15849&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/hannes&quot;&gt;Hannes&lt;/a&gt; made several performance improvements to &lt;code&gt;ghc-pkg&lt;/code&gt;, speeding up its closure
computation (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/16062&quot;&gt;!16062&lt;/a&gt;) and migrating it to use &lt;code&gt;OsPath&lt;/code&gt; (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15584&quot;&gt;!15584&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/andreask&quot;&gt;Andreas&lt;/a&gt; modularised the &lt;code&gt;GHC.Driver.Main&lt;/code&gt; module (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15940&quot;&gt;!15940&lt;/a&gt;), as that single
module had become quite unwieldy.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Following on from previous work allowing typechecker plugins to run in the
pattern match checker (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/14797&quot;&gt;!14797&lt;/a&gt;), &lt;a href=&quot;https://well-typed.com/people/sam&quot;&gt;Sam&lt;/a&gt; made sure that plugins are only initialised
once per module (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15485&quot;&gt;!15485&lt;/a&gt;), fixing the regression reported in &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/issues/26839&quot;&gt;#26839&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/rodrigo&quot;&gt;Rodrigo&lt;/a&gt; provided a standalone reproducer for the simplifier slowness reported
in &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/issues/26989&quot;&gt;#26989&lt;/a&gt;, which allowed Simon Peyton Jones to diagnose and fix this quadratic
behaviour (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15725&quot;&gt;!15725&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/sam&quot;&gt;Sam&lt;/a&gt; investigated the type family performance regressions reported in &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/issues/26426&quot;&gt;#26426&lt;/a&gt;,
identifying two key patches that had accidentally fixed the regression and
recording these findings in Notes (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/16113&quot;&gt;!16113&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/andreask&quot;&gt;Andreas&lt;/a&gt; identified that a patch to use &lt;code&gt;Generics&lt;/code&gt; within GHC significantly
regressed compile times (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/issues/27191&quot;&gt;#27191&lt;/a&gt;). The offending patch was reverted for the
time being, and the &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/wikis/commentary/coding-style#132-avoid-genericdata-instances&quot;&gt;coding style&lt;/a&gt; Wiki page was updated to
document this unfortunate limitation.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;backend&quot;&gt;Backend&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/sam&quot;&gt;Sam&lt;/a&gt; finished up work by Matthew Craven to improve the representation of
floating point literals in GHC, fixing several issues with the treatment of
negative zero and NaN values (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15528&quot;&gt;!15528&lt;/a&gt;). This brings GHC much closer to proper
IEEE 754 floating point compliance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/andreask&quot;&gt;Andreas&lt;/a&gt; discovered a bug with AArch64 profiled dynamic builds of GHC and
concluded that it was a bug in &lt;code&gt;gcc&lt;/code&gt;/&lt;code&gt;binutils&lt;/code&gt; (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/issues/26994&quot;&gt;#26994&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/sam&quot;&gt;Sam&lt;/a&gt; fixed a crash in Core Prep caused by invalid profiling tick occurrences
(&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/issues/27182&quot;&gt;#27182&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/16003&quot;&gt;!16003&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/sam&quot;&gt;Sam&lt;/a&gt; investigated a crash in &lt;code&gt;mkDupableContWithDmds&lt;/code&gt;, and worked with Simon
Peyton Jones to land a fix (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/issues/27261&quot;&gt;#27261&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/16084&quot;&gt;!16084&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/sam&quot;&gt;Sam&lt;/a&gt; fixed several bugs in the implementation of the &lt;code&gt;hsExprType&lt;/code&gt; function
(&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/issues/26910&quot;&gt;#26910&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15772&quot;&gt;!15772&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/zubin&quot;&gt;Zubin&lt;/a&gt; fixed the typing of void pointer chains in &lt;code&gt;capi&lt;/code&gt; FFI calls to avoid
&lt;code&gt;-Wincompatible-pointer-type&lt;/code&gt; errors by the C compiler (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/issues/26852&quot;&gt;#26852&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15547&quot;&gt;!15547&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/sam&quot;&gt;Sam&lt;/a&gt; helped first-time contributor Avery Parker land his AmeriHac contribution
to add constant folding for SIMD vector operations (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15512&quot;&gt;!15512&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/sam&quot;&gt;Sam&lt;/a&gt; reviewed several patches to the AArch64 native code generator by Ian Duncan,
in the process uncovering a cluster of latent correctness bugs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15620&quot;&gt;!15620&lt;/a&gt; fixed a bug in “shift right” using a logical shift instead of an
arithmetic shift (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/issues/26979&quot;&gt;#26979&lt;/a&gt;). A separate register clobbering bug was
identified and fixed.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15619&quot;&gt;!15619&lt;/a&gt; fixed sign extension at 32-bit width (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/issues/26978&quot;&gt;#26978&lt;/a&gt;). A separate bug
with the overflow bit was identified and fixed (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/issues/27047&quot;&gt;#27047&lt;/a&gt;). Another
register clobbering bug was found and fixed separately (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/issues/27046&quot;&gt;#27046&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/16031&quot;&gt;!16031&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/sam&quot;&gt;Sam&lt;/a&gt; fixed a recalcitrant “failed to detect OverLit” crash in
&lt;code&gt;coreExprToPmLit&lt;/code&gt; (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15895&quot;&gt;!15895&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/issues/27124&quot;&gt;#27124&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/issues/25926&quot;&gt;#25926&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/magnus&quot;&gt;Magnus&lt;/a&gt; and &lt;a href=&quot;https://well-typed.com/people/sam&quot;&gt;Sam&lt;/a&gt; investigated the GHC panic reported in &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/issues/27227&quot;&gt;#27227&lt;/a&gt;, which was
narrowed down to Cabal bug &lt;a href=&quot;https://github.com/haskell/cabal/issues/7684&quot;&gt;&lt;span&gt;#7684&lt;/span&gt;&lt;/a&gt;,
and subsequently fixed (&lt;a href=&quot;https://github.com/haskell/cabal/pull/11791&quot;&gt;&lt;span&gt;#11791&lt;/span&gt;&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;ghci-bytecode&quot;&gt;ghci &amp;amp; bytecode&lt;/h3&gt;
&lt;p&gt;Work continued on making the bytecode interpreter, which underpins GHCi as well
as the debugger, more capable and memory efficient.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/hannes&quot;&gt;Hannes&lt;/a&gt; introduced the &lt;code&gt;-fimport-loaded-target&lt;/code&gt; ghci flag to fix a regression
with the &lt;code&gt;:add&lt;/code&gt; command relating to support for multiple home units
(&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15533&quot;&gt;!15533&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/issues/26866&quot;&gt;#26866&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/hannes&quot;&gt;Hannes&lt;/a&gt; fixed a regression in the behaviour of &lt;code&gt;:load&lt;/code&gt; (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/issues/27202&quot;&gt;#27202&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15980&quot;&gt;!15980&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/hannes&quot;&gt;Hannes&lt;/a&gt; added support for &lt;code&gt;hpc&lt;/code&gt; in the bytecode interpreter (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/issues/27036&quot;&gt;#27036&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15843&quot;&gt;!15843&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/rodrigo&quot;&gt;Rodrigo&lt;/a&gt; added support for static constructors in the bytecode interpreter,
also fixing its treatment of unlifted values (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/issues/25636&quot;&gt;#25636&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15221&quot;&gt;!15221&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/hannes&quot;&gt;Hannes&lt;/a&gt; improved the memory usage of the bytecode interpreter by recording only
a &lt;code&gt;LinkableUsage&lt;/code&gt; instead of &lt;code&gt;Linkable&lt;/code&gt; in &lt;code&gt;LoaderState&lt;/code&gt; (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/issues/26500&quot;&gt;#26500&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/issues/27018&quot;&gt;#27018&lt;/a&gt;,
&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15689&quot;&gt;!15689&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;rts&quot;&gt;RTS&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/duncan&quot;&gt;Duncan&lt;/a&gt; consolidated the ticker implementations to a single one on POSIX
(&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15781&quot;&gt;!15781&lt;/a&gt;), removing signal-based ticker implementations (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15757&quot;&gt;!15757&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/16014&quot;&gt;!16014&lt;/a&gt;)
which presented a number of disadvantages (described in &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/issues/27073&quot;&gt;#27073&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/davide&quot;&gt;David&lt;/a&gt; resurrected an old MR improving the documentation of the allocator
(&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/3812&quot;&gt;!3812&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/andreask&quot;&gt;Andreas&lt;/a&gt; added missing profiling headers for &lt;code&gt;origin_thunk&lt;/code&gt; frames (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15665&quot;&gt;!15665&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/duncan&quot;&gt;Duncan&lt;/a&gt; identified some incorrect STOP_THREAD status codes in &lt;code&gt;ghc-events&lt;/code&gt;
(&lt;a href=&quot;https://github.com/haskell/ghc-events/issues/130&quot;&gt;&lt;span&gt;#130&lt;/span&gt;&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;build-system&quot;&gt;Build system&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/davide&quot;&gt;David&lt;/a&gt; made several improvements to GHC’s build system and Hadrian, in
relation to his work on Windows DLL support:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a fix for Unix paths in ACLOCAL_PATH (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/16112&quot;&gt;!16112&lt;/a&gt;),&lt;/li&gt;
&lt;li&gt;proper LLVM program versioning logic (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/16025&quot;&gt;!16025&lt;/a&gt;),&lt;/li&gt;
&lt;li&gt;work on response files to avoid MAX_PATH issues on Windows (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15891&quot;&gt;!15891&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/16120&quot;&gt;!16120&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/andreask&quot;&gt;Andreas&lt;/a&gt; fixed an issue with &lt;code&gt;--target&lt;/code&gt; in the configure script (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15649&quot;&gt;!15649&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/zubin&quot;&gt;Zubin&lt;/a&gt; stopped Hadrian from including package hashes in Haddock directory names,
as this was causing many broken links when browsing Haddocks (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/issues/26635&quot;&gt;#26635&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15475&quot;&gt;!15475&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;ghc-contribution-experience&quot;&gt;GHC contribution experience&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/magnus&quot;&gt;Magnus&lt;/a&gt; overhauled the MR template to be more helpful for new contributors
(&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15943&quot;&gt;!15943&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/issues/27165&quot;&gt;#27165&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Many team members provided reviews and helped land contributions from others,
as described elsewhere in this report.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;ci-and-tests&quot;&gt;CI and tests&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/magnus&quot;&gt;Magnus&lt;/a&gt; has been doing significant work on the gitlab.haskell.org
instance and CI infrastructure to improve robustness of CI, deal with spam
and manage the server load imposed by AI crawlers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/magnus&quot;&gt;Magnus&lt;/a&gt; changed the Darwin CI to clone rather than copy when creating the Cabal cache (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15683&quot;&gt;!15683&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/sam&quot;&gt;Sam&lt;/a&gt; added a vendored mini-QuickCheck component for use in GHC’s testsuite,
fixing some bugs in the previous implementation used in the &lt;code&gt;foundation&lt;/code&gt;
primops testsuite (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15893&quot;&gt;!15893&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/issues/25969&quot;&gt;#25969&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/issues/25990&quot;&gt;#25990&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;haskell-language-server&quot;&gt;Haskell Language Server&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/zubin&quot;&gt;Zubin&lt;/a&gt; prepared release 2.14.0 of the Haskell Language Server (&lt;a href=&quot;https://github.com/haskell/haskell-language-server/pull/4897&quot;&gt;&lt;span&gt;#4897&lt;/span&gt;&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/hannes&quot;&gt;Hannes&lt;/a&gt; reviewed many HLS PRs from contributors:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/haskell/haskell-language-server/pull/4958&quot;&gt;&lt;span&gt;#4958&lt;/span&gt;&lt;/a&gt; adding
a code action to delete unused bindings,&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/haskell/haskell-language-server/pull/4913&quot;&gt;&lt;span&gt;#4913&lt;/span&gt;&lt;/a&gt; improving
the handling of &lt;code&gt;hs-boot&lt;/code&gt; files,&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/haskell/haskell-language-server/pull/4915&quot;&gt;&lt;span&gt;#4915&lt;/span&gt;&lt;/a&gt; updating
the splice plugin,&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/haskell/haskell-language-server/pull/4917&quot;&gt;&lt;span&gt;#4917&lt;/span&gt;&lt;/a&gt; preserving
qualified field names when expanding record inlay hints,&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/haskell/haskell-language-server/pull/4902&quot;&gt;&lt;span&gt;#4902&lt;/span&gt;&lt;/a&gt; excluding
internal superclass names in class placeholders,&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/haskell/haskell-language-server/pull/4886&quot;&gt;&lt;span&gt;#4886&lt;/span&gt;&lt;/a&gt; cancelling
outstanding threads when closing the SQLite connection,&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/haskell/haskell-language-server/pull/4867&quot;&gt;&lt;span&gt;#4867&lt;/span&gt;&lt;/a&gt; improving
HLS’s response for &lt;code&gt;prepareRename&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/haskell/haskell-language-server/pull/4865&quot;&gt;&lt;span&gt;#4865&lt;/span&gt;&lt;/a&gt; migrating
the Stackage build to use GitHub actions,&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/haskell/haskell-language-server/pull/4854&quot;&gt;&lt;span&gt;#4854&lt;/span&gt;&lt;/a&gt; fixing
a redundant hash in the ghcide cache path.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/hannes&quot;&gt;Hannes&lt;/a&gt; released version &lt;code&gt;0.19.0&lt;/code&gt; of &lt;code&gt;hie-bios&lt;/code&gt; (&lt;a href=&quot;https://github.com/haskell/hie-bios/pull/506&quot;&gt;&lt;span&gt;#506&lt;/span&gt;&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/sam&quot;&gt;Sam&lt;/a&gt; fixed a &lt;code&gt;hie-bios&lt;/code&gt; regression in which the local build directory would get overwritten,
leading to cache trashing (&lt;a href=&quot;https://github.com/haskell/hie-bios/issues/501&quot;&gt;&lt;span&gt;#501&lt;/span&gt;&lt;/a&gt;, &lt;a href=&quot;https://github.com/haskell/hie-bios/pull/503&quot;&gt;&lt;span&gt;#503&lt;/span&gt;&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;haskell-syntax-highlighting&quot;&gt;Haskell syntax highlighting&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/sam&quot;&gt;Sam&lt;/a&gt; fixed a &lt;a href=&quot;https://github.com/JustusAdam/language-haskell/blob/master/CHANGELOG.md#370---09062026&quot;&gt;large number of bugs&lt;/a&gt;
in the &lt;code&gt;language-haskell&lt;/code&gt; VS Code syntax highlighting extension.&lt;/p&gt;
&lt;h2 id=&quot;haskell-debugger&quot;&gt;Haskell Debugger&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/rodrigo&quot;&gt;Rodrigo&lt;/a&gt; continued to lead development of the
&lt;a href=&quot;https://github.com/well-typed/haskell-debugger&quot;&gt;Haskell Debugger&lt;/a&gt; (&lt;code&gt;hdb&lt;/code&gt;), an
interactive step-through debugger for Haskell,
with contributions from &lt;a href=&quot;https://well-typed.com/people/andrea&quot;&gt;Andrea&lt;/a&gt; and &lt;a href=&quot;https://well-typed.com/people/hannes&quot;&gt;Hannes&lt;/a&gt;.
Built on top of the bytecode
interpreter, it implements the &lt;a href=&quot;https://microsoft.github.io/debug-adapter-protocol/&quot;&gt;Debug Adapter Protocol&lt;/a&gt;,
allowing debugging of Haskell programs directly in the editor. We:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;added a new RTS message to GHC allowing a thread’s flags (TSO flags)
to be set or unset (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15831&quot;&gt;!15831&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/issues/27131&quot;&gt;#27131&lt;/a&gt;), which is needed to safely implement
features like pausing, or toggling step-out/step-in per thread;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;arranged for &lt;code&gt;hdb&lt;/code&gt; to run the debuggee directly in the terminal
when using the external interpreter
(&lt;a href=&quot;https://github.com/well-typed/haskell-debugger/pull/260&quot;&gt;&lt;span&gt;#260&lt;/span&gt;&lt;/a&gt;);&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;added support for custom external interpreter commands to GHC (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15676&quot;&gt;!15676&lt;/a&gt;),
making use of them rather than parsing heap terms (&lt;a href=&quot;https://github.com/well-typed/haskell-debugger/pull/222&quot;&gt;&lt;span&gt;#222&lt;/span&gt;&lt;/a&gt;);&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;fixed a bug where forcing a thunk would invalidate stack frames on
all threads rather than just the right one
(&lt;a href=&quot;https://github.com/well-typed/haskell-debugger/pull/292&quot;&gt;&lt;span&gt;#292&lt;/span&gt;&lt;/a&gt;), and fixed
breakpoints being overwritten by looking for active breaks in the correct
&lt;code&gt;ModBreaks&lt;/code&gt;
(&lt;a href=&quot;https://github.com/well-typed/haskell-debugger/pull/298&quot;&gt;&lt;span&gt;#298&lt;/span&gt;&lt;/a&gt;);&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;refactored the home-unit session initialisation
(&lt;a href=&quot;https://github.com/well-typed/haskell-debugger/pull/279&quot;&gt;&lt;span&gt;#279&lt;/span&gt;&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/andrea&quot;&gt;Andrea&lt;/a&gt; made various quality-of-life improvements to the debugger:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;allowing imports at the REPL
(&lt;a href=&quot;https://github.com/well-typed/haskell-debugger/pull/229&quot;&gt;&lt;span&gt;#229&lt;/span&gt;&lt;/a&gt;);&lt;/li&gt;
&lt;li&gt;bringing
interactive imports back into scope after resuming execution
(&lt;a href=&quot;https://github.com/well-typed/haskell-debugger/pull/275&quot;&gt;&lt;span&gt;#275&lt;/span&gt;&lt;/a&gt;);&lt;/li&gt;
&lt;li&gt;inheriting the entry file’s language extensions
(&lt;a href=&quot;https://github.com/well-typed/haskell-debugger/pull/230&quot;&gt;&lt;span&gt;#230&lt;/span&gt;&lt;/a&gt;);&lt;/li&gt;
&lt;li&gt;adding
&lt;code&gt;LogMessage&lt;/code&gt; support to implement log points
(&lt;a href=&quot;https://github.com/well-typed/haskell-debugger/pull/223&quot;&gt;&lt;span&gt;#223&lt;/span&gt;&lt;/a&gt;);&lt;/li&gt;
&lt;li&gt;sharing a single HDB+GHC session for use with HLS
(&lt;a href=&quot;https://github.com/well-typed/haskell-debugger/pull/308&quot;&gt;&lt;span&gt;#308&lt;/span&gt;&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;runtime-observability&quot;&gt;Runtime observability&lt;/h2&gt;
&lt;h3 id=&quot;ghc-debug&quot;&gt;&lt;code&gt;ghc-debug&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/hannes&quot;&gt;Hannes&lt;/a&gt; performed various maintenance tasks on &lt;code&gt;ghc-debug&lt;/code&gt;, a key tool for
out-of-process heap analysis of Haskell programs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;released version 0.8.0.0 (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc-debug/-/merge_requests/88&quot;&gt;&lt;span&gt;!88&lt;/span&gt;&lt;/a&gt;),&lt;/li&gt;
&lt;li&gt;bumped version bounds (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc-debug/-/merge_requests/91&quot;&gt;&lt;span&gt;!91&lt;/span&gt;&lt;/a&gt;),&lt;/li&gt;
&lt;li&gt;fixed FreeBSD support (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc-debug/-/merge_requests/89&quot;&gt;&lt;span&gt;!89&lt;/span&gt;&lt;/a&gt;),&lt;/li&gt;
&lt;li&gt;landed an old MR by Teo Camarasu, adding support for the non-moving GC (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc-debug/-/merge_requests/10&quot;&gt;&lt;span&gt;!10&lt;/span&gt;&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;eventlog-live-eventlog-socket&quot;&gt;&lt;code&gt;eventlog-live&lt;/code&gt;, &lt;code&gt;eventlog-socket&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/wen&quot;&gt;Wen&lt;/a&gt; continued to develop &lt;a href=&quot;https://github.com/well-typed/eventlog-live/&quot;&gt;&lt;code&gt;eventlog-live&lt;/code&gt;&lt;/a&gt;,
which allows GHC’s eventlog to be monitored live as a program runs.
Highlights of the changes to &lt;code&gt;eventlog-live&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;support for receiving eventlog input over TCP (&lt;a href=&quot;https://github.com/well-typed/eventlog-live/pull/154&quot;&gt;&lt;span&gt;#154&lt;/span&gt;&lt;/a&gt;, &lt;a href=&quot;https://github.com/well-typed/eventlog-live/pull/155&quot;&gt;&lt;span&gt;#155&lt;/span&gt;&lt;/a&gt;),&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;improved profiling support with cost-centre profiles
(&lt;a href=&quot;https://github.com/well-typed/eventlog-live/pull/134&quot;&gt;&lt;span&gt;#134&lt;/span&gt;&lt;/a&gt;) and
&lt;a href=&quot;https://github.com/well-typed/ghc-stack-profiler&quot;&gt;&lt;code&gt;ghc-stack-profiler&lt;/code&gt;&lt;/a&gt;
profiles (&lt;a href=&quot;https://github.com/well-typed/eventlog-live/pull/131&quot;&gt;&lt;span&gt;#131&lt;/span&gt;&lt;/a&gt;),&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;integration with the RTS control server (&lt;a href=&quot;https://github.com/well-typed/eventlog-live/pull/139&quot;&gt;&lt;span&gt;#139&lt;/span&gt;&lt;/a&gt;, &lt;a href=&quot;https://github.com/well-typed/eventlog-live/pull/122&quot;&gt;&lt;span&gt;#122&lt;/span&gt;&lt;/a&gt;,
&lt;a href=&quot;https://github.com/well-typed/eventlog-live/pull/126&quot;&gt;&lt;span&gt;#126&lt;/span&gt;&lt;/a&gt;),&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;a new demo showing &lt;code&gt;eventlog-live&lt;/code&gt; monitoring GHC itself
(&lt;a href=&quot;https://github.com/well-typed/eventlog-live/pull/138&quot;&gt;&lt;span&gt;#138&lt;/span&gt;&lt;/a&gt;,
&lt;a href=&quot;https://github.com/well-typed/eventlog-live/pull/148&quot;&gt;&lt;span&gt;#148&lt;/span&gt;&lt;/a&gt;),&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;support for GHC 9.12 (&lt;a href=&quot;https://github.com/well-typed/eventlog-live/pull/136&quot;&gt;&lt;span&gt;#136&lt;/span&gt;&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This also included a litany of improvements to the underlying
&lt;a href=&quot;https://github.com/well-typed/eventlog-socket/&quot;&gt;&lt;code&gt;eventlog-socket&lt;/code&gt;&lt;/a&gt; library:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;lifecycle hooks (&lt;a href=&quot;https://github.com/well-typed/eventlog-socket/pull/63&quot;&gt;&lt;span&gt;#63&lt;/span&gt;&lt;/a&gt;),&lt;/li&gt;
&lt;li&gt;command registration (&lt;a href=&quot;https://github.com/well-typed/eventlog-socket/pull/45&quot;&gt;&lt;span&gt;#45&lt;/span&gt;&lt;/a&gt;),&lt;/li&gt;
&lt;li&gt;support for &lt;code&gt;startProfTimer&lt;/code&gt; and &lt;code&gt;stopProfTimer&lt;/code&gt; (&lt;a href=&quot;https://github.com/well-typed/eventlog-socket/pull/65&quot;&gt;&lt;span&gt;#65&lt;/span&gt;&lt;/a&gt;),&lt;/li&gt;
&lt;li&gt;allow building with &lt;code&gt;hsc2hs&lt;/code&gt; in cross-compilation mode (&lt;a href=&quot;https://github.com/well-typed/eventlog-socket/pull/64&quot;&gt;&lt;span&gt;#64&lt;/span&gt;&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Finally, &lt;a href=&quot;https://well-typed.com/people/wen&quot;&gt;Wen&lt;/a&gt; also landed several supporting changes in GHC itself:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;fixed a race condition in the RTS between &lt;code&gt;flushEventLog&lt;/code&gt; and
starting/stopping event logging (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15750&quot;&gt;!15750&lt;/a&gt;),&lt;/li&gt;
&lt;li&gt;added a new &lt;code&gt;-lI&lt;/code&gt; eventlog flag to emit IPE events (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/16004&quot;&gt;!16004&lt;/a&gt;),&lt;/li&gt;
&lt;li&gt;added support for dynamically changing trace flags (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15936&quot;&gt;!15936&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;ghc-stack-profiler&quot;&gt;&lt;code&gt;ghc-stack-profiler&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/hannes&quot;&gt;Hannes&lt;/a&gt; continued maintaining
&lt;a href=&quot;https://github.com/well-typed/ghc-stack-profiler&quot;&gt;&lt;code&gt;ghc-stack-profiler&lt;/code&gt;&lt;/a&gt;, a
profiler that relies on stack annotations rather than heavier profiling
mechanisms:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;released version &lt;code&gt;0.2.0.0&lt;/code&gt; (&lt;a href=&quot;https://github.com/well-typed/ghc-stack-profiler/pull/24&quot;&gt;&lt;span&gt;#24&lt;/span&gt;&lt;/a&gt;);&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;made the profiler more robust, ensuring it never crashes on decoding
errors (&lt;a href=&quot;https://github.com/well-typed/ghc-stack-profiler/pull/12&quot;&gt;&lt;span&gt;#12&lt;/span&gt;&lt;/a&gt;) and
backporting a fix for stack-decoding segmentation faults from GHC HEAD
(&lt;a href=&quot;https://github.com/well-typed/ghc-stack-profiler/pull/20&quot;&gt;&lt;span&gt;#20&lt;/span&gt;&lt;/a&gt;);&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;integrated the profiler with
&lt;a href=&quot;https://github.com/well-typed/eventlog-socket&quot;&gt;&lt;code&gt;eventlog-socket&lt;/code&gt;&lt;/a&gt;, adding
support for its lifecycle hooks
(&lt;a href=&quot;https://github.com/well-typed/ghc-stack-profiler/pull/19&quot;&gt;&lt;span&gt;#19&lt;/span&gt;&lt;/a&gt;) and an
&lt;code&gt;eventlog-socket&lt;/code&gt; test suite
(&lt;a href=&quot;https://github.com/well-typed/ghc-stack-profiler/pull/25&quot;&gt;&lt;span&gt;#25&lt;/span&gt;&lt;/a&gt;);&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;improved thread management by using &lt;code&gt;async&lt;/code&gt;
(&lt;a href=&quot;https://github.com/well-typed/ghc-stack-profiler/pull/10&quot;&gt;&lt;span&gt;#10&lt;/span&gt;&lt;/a&gt;) and
exposing &lt;code&gt;stopStackProfilerThread&lt;/code&gt;
(&lt;a href=&quot;https://github.com/well-typed/ghc-stack-profiler/pull/11&quot;&gt;&lt;span&gt;#11&lt;/span&gt;&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;ihaskell&quot;&gt;&lt;code&gt;IHaskell&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/sam&quot;&gt;Sam&lt;/a&gt; added Windows support to &lt;code&gt;IHaskell&lt;/code&gt;, a library that provides Haskell
integration for Jupyter notebooks (&lt;a href=&quot;https://github.com/IHaskell/IHaskell/pull/1595&quot;&gt;&lt;span&gt;#1595&lt;/span&gt;&lt;/a&gt;).&lt;/p&gt;
&lt;h2 id=&quot;stm-library&quot;&gt;&lt;code&gt;stm&lt;/code&gt; library&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://well-typed.com/people/magnus&quot;&gt;Magnus&lt;/a&gt; performed some important maintenance tasks on the &lt;code&gt;stm&lt;/code&gt; library,
adding missing compiler versions to CI (&lt;a href=&quot;https://github.com/haskell/stm/pull/98&quot;&gt;&lt;span&gt;#98&lt;/span&gt;&lt;/a&gt;)
and fixing a slow test (&lt;a href=&quot;https://github.com/haskell/stm/pull/97&quot;&gt;&lt;span&gt;#97&lt;/span&gt;&lt;/a&gt;).&lt;/p&gt;</description>
	<pubDate>Fri, 19 Jun 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Tweag I/O: Sheaves in Haskell</title>
	<guid isPermaLink="true">https://tweag.io/blog/2026-06-18-sheaves-in-haskell/</guid>
	<link>https://tweag.io/blog/2026-06-18-sheaves-in-haskell/</link>
	<description>&lt;p&gt;I recently found a way to represent sheaves in Haskell. It was a fun couple of
weeks of head-scratching. But as much as I wanted it to, the code in my
&lt;a href=&quot;https://github.com/aspiwack/sheaf-lang-demo&quot;&gt;demonstration repo&lt;/a&gt; doesn’t speak for itself. So I’m writing this blog
post to share my newfound understanding. In this post I’ll be assuming a pretty
solid knowledge of category theory (but not of sheaves, which I’ll be
explaining). If you aren’t, wait until my next post which will give a more
practical introduction to sheaves.&lt;/p&gt;
&lt;p&gt;I don’t think it’s
necessary to use Haskell for this. Other functional programming languages should
work as well, but Haskell certainly makes some things easier as types get a bit
dependent eventually. Of course, it would be even easier in a true dependently
typed language, but the whole point was to avoid needing that level of sophistication.&lt;/p&gt;
&lt;p&gt;As a general warning: all of this is about translating well-known mathematical
concepts into Haskell. While doing so, I have to use a lot of approximations, as
Haskell doesn’t have, say, a notion of equality. I will generally not even
mention any conditions that I’m supposed to prove to properly align with the
mathematical definitions, and only focus on the operational aspects. I’ll try to
leave enough breadcrumbs to fill in the gaps for those of you who would want to.&lt;/p&gt;
&lt;h2 id=&quot;first-presheaves&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#first-presheaves&quot;&gt;&lt;/a&gt;First, presheaves&lt;/h2&gt;
&lt;p&gt;I’ll start by giving a concrete instance of sheaves, which makes the definition
surprisingly transparent. Later I’ll be expanding that to the general notion of
sheaves.&lt;/p&gt;
&lt;p&gt;Let’s give ourselves a category of arithmetic expressions, or
rather, arithmetic functions. It’s got just enough material to illustrate the point.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-haskell&quot;&gt;&lt;code class=&quot;language-haskell&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Type&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TInt&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TBool&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TUnit&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TProd&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Ty&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Type&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;where&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;Id&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;Add&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TInt&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TInt&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TInt&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;Sub&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TInt&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TInt&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TInt&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;Mult&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TInt&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TInt&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TInt&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;Unit&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TUnit&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;IsZero&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TInt&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TBool&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;IfThenElse&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TBool&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;j&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;compose&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;k&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;compose&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Id&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;e&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;compose&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Add&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Add&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;compose&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;compose&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;compose&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Sub&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Sub&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;compose&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;compose&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;compose&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Mult&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Mult&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;compose&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;compose&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;compose&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;IsZero&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;IsZero&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;compose&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;compose&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Unit&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Unit&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;compose&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;IfThenElse&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;IfThenElse&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;compose&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;compose&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;compose&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now, consider the category of presheaves over &lt;code class=&quot;language-text&quot;&gt;Expr&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-haskell&quot;&gt;&lt;code class=&quot;language-haskell&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Presheaf&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Constraint&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Presheaf&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;where&lt;/span&gt;
  &lt;span class=&quot;token hvariable&quot;&gt;pb&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;forall&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(I named the presheaves’ restriction &lt;code class=&quot;language-text&quot;&gt;pb&lt;/code&gt;, for “pullback”, because we’re going
to be writing it quite a lot.)&lt;/p&gt;
&lt;p&gt;The category of presheaves (with natural transformations &lt;code class=&quot;language-text&quot;&gt;forall i. p i -&amp;gt; q i&lt;/code&gt;
as morphisms) is a Cartesian closed category (and then some) which contains the
&lt;code class=&quot;language-text&quot;&gt;Expr&lt;/code&gt; category as a full subcategory, via the Yoneda embedding&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-haskell&quot;&gt;&lt;code class=&quot;language-haskell&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Y&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;newtype&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Y&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;MkY&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Presheaf&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Y&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;where&lt;/span&gt;
  &lt;span class=&quot;token hvariable&quot;&gt;pb&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;MkY&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;MkY&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;`compose`&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Therefore we can think of the category of presheaves as a completion of
&lt;code class=&quot;language-text&quot;&gt;Expr&lt;/code&gt; with a bunch of extra structure. And the problem that we will want
to solve is that presheaves actually add &lt;em&gt;too much&lt;/em&gt; structure. This manifests in
the impossibility of interpreting &lt;code class=&quot;language-text&quot;&gt;IfThenElse&lt;/code&gt;. Or, rather, the Yoneda embedding
lets us build a presheaf&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-haskell&quot;&gt;&lt;code class=&quot;language-haskell&quot;&gt;&lt;span class=&quot;token hvariable&quot;&gt;ifThenElse&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Y&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TBool&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Y&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Y&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Y&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But this isn’t the usual type of &lt;code class=&quot;language-text&quot;&gt;ifThenElse&lt;/code&gt;, we want instead&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-haskell&quot;&gt;&lt;code class=&quot;language-haskell&quot;&gt;&lt;span class=&quot;token hvariable&quot;&gt;ifThenElse&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Presheaf&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;forall&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Y&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Bool&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;sheaves-concretely&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#sheaves-concretely&quot;&gt;&lt;/a&gt;Sheaves, concretely&lt;/h2&gt;
&lt;p&gt;Unfortunately, we can’t define such an &lt;code class=&quot;language-text&quot;&gt;ifThenElse&lt;/code&gt; function. This is because
&lt;code class=&quot;language-text&quot;&gt;Y TBool&lt;/code&gt; isn’t a coproduct in the category of presheaves. Presheaves create
coproducts (and in fact all colimits) freely.&lt;/p&gt;
&lt;p&gt;What we &lt;em&gt;can&lt;/em&gt; do, however, is define a new type class, and we can even define it
in the most on-the-nose way possible (because nobody is stopping us).&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-haskell&quot;&gt;&lt;code class=&quot;language-haskell&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Presheaf&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Sheaf&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;where&lt;/span&gt;
  &lt;span class=&quot;token hvariable&quot;&gt;glueIfThenElse&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;forall&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TBool&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;ifThenElse&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Sheaf&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;forall&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Y&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TBool&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;ifThenElse&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;MkY&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;glueIfThenElse&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;e&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is almost insultingly straightforward, but I swear this is a mere
specialisation of the general definition of sheaves, only slightly simplified
from the definition seen in textbooks.&lt;/p&gt;
&lt;p&gt;Now, of course, sheaves support &lt;code class=&quot;language-text&quot;&gt;ifThenElse&lt;/code&gt; as we wanted, but the truly
astounding thing is that the theory of sheaves tells us that the category of
sheaves (and natural transformations &lt;code class=&quot;language-text&quot;&gt;forall i. p i -&amp;gt; q i&lt;/code&gt;) also has all the
structure we need from the category of presheaves. In particular it’s Cartesian
closed. Let’s demonstrate this next.&lt;/p&gt;
&lt;h3 id=&quot;closed-cartesianness&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#closed-cartesianness&quot;&gt;&lt;/a&gt;Closed Cartesianness&lt;/h3&gt;
&lt;p&gt;Products of sheaves are simply Haskell’s product applied fibrewise, same as with
presheaves:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-haskell&quot;&gt;&lt;code class=&quot;language-haskell&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;×&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;newtype&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; × &lt;span class=&quot;token hvariable&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;MkProd&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;q&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Presheaf&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Presheaf&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Presheaf&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; × &lt;span class=&quot;token hvariable&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;where&lt;/span&gt;
  &lt;span class=&quot;token hvariable&quot;&gt;pb&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;MkProd&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;MkProd&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;pb&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;pb&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Sheaf&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Sheaf&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Sheaf&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; × &lt;span class=&quot;token hvariable&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;where&lt;/span&gt;
  &lt;span class=&quot;token hvariable&quot;&gt;glueIfThenElse&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;MkProd&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;tp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;tq&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;MkProd&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;fq&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token constant&quot;&gt;MkProd&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;glueIfThenElse&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;tp&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;glueIfThenElse&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;tq&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;fq&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Exponential objects are more complicated. If you’ve never seen exponentials of
presheaves before, you can think of the type in terms of variance: because
&lt;code class=&quot;language-text&quot;&gt;forall i. p i -&amp;gt; q i&lt;/code&gt; is contravariant in &lt;code class=&quot;language-text&quot;&gt;p&lt;/code&gt;, we can’t implement &lt;code class=&quot;language-text&quot;&gt;pb&lt;/code&gt; for
natural transformation directly. So we freely adjoin the presheaf structure.
Here again, the construction is the same for presheaves and sheaves.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-haskell&quot;&gt;&lt;code class=&quot;language-haskell&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;PFun&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;newtype&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;PFun&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;q&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;MkPFun&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;forall&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;q&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Presheaf&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Presheaf&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Presheaf&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PFun&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;where&lt;/span&gt;
  &lt;span class=&quot;token hvariable&quot;&gt;pb&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;MkPFun&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;MkPFun&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;compose&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;x&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Presheaf&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Sheaf&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Sheaf&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PFun&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;where&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;-- This is not a typo, `p` only needs to be a presheaf.&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;-- It's occasionally useful.&lt;/span&gt;
  &lt;span class=&quot;token hvariable&quot;&gt;glueIfThenElse&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;MkPFun&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;ft&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;MkPFun&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;ff&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;MkPFun&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;$&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;glueIfThenElse&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;`compose`&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;ft&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;ff&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I found that the twist in the definition of exponentials is the source of
much of the difficulties in working with sheaves. For instance, this is why we
need &lt;code class=&quot;language-text&quot;&gt;IfThenElse&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;glueIfThenElse&lt;/code&gt; rather than this more typical way of
expressing that &lt;code class=&quot;language-text&quot;&gt;TBool&lt;/code&gt; is a coproduct of &lt;code class=&quot;language-text&quot;&gt;Unit&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;Unit&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-haskell&quot;&gt;&lt;code class=&quot;language-haskell&quot;&gt;&lt;span class=&quot;token hvariable&quot;&gt;cocone&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TUnit&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TUnit&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TBool&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;cocone&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;IfThenElse&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Id&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Unit&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;`compose`&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Unit&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;`compose`&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;glueCocone&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TUnit&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TUnit&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TBool&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;glueCocone&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;glueIfThenElse&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Id&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;pb&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Unit&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;pb&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Unit&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It turns out that &lt;code class=&quot;language-text&quot;&gt;IfThenElse&lt;/code&gt; is, in fact, strictly stronger than &lt;code class=&quot;language-text&quot;&gt;cocone&lt;/code&gt; in
general. I started the project believing them to be equivalent, but they
aren’t in general. They are equivalent in a Cartesian closed category (among
other things) though, but &lt;code class=&quot;language-text&quot;&gt;Expr&lt;/code&gt; isn’t Cartesian closed. Textbooks also
have a version of &lt;code class=&quot;language-text&quot;&gt;glueCocone&lt;/code&gt;, specifically that sheaves must verify that
&lt;code class=&quot;language-text&quot;&gt;p TBool&lt;/code&gt; must be isomorphic to a pair &lt;code class=&quot;language-text&quot;&gt;p TUnit&lt;/code&gt;. Realising that this condition
wasn’t sufficient to prove that &lt;code class=&quot;language-text&quot;&gt;PFun p q&lt;/code&gt; was a sheaf took me a while; and this
is how, dear reader, one loses nights of sleep.&lt;/p&gt;
&lt;h3 id=&quot;yoneda-embeddings-as-sheaves&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#yoneda-embeddings-as-sheaves&quot;&gt;&lt;/a&gt;Yoneda embeddings as sheaves&lt;/h3&gt;
&lt;p&gt;Another thing, with our definition of sheaves, is that the Yoneda embeddings
of objects &lt;code class=&quot;language-text&quot;&gt;Ty&lt;/code&gt; are sheaves. This won’t always be the case for the general
notion of sheaves below, though.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-haskell&quot;&gt;&lt;code class=&quot;language-haskell&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Sheaf&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Y&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;where&lt;/span&gt;
  &lt;span class=&quot;token hvariable&quot;&gt;glueIfThenElse&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;MkY&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;MkY&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;MkY&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;IfThenElse&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;f&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;coproducts-of-sheaves&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#coproducts-of-sheaves&quot;&gt;&lt;/a&gt;Coproducts of sheaves&lt;/h3&gt;
&lt;p&gt;The category of sheaves also has coproducts, but they aren’t the same as that of
presheaves. Coproducts of presheaves are defined fibrewise like products, but as
we’ve been saying this is “too free”, in that it creates a coproduct for &lt;code class=&quot;language-text&quot;&gt;TUnit&lt;/code&gt;
and &lt;code class=&quot;language-text&quot;&gt;TUnit&lt;/code&gt; which is distinct from &lt;code class=&quot;language-text&quot;&gt;TBool&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Fortunately, there’s a technical device which makes
defining coproducts of sheaves easy: the free sheaf construction, also known as sheafification.
It turns out that we can construct a free sheaf out of any presheaf, and the way
you do that is to simply store all the uses of &lt;code class=&quot;language-text&quot;&gt;glueIfThenElse&lt;/code&gt; instead of
running them (much like &lt;code class=&quot;language-text&quot;&gt;PFun&lt;/code&gt; stores all the uses of &lt;code class=&quot;language-text&quot;&gt;pb&lt;/code&gt; instead of running
them):&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-haskell&quot;&gt;&lt;code class=&quot;language-haskell&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Sheafify&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;where&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;Ret&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Sheafify&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;ShIfThenElse&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TBool&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Sheafify&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Sheafify&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Sheafify&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Presheaf&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Sheaf&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Sheafify&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;where&lt;/span&gt;
  &lt;span class=&quot;token hvariable&quot;&gt;glueIfThenElse&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;ShIfThenElse&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Presheaf&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Presheaf&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Sheafify&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;where&lt;/span&gt;
  &lt;span class=&quot;token hvariable&quot;&gt;pb&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Ret&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Ret&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;pf&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token hvariable&quot;&gt;pb&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;ShIfThenElse&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;ShIfThenElse&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;pb&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;pb&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;pb&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The coproduct of two sheaves is simply the sheafification of their coproduct as
presheaves.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-haskell&quot;&gt;&lt;code class=&quot;language-haskell&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;newtype&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;PSum&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;q&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;MkPSum&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Either&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;q&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Presheaf&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Presheaf&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Presheaf&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PSum&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;where&lt;/span&gt;
  &lt;span class=&quot;token hvariable&quot;&gt;pb&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PSum&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Left&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;PSum&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Left&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;pb&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token hvariable&quot;&gt;pb&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PSum&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Right&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;PSum&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Right&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;pb&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;ShSum&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;q&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Sheafify&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PSum&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;-- Therefore:&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;-- instance (Sheaf p, Sheaf q) =&amp;gt; Sheaf (ShSum p q))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can also define recursive data types like lists (in categorical terms,
polynomial endofunctors have initial algebras), you just have to make sure to
wrap all the recursive calls with &lt;code class=&quot;language-text&quot;&gt;Sheafify&lt;/code&gt;. The easiest way is to inline
&lt;code class=&quot;language-text&quot;&gt;Sheafify&lt;/code&gt; like so:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-haskell&quot;&gt;&lt;code class=&quot;language-haskell&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;ShList&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;where&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;ShNil&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;ShList&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;ShCons&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;ShList&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;ShList&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;ListIfThenElse&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TBool&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;ShList&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;ShList&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;ShList&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;sheaves-generally&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#sheaves-generally&quot;&gt;&lt;/a&gt;Sheaves, generally&lt;/h2&gt;
&lt;p&gt;Now we have the general idea set up. Let’s tackle the general notion of
sheaves. First we can get rid of &lt;code class=&quot;language-text&quot;&gt;Expr&lt;/code&gt;, and use an arbitrary category as
a base.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-haskell&quot;&gt;&lt;code class=&quot;language-haskell&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- The `Category` class from base.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Category&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;forall&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Constraint&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Category&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;hom&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;where&lt;/span&gt;
  &lt;span class=&quot;token builtin&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;hom&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;a&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;hom&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;hom&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;hom&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;c&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Presheaves readily generalise to arbitrary categories&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-haskell&quot;&gt;&lt;code class=&quot;language-haskell&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Presheaf&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;forall&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Constraint&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Presheaf&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;hom&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;where&lt;/span&gt;
  &lt;span class=&quot;token hvariable&quot;&gt;pb&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;hom&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;a&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;topology-sites&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#topology-sites&quot;&gt;&lt;/a&gt;Topology, sites&lt;/h3&gt;
&lt;p&gt;We will need an extra piece of data in order to define sheaves, called a
&lt;em&gt;Grothendieck topology&lt;/em&gt; (I’ll just be saying “topology”). This will be the part
that lets us choose which objects of the base category are to be colimits in the
category of sheaves.&lt;/p&gt;
&lt;p&gt;Before I show how we can represent topologies in Haskell, let us make a small
detour and examine the textbook definition of sheaves (and reverting to
mathematical notation for a moment). First a new notion: a sieve on an object
&lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&amp;lt;semantics&amp;gt;a&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;a&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height: 0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is a set of arrows with codomain &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&amp;lt;semantics&amp;gt;a&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;a&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height: 0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; closed by precomposition. That is a
set &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&amp;lt;semantics&amp;gt;S&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;S&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height: 0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;S&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, such that for any &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&amp;lt;semantics&amp;gt;(x&amp;lt;mover&amp;gt;&amp;lt;mo&amp;gt;&amp;lt;mo&amp;gt;⟶&amp;lt;/mo&amp;gt;&amp;lt;/mo&amp;gt;&amp;lt;mi&amp;gt;f&amp;lt;/mi&amp;gt;&amp;lt;/mover&amp;gt;a)∈S&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;(x \stackrel{f}{\longrightarrow} a)\in S&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;&lt;span class=&quot;mop op-limits&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height: 1.3442em;&quot;&gt;&lt;span&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height: 3em;&quot;&gt;&lt;/span&gt;&lt;span&gt;&lt;span class=&quot;mop&quot;&gt;⟶&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height: 3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;f&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height: 0.011em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;∈&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height: 0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;S&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; and
any arrow &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&amp;lt;semantics&amp;gt;(y&amp;lt;mover&amp;gt;&amp;lt;mo&amp;gt;&amp;lt;mo&amp;gt;⟶&amp;lt;/mo&amp;gt;&amp;lt;/mo&amp;gt;&amp;lt;mi&amp;gt;g&amp;lt;/mi&amp;gt;&amp;lt;/mover&amp;gt;x)&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;(y \stackrel{g}{\longrightarrow} x)&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;&lt;span class=&quot;mop op-limits&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height: 1.1595em;&quot;&gt;&lt;span&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height: 3em;&quot;&gt;&lt;/span&gt;&lt;span&gt;&lt;span class=&quot;mop&quot;&gt;⟶&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height: 3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height: 0.011em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, we also have &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&amp;lt;semantics&amp;gt;(y&amp;lt;mover&amp;gt;&amp;lt;mo&amp;gt;&amp;lt;mo&amp;gt;⟶&amp;lt;/mo&amp;gt;&amp;lt;/mo&amp;gt;&amp;lt;mi&amp;gt;g&amp;lt;/mi&amp;gt;&amp;lt;/mover&amp;gt;x&amp;lt;mover&amp;gt;&amp;lt;mo&amp;gt;&amp;lt;mo&amp;gt;⟶&amp;lt;/mo&amp;gt;&amp;lt;/mo&amp;gt;&amp;lt;mi&amp;gt;f&amp;lt;/mi&amp;gt;&amp;lt;/mover&amp;gt;a)∈S&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;(y
\stackrel{g}{\longrightarrow} x \stackrel{f}{\longrightarrow} a)\in S&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;&lt;span class=&quot;mop op-limits&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height: 1.1595em;&quot;&gt;&lt;span&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height: 3em;&quot;&gt;&lt;/span&gt;&lt;span&gt;&lt;span class=&quot;mop&quot;&gt;⟶&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height: 3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height: 0.011em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;&lt;span class=&quot;mop op-limits&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height: 1.3442em;&quot;&gt;&lt;span&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height: 3em;&quot;&gt;&lt;/span&gt;&lt;span&gt;&lt;span class=&quot;mop&quot;&gt;⟶&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height: 3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;f&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height: 0.011em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;∈&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height: 0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;S&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. A
topology is a set of such sieves (subject to some axioms). Sieves in a topology
are called &lt;em&gt;covering sieves&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Let &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&amp;lt;semantics&amp;gt;P&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;P&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height: 0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;P&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; be a presheaf. A matching
family in &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&amp;lt;semantics&amp;gt;P&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;P&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height: 0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;P&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, for a covering sieve &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&amp;lt;semantics&amp;gt;S&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;S&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height: 0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;S&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; on &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&amp;lt;semantics&amp;gt;a&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;a&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height: 0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, is a function &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&amp;lt;semantics&amp;gt;m&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;m&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height: 0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; mapping each
&lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&amp;lt;semantics&amp;gt;(x&amp;lt;mover&amp;gt;&amp;lt;mo&amp;gt;&amp;lt;mo&amp;gt;⟶&amp;lt;/mo&amp;gt;&amp;lt;/mo&amp;gt;&amp;lt;mi&amp;gt;f&amp;lt;/mi&amp;gt;&amp;lt;/mover&amp;gt;a)∈S&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;(x \stackrel{f}{\longrightarrow} a)\in S&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;&lt;span class=&quot;mop op-limits&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height: 1.3442em;&quot;&gt;&lt;span&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height: 3em;&quot;&gt;&lt;/span&gt;&lt;span&gt;&lt;span class=&quot;mop&quot;&gt;⟶&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height: 3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;f&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height: 0.011em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;∈&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height: 0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;S&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; to &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&amp;lt;semantics&amp;gt;mf∈P(x)&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;m_f ∈ P(x)&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height: 0.3361em;&quot;&gt;&lt;span&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height: 2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;f&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height: 0.2861em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;∈&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, such that &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&amp;lt;semantics&amp;gt;mf.g=pb(g)(mf)&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;m_{f . g} = \mathsf{pb}(g) (m_f)&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height: 0.3361em;&quot;&gt;&lt;span&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height: 2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mord mtight&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height: 0.2861em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathsf&quot;&gt;pb&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height: 0.3361em;&quot;&gt;&lt;span&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height: 2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;f&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height: 0.2861em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. Then,
&lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&amp;lt;semantics&amp;gt;P&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;P&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height: 0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;P&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is a sheaf if for every such matching family &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&amp;lt;semantics&amp;gt;m&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;m&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height: 0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, there is a unique &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&amp;lt;semantics&amp;gt;glue(m)∈P(a)&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;\mathsf{glue}(m) \in P(a)&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathsf&quot;&gt;glue&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;∈&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
such that &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&amp;lt;semantics&amp;gt;mf=pb(f)(glue(m))&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;m_f = \mathsf{pb}(f) (\mathsf{glue}(m))&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height: 0.3361em;&quot;&gt;&lt;span&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height: 2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;f&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height: 0.2861em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathsf&quot;&gt;pb&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathsf&quot;&gt;glue&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; for all &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&amp;lt;semantics&amp;gt;f∈S&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;f ∈ S&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;∈&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height: 0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;S&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Now, this is an extraordinarily compact definition. It achieves a lot in just a
handful of axioms. But it’s also a very wasteful definition. The definition of
sieves requires that all the &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&amp;lt;semantics&amp;gt;(y&amp;lt;mover&amp;gt;&amp;lt;mo&amp;gt;&amp;lt;mo&amp;gt;⟶&amp;lt;/mo&amp;gt;&amp;lt;/mo&amp;gt;&amp;lt;mi&amp;gt;g&amp;lt;/mi&amp;gt;&amp;lt;/mover&amp;gt;x&amp;lt;mover&amp;gt;&amp;lt;mo&amp;gt;&amp;lt;mo&amp;gt;⟶&amp;lt;/mo&amp;gt;&amp;lt;/mo&amp;gt;&amp;lt;mi&amp;gt;f&amp;lt;/mi&amp;gt;&amp;lt;/mover&amp;gt;a)∈S&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;(y \stackrel{g}{\longrightarrow} x \stackrel{f}{\longrightarrow} a)\in S&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;&lt;span class=&quot;mop op-limits&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height: 1.1595em;&quot;&gt;&lt;span&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height: 3em;&quot;&gt;&lt;/span&gt;&lt;span&gt;&lt;span class=&quot;mop&quot;&gt;⟶&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height: 3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height: 0.011em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;&lt;span class=&quot;mop op-limits&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height: 1.3442em;&quot;&gt;&lt;span&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height: 3em;&quot;&gt;&lt;/span&gt;&lt;span&gt;&lt;span class=&quot;mop&quot;&gt;⟶&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height: 3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;f&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height: 0.011em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;∈&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height: 0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;S&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
are arguments of &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&amp;lt;semantics&amp;gt;m&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;m&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height: 0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, but at the same time that &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&amp;lt;semantics&amp;gt;mf.g&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;m_{f . g}&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height: 0.3361em;&quot;&gt;&lt;span&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height: 2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mord mtight&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height: 0.2861em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is determined by &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&amp;lt;semantics&amp;gt;mf&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;m_f&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height: 0.3361em;&quot;&gt;&lt;span&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height: 2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;f&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height: 0.2861em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;This is very unsatisfactory from a functional programming perspective, as we like
to make illegal things unrepresentable, but the mathematical definition gives us
infinitely many ways to represent illegal states. Besides, having many
irrelevant values to take into account adds unwanted noise to our programs.&lt;/p&gt;
&lt;p&gt;Even if you are fine with those issues, there’s a bigger problem. The
implementation of gluing for exponentials (much for the same reason as exponentials
needing the full &lt;code class=&quot;language-text&quot;&gt;IfThenElse&lt;/code&gt; rather than merely &lt;code class=&quot;language-text&quot;&gt;cocone&lt;/code&gt;) necessarily involves a
sieve, called the pullback sieve &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&amp;lt;semantics&amp;gt;f∗S&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;f^*S&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height: 0.6887em;&quot;&gt;&lt;span&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height: 2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mbin mtight&quot;&gt;∗&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;S&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; where (&lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&amp;lt;semantics&amp;gt;b&amp;lt;mover&amp;gt;&amp;lt;mo&amp;gt;&amp;lt;mo&amp;gt;⟶&amp;lt;/mo&amp;gt;&amp;lt;/mo&amp;gt;&amp;lt;mi&amp;gt;f&amp;lt;/mi&amp;gt;&amp;lt;/mover&amp;gt;a)&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;b \stackrel{f}{\longrightarrow}
a)&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;&lt;span class=&quot;mop op-limits&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height: 1.3442em;&quot;&gt;&lt;span&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height: 3em;&quot;&gt;&lt;/span&gt;&lt;span&gt;&lt;span class=&quot;mop&quot;&gt;⟶&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height: 3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;f&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height: 0.011em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is an arrow and &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&amp;lt;semantics&amp;gt;S&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;S&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height: 0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;S&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is a sieve on &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&amp;lt;semantics&amp;gt;a&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;a&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height: 0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;; &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&amp;lt;semantics&amp;gt;f∗S&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;f^*S&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height: 0.6887em;&quot;&gt;&lt;span&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height: 2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mbin mtight&quot;&gt;∗&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;S&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is, then, a sieve on &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&amp;lt;semantics&amp;gt;b&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;b&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height: 0.6944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;.
And this is too much dependent typing for even Haskell. I’ve
tried to make it work but couldn’t.&lt;/p&gt;
&lt;p&gt;Which leads us to our first simplification: we don’t need covering sieves, we
can consider arbitrary covering families of arrows (the corresponding covering
sieve is the sieve generated by those arrows, but it’ll only exist in our head). Our second simplification
is that we don’t even need covering families to be families of arrows:
arbitrary types will do. This will remove most of the obstacles, and the
pullback sieve won’t show up at all.&lt;/p&gt;
&lt;p&gt;In ordinary mathematics, a topology is a set of sets. The natural way to
represent this in types is as a type indexed by another type, which yields our
definition of topology, or rather of a &lt;em&gt;site&lt;/em&gt;: a category equipped with a
topology.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-haskell&quot;&gt;&lt;code class=&quot;language-haskell&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Site&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;forall&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Constraint&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Category&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;hom&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Site&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;hom&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;where&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Cover&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;hom&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Type&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Gen&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;hom&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Cover&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;hom&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Type&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Where &lt;code class=&quot;language-text&quot;&gt;Cover hom a&lt;/code&gt; is the type of covering families of &lt;code class=&quot;language-text&quot;&gt;a&lt;/code&gt; (typically,
&lt;code class=&quot;language-text&quot;&gt;Cover hom a&lt;/code&gt; is simply an enum of names), and &lt;code class=&quot;language-text&quot;&gt;Gen hom c&lt;/code&gt; is the type of elements of
the covering family &lt;code class=&quot;language-text&quot;&gt;c&lt;/code&gt; (which we think of as generating a covering sieve, hence
the name).&lt;/p&gt;
&lt;h3 id=&quot;sheaves-on-a-site&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#sheaves-on-a-site&quot;&gt;&lt;/a&gt;Sheaves on a site&lt;/h3&gt;
&lt;p&gt;Now sheaves are given by the following type class:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-haskell&quot;&gt;&lt;code class=&quot;language-haskell&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Site&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;hom&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Presheaf&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;hom&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Sheaf&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;hom&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;where&lt;/span&gt;
  &lt;span class=&quot;token hvariable&quot;&gt;glue&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;forall&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Cover&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;hom&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;hom&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;forall&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Gen&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;hom&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;x&lt;/span&gt; × &lt;span class=&quot;token hvariable&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;b&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(I’ve cheated a little and assumed that the underlying category is Cartesian; we
can get rid of this hypothesis by replacing &lt;code class=&quot;language-text&quot;&gt;p (k × b)&lt;/code&gt; with the equivalent, but
considerably more heavyweight, &lt;code class=&quot;language-text&quot;&gt;PFun (Y x) p b&lt;/code&gt;)&lt;/p&gt;
&lt;p&gt;This definition includes one trick that I haven’t described yet: with a cover
&lt;code class=&quot;language-text&quot;&gt;c :: Cover hom a&lt;/code&gt; instead of gluing only at type &lt;code class=&quot;language-text&quot;&gt;p a&lt;/code&gt;, we need to be able to glue
at type &lt;code class=&quot;language-text&quot;&gt;p b&lt;/code&gt; for any arrow &lt;code class=&quot;language-text&quot;&gt;f :: hom b a&lt;/code&gt;. This is how we avoid having to talk
about a pullback sieve. And this also seems to be why generators don’t need to
be actual arrows.&lt;/p&gt;
&lt;p&gt;To elucidate this definition, let’s see how to instantiate it to &lt;code class=&quot;language-text&quot;&gt;Expr&lt;/code&gt;&lt;sup id=&quot;fnref-1&quot;&gt;&lt;a class=&quot;footnote-ref&quot; href=&quot;https://www.tweag.io/rss.xml#fn-1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-haskell&quot;&gt;&lt;code class=&quot;language-haskell&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Site&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;where&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Cover&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;where&lt;/span&gt;
    &lt;span class=&quot;token constant&quot;&gt;BoolCover&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Cover&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TBool&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Gen&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;where&lt;/span&gt;
    &lt;span class=&quot;token constant&quot;&gt;TrueCovers&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Gen&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;BoolCover&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TUnit&lt;/span&gt;
    &lt;span class=&quot;token constant&quot;&gt;FalseCovers&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Gen&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;BoolCover&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TUnit&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;glueIfThenElse&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Sheaf&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TBool&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;glueIfThenElse&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;glue&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;BoolCover&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;TrueCovers&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;pb&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;snd&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;t&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;FalseCovers&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;pb&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;snd&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;f&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To show a bigger example, one that makes use of the &lt;code class=&quot;language-text&quot;&gt;x&lt;/code&gt; parameter in &lt;code class=&quot;language-text&quot;&gt;p (x × b)&lt;/code&gt;
(so far we’ve simply ignored &lt;code class=&quot;language-text&quot;&gt;x&lt;/code&gt;, since it’s always been equal to &lt;code class=&quot;language-text&quot;&gt;Bool&lt;/code&gt;), let’s
extend the arithmetic expressions with a sum type:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-haskell&quot;&gt;&lt;code class=&quot;language-haskell&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;SumTy&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; … &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TSum&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;b&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;SumExpr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;where&lt;/span&gt;
  … &lt;span class=&quot;token comment&quot;&gt;-- Like Expr&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;Left&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;SumExpr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;SumExpr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;TSum&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;Right&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;SumExpr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;SumExpr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;TSum&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;Case&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;SumExpr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;TSum&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;SumExpr&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;k&lt;/span&gt; × &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;SumExpr&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;j&lt;/span&gt; × &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;SumExpr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;l&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In order to be able to pattern match on sums in the category of sheaves, we will
have to add a cover for &lt;code class=&quot;language-text&quot;&gt;TSum&lt;/code&gt;. As the type of &lt;code class=&quot;language-text&quot;&gt;Case&lt;/code&gt; suggests, we will use the
&lt;code class=&quot;language-text&quot;&gt;x&lt;/code&gt; parameter to pass the value contained in &lt;code class=&quot;language-text&quot;&gt;Left&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;Right&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-haskell&quot;&gt;&lt;code class=&quot;language-haskell&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Site&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;SumExpr&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;where&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Cover&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;SumExpr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;where&lt;/span&gt;
    &lt;span class=&quot;token constant&quot;&gt;BoolCover&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Cover&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;SumExpr&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TBool&lt;/span&gt;
    &lt;span class=&quot;token constant&quot;&gt;SumCover&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;forall&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Cover&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;SumExpr&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;a&lt;/span&gt; `&lt;span class=&quot;token constant&quot;&gt;TSum&lt;/span&gt;` &lt;span class=&quot;token hvariable&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Gen&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;SumExpr&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;where&lt;/span&gt;
    &lt;span class=&quot;token constant&quot;&gt;TrueCovers&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Gen&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;SumExpr&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;BoolCover&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TUnit&lt;/span&gt;
    &lt;span class=&quot;token constant&quot;&gt;FalseCovers&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Gen&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;SumExpr&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;BoolCover&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TUnit&lt;/span&gt;

    &lt;span class=&quot;token constant&quot;&gt;LeftCovers&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Gen&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;SumExpr&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;SumCover&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;a&lt;/span&gt;
    &lt;span class=&quot;token constant&quot;&gt;RightCovers&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Gen&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;SumExpr&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;SumCover&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;b&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is equivalent to saying that sheaves for &lt;code class=&quot;language-text&quot;&gt;SumExpr&lt;/code&gt; have two gluing
functions, &lt;code class=&quot;language-text&quot;&gt;glueIfThenElse&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;glueCase&lt;/code&gt;, such that in &lt;code class=&quot;language-text&quot;&gt;glueCase&lt;/code&gt; the &lt;code class=&quot;language-text&quot;&gt;Left&lt;/code&gt;
alternative is passed an &lt;code class=&quot;language-text&quot;&gt;a&lt;/code&gt; and the &lt;code class=&quot;language-text&quot;&gt;Right&lt;/code&gt; alternative is passed a &lt;code class=&quot;language-text&quot;&gt;b&lt;/code&gt;, like
we expect of a &lt;code class=&quot;language-text&quot;&gt;case&lt;/code&gt; expression.&lt;/p&gt;
&lt;p&gt;Now, all instances from the previous section can be written in this abstract
style. Except the instance for the Yoneda embedding. In particular, if you add a
covering family for an object which isn’t a colimit in the base category, then
the Yoneda embedding won’t yield sheaves. If you want to look this up,
topologies where the Yoneda embedding only yields sheaves are called
&lt;a href=&quot;https://ncatlab.org/nlab/show/subcanonical+coverage&quot;&gt;subcanonical&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;further-reading-and-final-thoughts&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#further-reading-and-final-thoughts&quot;&gt;&lt;/a&gt;Further reading and final thoughts&lt;/h2&gt;
&lt;p&gt;If you want to see the actual instances for the abstract definition of sheaves,
&lt;a href=&quot;https://github.com/aspiwack/sheaf-lang-demo/blob/fb72ef5cd372a2e67e028cce38eaaa068e546e6c/src/Sheaf.hs&quot;&gt;you’ll find them in this file&lt;/a&gt;. In there the site is actually
concrete, but the instances are written as if it were abstract.&lt;/p&gt;
&lt;p&gt;For those who want to read even more, I wrote some other thoughts on the project
&lt;a href=&quot;https://bsky.app/profile/aspiwack.bsky.social/post/3mk24fcpik22g&quot;&gt;on Bluesky&lt;/a&gt; which you may enjoy. If you are type-theory inclined, you
will probably enjoy &lt;a href=&quot;https://inria.hal.science/hal-04251754&quot;&gt;Pierre-Marie Pédrot’s &lt;em&gt;Pursuing Shtuck&lt;/em&gt;&lt;/a&gt;, it helped
me a lot with figuring these things out (it left quite direct a mark on the
project – for instance I lifted the definition of the sheafification functor
directly from there).&lt;/p&gt;
&lt;p&gt;When I started trying to implement sheaves I didn’t know whether it would work.
Sometimes it pays to be stubborn enough. But also, implementing a project like
this lets you confront the finer details. Here’s one: in my definition of
&lt;code class=&quot;language-text&quot;&gt;Expr&lt;/code&gt; there is no fixed point. Recursive functions like &lt;code class=&quot;language-text&quot;&gt;fact&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;fib&lt;/code&gt;
simply compile to infinite &lt;code class=&quot;language-text&quot;&gt;Expr&lt;/code&gt; trees (which is fine as long as you keep
&lt;code class=&quot;language-text&quot;&gt;Expr&lt;/code&gt; lazy enough). And the truth is: I don’t know how to add fixed
points in a way that could be lifted to sheaves (via a sheaf condition or
otherwise). It might not be possible at all (if you know something about that,
get in touch!). Anyway, now, at least, I know what I don’t know.&lt;/p&gt;
&lt;section class=&quot;acknowledgements&quot;&gt;
&lt;p&gt;[2026-06-22] Many thanks to Sjoerd Visscher who spotted an inexcusable amount of typos in
this post as I first published it.&lt;/p&gt;
&lt;/section&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn-1&quot;&gt;We can, conversely, derive &lt;code class=&quot;language-text&quot;&gt;glue&lt;/code&gt; from &lt;code class=&quot;language-text&quot;&gt;glueIfThenElse&lt;/code&gt; using the fact
that a pair of &lt;code class=&quot;language-text&quot;&gt;p i&lt;/code&gt; is isomorphic to a function &lt;code class=&quot;language-text&quot;&gt;Bool -&amp;gt; p i&lt;/code&gt;. But this
requires singleton types to deal with the dependent quantification of the
cover &lt;code class=&quot;language-text&quot;&gt;c&lt;/code&gt;. To avoid obscuring the presentation, I’m not showing the converse
direction in this already-too-long blog post.&lt;a class=&quot;footnote-backref&quot; href=&quot;https://www.tweag.io/rss.xml#fnref-1&quot;&gt;↩&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description>
	<pubDate>Thu, 18 Jun 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Abhinav Sarkar: Nix for Haskell: Static Builds</title>
	<guid isPermaLink="false">https://abhinavsarkar.net/posts/nix-for-haskell-static-builds/</guid>
	<link>https://abhinavsarkar.net/posts/nix-for-haskell-static-builds/?mtm_campaign=feed</link>
	<description>&lt;p&gt;In the &lt;a href=&quot;https://abhinavsarkar.net/posts/nix-for-haskell/?mtm_campaign=feed&quot;&gt;previous post&lt;/a&gt;, we learned how to get started with managing and building a &lt;a href=&quot;https://haskell.org&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Haskell&lt;/a&gt; project with &lt;a href=&quot;https://nixos.org&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Nix&lt;/a&gt;. In this post, we learn how to easily create statically-linked executables for Haskell projects with Nix.&lt;/p&gt;
&lt;p&gt;This post was originally published on &lt;a href=&quot;https://abhinavsarkar.net/posts/nix-for-haskell-static-builds/?mtm_campaign=feed&quot;&gt;abhinavsarkar.net&lt;/a&gt;.&lt;/p&gt;&lt;section class=&quot;series-info&quot;&gt;
  &lt;p&gt;This post is a part of the series: &lt;strong&gt;Nix for Haskell&lt;/strong&gt;.&lt;/p&gt;
  &lt;ol&gt;
    &lt;li&gt;
      
       &lt;a href=&quot;https://abhinavsarkar.net/posts/nix-for-haskell/?mtm_campaign=feed&quot;&gt;Getting Started&lt;/a&gt; 
    &lt;/li&gt;
    &lt;li&gt;
       &lt;strong&gt;Static Builds&lt;/strong&gt; ğŸ‘ˆ
      
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/section&gt;

&lt;nav class=&quot;right-toc&quot; id=&quot;toc&quot;&gt;&lt;h3&gt;Contents&lt;/h3&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#static-builds&quot;&gt;Static Builds&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#enabling-static-builds-in-ghc&quot;&gt;Enabling Static Builds in GHC&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#configuring-the-application&quot;&gt;Configuring the Application&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#rooting-static-build-dependencies&quot;&gt;Rooting Static Build Dependencies&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#finale&quot;&gt;Finale&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#bonus-building-a-docker-image&quot;&gt;Bonus: Building a Docker Image&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/nav&gt;
&lt;p&gt;I recommend going through the &lt;a href=&quot;https://abhinavsarkar.net/posts/nix-for-haskell/?mtm_campaign=feed&quot;&gt;previous post&lt;/a&gt;, because we are going to start off from where we left last time (ignoring the bonus sections). This is how our projectâ€™s directory tree looks at this point:&lt;/p&gt;
&lt;pre class=&quot;plain&quot;&gt;&lt;code&gt;.
|â€” app
|Â  |â€” Main.hs
|â€” ftr.cabal
|â€” nix
|Â  |â€” nixpkgs.nix
|Â  |â€” sources.json
|Â  |â€” sources.nix
|â€” package.nix
|â€” shell.nix&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Main.hs&lt;/code&gt; is the default generated main file that prints â€œHello, Haskell!â€�. &lt;code&gt;ftr.cabal&lt;/code&gt; is the default generated &lt;a href=&quot;https://www.haskell.org/cabal/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Cabal&lt;/a&gt; file. &lt;code&gt;sources.(json|nix)&lt;/code&gt; are generated by &lt;a href=&quot;https://github.com/nmattia/niv&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Niv&lt;/a&gt; to pin &lt;a href=&quot;https://github.com/NixOS/nixpkgs/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Nixpkgs&lt;/a&gt; to a particular revision. &lt;a href=&quot;https://abhinavsarkar.net/posts/nix-for-haskell/?mtm_campaign=feed#nixpkgs_nix&quot;&gt;&lt;code&gt;nixpkgs.nix&lt;/code&gt;&lt;/a&gt; provides the nixpkgs that we use for building tools and dependencies. &lt;a href=&quot;https://abhinavsarkar.net/posts/nix-for-haskell/?mtm_campaign=feed#package_nix&quot;&gt;&lt;code&gt;package.nix&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://abhinavsarkar.net/posts/nix-for-haskell/?mtm_campaign=feed#shell_nix&quot;&gt;&lt;code&gt;shell.nix&lt;/code&gt;&lt;/a&gt; build the package and manage the Nix shell respectively. We are not going to touch any of these files in this post. Letâ€™s get started.&lt;/p&gt;
&lt;h2 id=&quot;static-builds&quot;&gt;Static Builds&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#static-builds&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A &lt;a href=&quot;https://en.wikipedia.org/wiki/static_build&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;static build&lt;/a&gt; is an executable that is statically-linked against all the libraries it depends on. This is in contrast to a dynamically-linked executable, which contains references to the libraries it depends on, and those libraries are loaded and linked when the executable runs. While dynamic linking has its &lt;a href=&quot;https://en.wikipedia.org/wiki/Static_build#Dynamic_linking&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot; title=&quot;Benefits of dynamic linking&quot;&gt;benefits&lt;/a&gt;, the main advantage of static linking is that the executable can be shipped by itself, without needing to ship or install dependency libraries. This makes it quite attractive for deploying backend services. You download and deploy that one binary executable file and you are done! No need to care about installing and maintaining its dependencies.&lt;/p&gt;
&lt;p&gt;Many compilers support static buildsâ€”&lt;a href=&quot;https://golang.org/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Go&lt;/a&gt; and &lt;a href=&quot;https://www.rust-lang.org/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Rust&lt;/a&gt; being two. Haskell compiler &lt;a href=&quot;https://www.haskell.org/ghc/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;GHC&lt;/a&gt; also supports it, but not out-of-the-box. To statically link a Haskell executable, we need to configure GHC itself, and then configure the executable build as well. We also need to configure GHC to link with &lt;a href=&quot;https://en.wikipedia.org/wiki/musl&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;musl&lt;/a&gt; libc. Thatâ€™s where Nix helps us by smoothing out the process&lt;a class=&quot;footnote-ref&quot; href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#fn1&quot; id=&quot;fnref1&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;enabling-static-builds-in-ghc&quot;&gt;Enabling Static Builds in GHC&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#enabling-static-builds-in-ghc&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As mentioned, first we need a GHC configured to do static builds. We create a nixpkgs derivation, separate from &lt;a href=&quot;https://abhinavsarkar.net/posts/nix-for-haskell/?mtm_campaign=feed#nixpkgs_nix&quot;&gt;&lt;code&gt;nixpkgs.nix&lt;/code&gt;&lt;/a&gt;, that contains the custom configured GHC.&lt;/p&gt;
&lt;figure&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot;&gt;&lt;pre class=&quot;sourceCode nix noNumberSource&quot;&gt;&lt;code class=&quot;sourceCode nix&quot;&gt;&lt;span id=&quot;cb2-1&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-2&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;arch&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-3&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;ghcVersion&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bu&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;./nixpkgs.nix&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;}).&lt;/span&gt;haskellPackages&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;ghc&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;version&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-4&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;:&lt;/span&gt;
&lt;span id=&quot;cb2-5&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-6&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;getGHCWithVersion&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;lib&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;ghc&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; lib&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;replaceStrings &lt;span class=&quot;op&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;.&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;]&lt;/span&gt; ghcVersion&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-7&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;sources&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;./sources.nix&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-8&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-9&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;bu&quot;&gt;import&lt;/span&gt; sources&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;nixpkgs &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-10&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;system&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; arch &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;-linux&quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-11&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;overlays&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-12&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;final&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;prev&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-13&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-14&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;va&quot;&gt;compiler&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; getGHCWithVersion prev&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;lib&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-15&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;va&quot;&gt;prevHPackages&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; prev&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;haskell&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;packages&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;${&lt;/span&gt;compiler&lt;span class=&quot;sc&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-16&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;kw&quot;&gt;in&lt;/span&gt; prev&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;lib&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;attrsets&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;recursiveUpdate prev &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-17&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;va&quot;&gt;haskell&lt;/span&gt;.&lt;span class=&quot;va&quot;&gt;packages&lt;/span&gt;.&lt;span class=&quot;sc&quot;&gt;${&lt;/span&gt;compiler&lt;span class=&quot;sc&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; prevHPackages&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;override &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-18&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;va&quot;&gt;ghc&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; prevHPackages&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;ghc&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;override &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-19&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;va&quot;&gt;enableRelocatedStaticLibs&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;cn&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-20&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;va&quot;&gt;enableShared&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;cn&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-21&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;va&quot;&gt;enableDwarf&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;cn&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-22&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;va&quot;&gt;enableProfiledLibs&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;cn&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-23&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;va&quot;&gt;enableDocs&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;cn&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-24&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;va&quot;&gt;enableNativeBignum&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;cn&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-25&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-26&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-26&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;va&quot;&gt;buildHaskellPackages&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; prevHPackages&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;buildHaskellPackages&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;override &lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;old&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-27&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-27&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;va&quot;&gt;ghc&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; final&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;haskell&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;packages&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;${&lt;/span&gt;compiler&lt;span class=&quot;sc&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;ghc&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-28&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-28&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;va&quot;&gt;buildHaskellPackages&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; final&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;haskell&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;packages&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;${&lt;/span&gt;compiler&lt;span class=&quot;sc&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-29&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-29&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;op&quot;&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-30&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-30&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-31&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-31&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb2-32&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-32&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-33&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-33&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ( &lt;span class=&quot;va&quot;&gt;final&lt;/span&gt;: &lt;span class=&quot;va&quot;&gt;prev&lt;/span&gt;:&lt;/span&gt;
&lt;span id=&quot;cb2-34&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-34&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;compiler&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; getGHCWithVersion prev&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;lib&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-35&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-35&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;in&lt;/span&gt; {&lt;/span&gt;
&lt;span id=&quot;cb2-36&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-36&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;va&quot;&gt;haskellPackages&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; prev&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;haskell&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;packages&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;${&lt;/span&gt;compiler&lt;span class=&quot;sc&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-37&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-37&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;va&quot;&gt;ghc&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; prev&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;haskell&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;packages&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;${&lt;/span&gt;compiler&lt;span class=&quot;sc&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;ghc&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-38&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-38&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-39&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-39&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-40&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-40&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;final&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;prev&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-41&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-41&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;haskell&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; prev&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;haskell &lt;span class=&quot;op&quot;&gt;//&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-42&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-42&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;va&quot;&gt;packageOverrides&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; prev&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;lib&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;composeExtensions prev&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;haskell&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;packageOverrides &lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-43&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-43&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;va&quot;&gt;hfinal&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;hprev&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-44&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-44&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;va&quot;&gt;mkDerivation&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-45&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-45&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;              hprev&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;mkDerivation &lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-46&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-46&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                args &lt;span class=&quot;op&quot;&gt;//&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-47&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-47&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                  &lt;span class=&quot;va&quot;&gt;doCheck&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;cn&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-48&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-48&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                  &lt;span class=&quot;va&quot;&gt;doHaddock&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;cn&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-49&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-49&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                  &lt;span class=&quot;va&quot;&gt;enableLibraryProfiling&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;cn&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-50&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-50&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                  &lt;span class=&quot;va&quot;&gt;enableExecutableProfiling&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;cn&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-51&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-51&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                &lt;span class=&quot;op&quot;&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-52&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-52&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;op&quot;&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-53&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-53&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-54&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-54&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-55&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-55&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-56&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-56&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-57&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb2-57&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;figcaption&gt;
nix/nixpkgs-static-ghc.nix
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Letâ€™s go over it piece-by-piece. First, we take the &lt;code&gt;arch&lt;/code&gt; and &lt;code&gt;ghcVersion&lt;/code&gt; parameters, letting us build the package for different architectures (&lt;a href=&quot;https://en.wikipedia.org/wiki/X86-64&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;X86-64&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/AArch64&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;AArch64&lt;/a&gt;), and for different GHC versions. We default the &lt;code&gt;ghcVersion&lt;/code&gt; to the default GHC in nixpkgs.&lt;/p&gt;
&lt;p&gt;The derivation is same as &lt;a href=&quot;https://abhinavsarkar.net/posts/nix-for-haskell/?mtm_campaign=feed#nixpkgs_nix&quot;&gt;&lt;code&gt;nixpkgs.nix&lt;/code&gt;&lt;/a&gt;, except we add some overlays. The first overlay adds the custom configured GHC for static builds. We enable certain configurations for that purpose:&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;&lt;code&gt;enableRelocatedStaticLibs = true&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;
Configures GHC runtime system and core packages to be built with position independent code so that they can be loaded for template Haskell.
&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;enableShared = false&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;
Disables building dynamically-linkable libraries, so they are built only as static archives.
&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;enableDwarf = false&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;
Disables &lt;a href=&quot;https://en.wikipedia.org/wiki/DWARF&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;DWARF&lt;/a&gt;-based stack traces, because it is unavailable on musl targets.
&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;enableProfiledLibs = false&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;
Disables building profiling enabled libraries.
&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;enableDocs = false&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;
Disables generation of documentation.
&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;enableNativeBignum = true&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;
Makes GHC use pure-Haskell based native bignum backend &lt;a href=&quot;https://hackage.haskell.org/package/ghc-bignum&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;&lt;code&gt;ghc-bignum&lt;/code&gt;&lt;/a&gt; instead of &lt;a href=&quot;https://gmplib.org/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;GMP&lt;/a&gt;, so that the package executables it creates are GPL-free. You may remove this setting if you are okay with GPL executables.
&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;The &lt;code&gt;buildHaskellPackages&lt;/code&gt; related lines set the custom GHC as the compiler for Haskell-based tools used in Nix&lt;a class=&quot;footnote-ref&quot; href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#fn2&quot; id=&quot;fnref2&quot;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The second overlay makes &lt;a href=&quot;https://github.com/NixOS/cabal2nix/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;&lt;code&gt;cabal2nix&lt;/code&gt;&lt;/a&gt;â€”the tool used to convert &lt;code&gt;.cabal&lt;/code&gt; files into Nix derivationsâ€”use the custom GHC. The third overlay disables documentation generation, testing, and profiling of all Haskell libraries built with the custom GHC. We do this to save the build time, assuming that static builds are for release only, and the docs, tests, and profiling are done using a normal GHC.&lt;/p&gt;
&lt;p&gt;Building this custom GHC may take anywhere from several minutes to several hours depending on the build machine configuration&lt;a class=&quot;footnote-ref&quot; href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#fn3&quot; id=&quot;fnref3&quot;&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt;&lt;a class=&quot;footnote-ref&quot; href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#fn4&quot; id=&quot;fnref4&quot;&gt;&lt;sup&gt;4&lt;/sup&gt;&lt;/a&gt;. But this is a one-time price to pay, as long as we keep the GHC build around. Next, we configure our package to be built as a statically-linked executable.&lt;/p&gt;
&lt;h2 id=&quot;configuring-the-application&quot;&gt;Configuring the Application&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#configuring-the-application&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;package-static.nix&lt;/code&gt; file is equivalent of the &lt;a href=&quot;https://abhinavsarkar.net/posts/nix-for-haskell/?mtm_campaign=feed#package_nix&quot;&gt;&lt;code&gt;package.nix&lt;/code&gt;&lt;/a&gt; file from the previous post, but builds statically-linked exes.&lt;/p&gt;
&lt;figure&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb3&quot;&gt;&lt;pre class=&quot;sourceCode nix noNumberSource&quot;&gt;&lt;code class=&quot;sourceCode nix&quot;&gt;&lt;span id=&quot;cb3-1&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-2&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;arch&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-3&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;ghcVersion&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bu&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;./nix/nixpkgs.nix&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;}).&lt;/span&gt;haskellPackages&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;ghc&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;version&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-4&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;:&lt;/span&gt;
&lt;span id=&quot;cb3-5&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-6&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;pkgsOrig&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;./nix/nixpkgs-static-ghc.nix&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;inherit&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;arch&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;ghcVersion&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-7&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;pkgs&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; pkgsOrig&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;pkgsMusl&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-8&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;hlib&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;haskell&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;lib&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;compose&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-9&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-10&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;staticDeps&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;./nix/static-deps.nix&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;inherit&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;pkgs&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-11&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;inherit&lt;/span&gt; (&lt;span class=&quot;va&quot;&gt;staticDeps&lt;/span&gt;) &lt;span class=&quot;va&quot;&gt;libffi&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;zlib&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;numactl&lt;/span&gt;;&lt;/span&gt;
&lt;span id=&quot;cb3-12&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-13&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;lib&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;pipe&lt;/span&gt;
&lt;span id=&quot;cb3-14&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;haskellPackages&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;callCabal2nix &lt;span class=&quot;st&quot;&gt;&quot;ftr&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;lib&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;cleanSource &lt;span class=&quot;ss&quot;&gt;./.&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-15&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;[&lt;/span&gt; hlib&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;dontHaddock&lt;/span&gt;
&lt;span id=&quot;cb3-16&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    hlib&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;dontHyperlinkSource&lt;/span&gt;
&lt;span id=&quot;cb3-17&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    hlib&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;dontCoverage&lt;/span&gt;
&lt;span id=&quot;cb3-18&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    hlib&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;disableExecutableProfiling&lt;/span&gt;
&lt;span id=&quot;cb3-19&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    hlib&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;disableLibraryProfiling&lt;/span&gt;
&lt;span id=&quot;cb3-20&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    hlib&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;disableSharedLibraries&lt;/span&gt;
&lt;span id=&quot;cb3-21&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    hlib&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;justStaticExecutables&lt;/span&gt;
&lt;span id=&quot;cb3-22&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    hlib&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;enableDeadCodeElimination&lt;/span&gt;
&lt;span id=&quot;cb3-23&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;(&lt;/span&gt; hlib&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;overrideCabal &lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;old&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-24&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;enableParallelBuilding&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;cn&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-25&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;buildTools&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;old&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;buildTools &lt;span class=&quot;kw&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;[&lt;/span&gt; pkgsOrig&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;buildPackages&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;lld &lt;span class=&quot;op&quot;&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-26&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-26&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;}))&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-27&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-27&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;(&lt;/span&gt; hlib&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;appendConfigureFlags &lt;span class=&quot;op&quot;&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-28&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-28&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;st&quot;&gt;&quot;-O2&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-29&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-29&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;st&quot;&gt;&quot;--ghc-option=-fPIC&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-30&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-30&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;st&quot;&gt;&quot;--ghc-option=-optl=-static&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-31&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-31&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;st&quot;&gt;&quot;--ghc-option=-split-sections&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-32&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-32&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;st&quot;&gt;&quot;--ghc-option=-optl-fuse-ld=lld&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-33&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-33&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;st&quot;&gt;&quot;--ld-option=-fuse-ld=lld&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-34&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-34&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;st&quot;&gt;&quot;--with-ld=ld.lld&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-35&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-35&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;st&quot;&gt;&quot;--ld-option=-Wl,--gc-sections,--build-id,--icf=all&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-36&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-36&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;st&quot;&gt;&quot;--extra-lib-dirs=&lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;${&lt;/span&gt;libffi&lt;span class=&quot;sc&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;/lib&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-37&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-37&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;st&quot;&gt;&quot;--extra-lib-dirs=&lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;${&lt;/span&gt;zlib&lt;span class=&quot;sc&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;/lib&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-38&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-38&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;st&quot;&gt;&quot;--extra-lib-dirs=&lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;${&lt;/span&gt;numactl&lt;span class=&quot;sc&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;/lib&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-39&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-39&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-40&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-40&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;stdenv&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;mkDerivation &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-41&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-41&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;${&lt;/span&gt;src&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;sc&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;-compressed&quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-42&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-42&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;kw&quot;&gt;inherit&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-43&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-43&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;nativeBuildInputs&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;[&lt;/span&gt; pkgsOrig&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;upx &lt;span class=&quot;op&quot;&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-44&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-44&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;installPhase&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;''&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-45&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-45&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;        mkdir -p $out&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-46&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-46&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;        cp -R $src/. $out&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-47&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-47&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;        chmod -R +w $out/bin&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-48&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-48&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;        upx -q --lzma -1 $out/bin/*&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-49&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-49&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;        chmod -R -w $out/bin&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-50&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-50&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;      ''&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-51&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-51&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-52&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-52&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;figcaption&gt;
package-static.nix
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Letâ€™s go over the file in parts.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;package-static.nix&lt;/code&gt; also takes &lt;code&gt;arch&lt;/code&gt; and &lt;code&gt;ghcVersion&lt;/code&gt; as parameters, and passes them to &lt;code&gt;nix/nixpkgs-static-ghc.nix&lt;/code&gt; to create the nixpkgs with the custom GHC as described above. This give us &lt;code&gt;pkgsOrig&lt;/code&gt;, from which we get the &lt;code&gt;pkgsMusl&lt;/code&gt; version. &lt;code&gt;pkgsMusl&lt;/code&gt; is same nixpkgs, except every executable in it links to musl libc. We capture this as &lt;code&gt;pkgs&lt;/code&gt;, and use it to build our Haskell package.&lt;/p&gt;
&lt;p&gt;When linking the executable, we need to link it against static version of all the dependency libraries it depends on. Thatâ€™s what &lt;code&gt;nix/static-deps.nix&lt;/code&gt; file provides us. Weâ€™ll look at it in the next section, but for now, we see that it gives us the &lt;code&gt;libffi&lt;/code&gt;, &lt;code&gt;zlib&lt;/code&gt;, and &lt;code&gt;numactl&lt;/code&gt; libraries&lt;a class=&quot;footnote-ref&quot; href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#fn5&quot; id=&quot;fnref5&quot;&gt;&lt;sup&gt;5&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Finally, we get to the package configuration. It starts the same as &lt;a href=&quot;https://abhinavsarkar.net/posts/nix-for-haskell/?mtm_campaign=feed#package_nix&quot;&gt;&lt;code&gt;package.nix&lt;/code&gt;&lt;/a&gt;, using &lt;code&gt;cabal2nix&lt;/code&gt; to connect the Haskell project to Nix, but then, we provide a list of custom configurations. We disable &lt;a href=&quot;http://www.haskell.org/haddock/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Haddock&lt;/a&gt; docs, hyperlinked source docs, coverage tests, profiling, and shared library build. We enable static executable build and dead code elimination. Then we configure cabal to run builds with multithreading, and add &lt;a href=&quot;https://web.archive.org/web/20260618/https://lld.llvm.org/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;&lt;code&gt;lld&lt;/code&gt;&lt;/a&gt; to its list of build tools.&lt;/p&gt;
&lt;p&gt;Then, we add many configuration flags:&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;&lt;code&gt;-O2&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;
Enables optimization.
&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;--ghc-option=-fPIC&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;
Enables emission of position independent code.
&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;--ghc-option=-optl=-static&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;
Enables static linking.
&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;--ghc-option=-split-sections&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;
Enables &lt;a href=&quot;https://downloads.haskell.org/ghc/latest/docs/users_guide/phases.html#ghc-flag-fsplit-sections&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;split sections&lt;/a&gt; to produce smaller binaries.
&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;--ghc-option=-optl-fuse-ld=lld&lt;/code&gt;, &lt;code&gt;--ld-option=-fuse-ld=lld&lt;/code&gt;, &lt;code&gt;--with-ld=ld.lld&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;
Configures GHC to use &lt;a href=&quot;https://web.archive.org/web/20260618/https://lld.llvm.org/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;&lt;code&gt;lld&lt;/code&gt;&lt;/a&gt; as the linker, which is much faster than the default linker. You can omit these lines to use the default linker. Or you can replace all metions of &lt;code&gt;lld&lt;/code&gt; with &lt;code&gt;mold&lt;/code&gt; to use the &lt;a href=&quot;https://github.com/rui314/mold&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Mold&lt;/a&gt; linker, which may be even faster depending on your project.
&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;--ld-option=-Wl,--gc-sections,--build-id,--icf=all&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;
Enables reductions in binary size by removing dead code&lt;a class=&quot;footnote-ref&quot; href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#fn6&quot; id=&quot;fnref6&quot;&gt;&lt;sup&gt;6&lt;/sup&gt;&lt;/a&gt;.
&lt;/dd&gt;
&lt;/dl&gt;
&lt;dl&gt;
&lt;dt&gt;&lt;code&gt;--extra-lib-dirs=...&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;
These lines allow GHC to link the output executable against the static version of the mentioned dependency libraries.
&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;Finally, the last function in the pipeline uses &lt;a href=&quot;https://upx.github.io/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;UPX&lt;/a&gt; to compress the output executable. This generally results in a large reduction in the binary size&lt;a class=&quot;footnote-ref&quot; href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#fn7&quot; id=&quot;fnref7&quot;&gt;&lt;sup&gt;7&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now we can actually build the statically-linked exe:&lt;/p&gt;
&lt;pre class=&quot;plain&quot;&gt;&lt;code&gt;$ nix-build --argstr arch x86_64 package-static.nix
$ nix-build --argstr arch aarch64 package-static.nix
$ nix-build --argstr arch x86_64 --argstr ghcVersion &quot;9.12&quot; package-static.nix&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first and second line above build the exe for the X86-64 and AArch64 architectures with the default GHC version. The third line specifies a different GHC version to build with. Here is the cleaned-up output log for the first command:&lt;/p&gt;
&lt;details&gt;

Output log

&lt;pre class=&quot;plain&quot;&gt;&lt;code&gt;$ nix-build --argstr arch x86_64 package-static.nix
these 2 derivations will be built:
  /nix/store/42a291bq7ydvkdy3fdsyj82axrfsi6sy-ftr-0.1.0.0.drv
  /nix/store/2c2l50la8291q0jrqlc23bybaxwip8y2-ftr-0.1.0.0-compressed.drv
building '/nix/store/42a291bq7ydvkdy3fdsyj82axrfsi6sy-ftr-0.1.0.0.drv' on 'ssh-ng://builder@linux-builder'...
copying 1 paths...
copying path '/nix/store/l9ls307kzxby72hqj4yl7ri7m8s3b3fk-source' to 'ssh-ng://builder@linux-builder'...
building '/nix/store/42a291bq7ydvkdy3fdsyj82axrfsi6sy-ftr-0.1.0.0.drv'...
Running phase: setupCompilerEnvironmentPhase
Build with /nix/store/717lxds14ra0ndbnin2qhdhh91d3b69g-ghc-musl-native-bignum-9.10.3.
Running phase: unpackPhase
unpacking source archive /nix/store/l9ls307kzxby72hqj4yl7ri7m8s3b3fk-source
source root is source
Running phase: patchPhase
Running phase: compileBuildDriverPhase
setupCompileFlags: -package-db=/nix/var/nix/b/10kwxdphxvyy519y831ryji7fn/b/tmp.EPOEKNjT6Z/setup-package.conf.d -threaded
[1 of 2] Compiling Main             ( /nix/store/4mdp8nhyfddh7bllbi7xszz7k9955n79-Setup.hs, /nix/var/nix/b/10kwxdphxvyy519y831ryji7fn/b/tmp.EPOEKNjT6Z/Main.o )
[2 of 2] Linking Setup
Running phase: updateAutotoolsGnuConfigScriptsPhase
Running phase: configurePhase
configureFlags: --verbose --prefix=/nix/store/pb2zay1k8b0vifhx7ghd5j6lbncq4b66-ftr-0.1.0.0 --libdir=$prefix/lib/$compiler/lib --libsubdir=$abi/$libname --with-gcc=gcc --package-db=/nix/var/nix/b/10kwxdphxvyy519y831ryji7fn/b/tmp.EPOEKNjT6Z/package.conf.d --ghc-option=-j4 --ghc-option=+RTS --ghc-option=-A64M --ghc-option=-RTS --disable-library-profiling --disable-profiling --disable-shared --disable-coverage --enable-static --disable-executable-dynamic --disable-tests --disable-benchmarks --enable-library-vanilla --disable-library-for-ghci --enable-split-sections --enable-library-stripping --enable-executable-stripping -O2 --ghc-option=-fPIC --ghc-option=-split-sections --ghc-option=-optl-fuse-ld=lld --ld-option=-fuse-ld=lld --ld-option=-Wl,--gc-sections,--build-id,--icf=all --with-ld=ld.lld --ghc-option=-optl=-static --extra-lib-dirs=/nix/store/yi771fg1dfj1bg618vv5flmisy8zw3hm-libffi-3.5.2/lib --extra-lib-dirs=/nix/store/jk77s356gjn68dcrzpz1m7m5amzxmkw8-zlib-1.3.2-static/lib --extra-lib-dirs=/nix/store/044b10glmg0f3yyijmrwrgv5lsys6x6n-numactl-2.0.18/lib --extra-lib-dirs=/nix/store/m1j2f9b1h6pbq1mq5ibnw4cpp60w5dfi-libffi-3.5.2/lib --extra-include-dirs=/nix/store/j9c1ifaa7vph3zxfbzb55y1frm0vp4xm-musl-iconv-1.2.5/include --extra-lib-dirs=/nix/store/lrrmafbkrpa4f3wxfz6a3sd3dv6xgp7n-numactl-2.0.18/lib

[snip]

Running phase: buildPhase
Preprocessing executable 'ftr' for ftr-0.1.0.0...
Building executable 'ftr' for ftr-0.1.0.0...
[1 of 1] Compiling Main             ( app/Main.hs, dist/build/ftr/ftr-tmp/Main.o )
[2 of 2] Linking dist/build/ftr/ftr
Running phase: haddockPhase
Running phase: installPhase
Installing executable ftr in /nix/store/pb2zay1k8b0vifhx7ghd5j6lbncq4b66-ftr-0.1.0.0/bin
Warning: The directory
/nix/store/pb2zay1k8b0vifhx7ghd5j6lbncq4b66-ftr-0.1.0.0/bin is not in the
system search path.
Running phase: fixupPhase
shrinking RPATHs of ELF executables and libraries in /nix/store/pb2zay1k8b0vifhx7ghd5j6lbncq4b66-ftr-0.1.0.0
shrinking /nix/store/pb2zay1k8b0vifhx7ghd5j6lbncq4b66-ftr-0.1.0.0/bin/ftr
patchelf: cannot find section '.dynamic'. The input file is most likely statically linked
checking for references to /nix/var/nix/b/10kwxdphxvyy519y831ryji7fn/b/ in /nix/store/pb2zay1k8b0vifhx7ghd5j6lbncq4b66-ftr-0.1.0.0...
patchelf: cannot find section '.dynamic'. The input file is most likely statically linked
patching script interpreter paths in /nix/store/pb2zay1k8b0vifhx7ghd5j6lbncq4b66-ftr-0.1.0.0
stripping (with command strip and flags -S -p) in  /nix/store/pb2zay1k8b0vifhx7ghd5j6lbncq4b66-ftr-0.1.0.0/bin
copying 1 paths...
copying path '/nix/store/pb2zay1k8b0vifhx7ghd5j6lbncq4b66-ftr-0.1.0.0' from 'ssh-ng://builder@linux-builder'...
building '/nix/store/2c2l50la8291q0jrqlc23bybaxwip8y2-ftr-0.1.0.0-compressed.drv' on 'ssh-ng://builder@linux-builder'...
copying 0 paths...
building '/nix/store/2c2l50la8291q0jrqlc23bybaxwip8y2-ftr-0.1.0.0-compressed.drv'...
Running phase: unpackPhase
unpacking source archive /nix/store/pb2zay1k8b0vifhx7ghd5j6lbncq4b66-ftr-0.1.0.0
source root is ftr-0.1.0.0
Running phase: patchPhase
Running phase: updateAutotoolsGnuConfigScriptsPhase
Running phase: configurePhase
no configure script, doing nothing
Running phase: buildPhase
no Makefile or custom buildPhase, doing nothing
Running phase: installPhase
                       Ultimate Packer for eXecutables
                          Copyright (C) 1996 - 2026
UPX 5.1.1       Markus Oberhumer, Laszlo Molnar &amp;amp; John Reiser    Mar 5th 2026

        File size         Ratio      Format      Name
   --------------------   ------   -----------   -----------
   1356096 -&amp;gt;    525804   38.77%   linux/amd64   ftr                           bin/ftr [linux/amd64, LZMA/1]

Packed 1 file.
Running phase: fixupPhase
shrinking RPATHs of ELF executables and libraries in /nix/store/j8gg1x3vrlb5dc1mh149ys0nih9fvmwk-ftr-0.1.0.0-compressed
shrinking /nix/store/j8gg1x3vrlb5dc1mh149ys0nih9fvmwk-ftr-0.1.0.0-compressed/bin/ftr
patchelf: no section headers. The input file is probably a statically linked, self-decompressing binary
checking for references to /nix/var/nix/b/19b7g2frvcvani3cnj61lsb4fq/b/ in /nix/store/j8gg1x3vrlb5dc1mh149ys0nih9fvmwk-ftr-0.1.0.0-compressed...
patchelf: no section headers. The input file is probably a statically linked, self-decompressing binary
patching script interpreter paths in /nix/store/j8gg1x3vrlb5dc1mh149ys0nih9fvmwk-ftr-0.1.0.0-compressed
stripping (with command strip and flags -S -p) in  /nix/store/j8gg1x3vrlb5dc1mh149ys0nih9fvmwk-ftr-0.1.0.0-compressed/bin
copying 1 paths...
copying path '/nix/store/j8gg1x3vrlb5dc1mh149ys0nih9fvmwk-ftr-0.1.0.0-compressed' from 'ssh-ng://builder@linux-builder'...
/nix/store/j8gg1x3vrlb5dc1mh149ys0nih9fvmwk-ftr-0.1.0.0-compressed&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;The output log mentions:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;patchelf: cannot find section â€˜.dynamicâ€™. The input file is most likely statically linked&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;We can also verify for ourselves:&lt;/p&gt;
&lt;pre class=&quot;plain&quot;&gt;&lt;code&gt;$ file /nix/store/j8gg1x3vrlb5dc1mh149ys0nih9fvmwk-ftr-0.1.0.0-compressed/bin/ftr
/nix/store/j8gg1x3vrlb5dc1mh149ys0nih9fvmwk-ftr-0.1.0.0-compressed/bin/ftr: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), BuildID[sha1]=df53df80d301b4bba2a7634a4169c6291d64ea72, statically linked, no section header&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is one last thing to take care of.&lt;/p&gt;
&lt;h2 id=&quot;rooting-static-build-dependencies&quot;&gt;Rooting Static Build Dependencies&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#rooting-static-build-dependencies&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Dynamically-linked Haskell builds contain references to their dependency libraries and GHC that was used to build it. If you use &lt;a href=&quot;https://direnv.net/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;&lt;code&gt;direnv&lt;/code&gt;&lt;/a&gt; or install a dynamically-linked executable, it creates Nix GC roots for the libraries and GHC, preventing them from being garbage-collected by Nix. But statically-linked builds have no references to anything, as intended. So we need to create GC roots by ourselves to the libraries and the GHC toolchain. This is even more important because building the custom GHC may be an extremely time-consuming affair.&lt;/p&gt;
&lt;p&gt;First, we list all dependencies in a separate file:&lt;/p&gt;
&lt;figure&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb7&quot;&gt;&lt;pre class=&quot;sourceCode nix noNumberSource&quot;&gt;&lt;code class=&quot;sourceCode nix&quot;&gt;&lt;span id=&quot;cb7-1&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb7-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;pkgs&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;:&lt;/span&gt;
&lt;span id=&quot;cb7-2&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb7-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-3&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb7-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;ghc&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;haskellPackages&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;ghc&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-4&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb7-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;jailbreak-cabal&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;haskellPackages&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;buildHaskellPackages&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;jailbreak&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;cabal&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-5&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb7-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;cabal2nix-unwrapped&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;cabal2nix&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;unwrapped&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-6&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb7-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;gmp6&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;gmp6&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;override &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;withStatic&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;cn&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-7&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb7-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;libffi&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;libffi&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;overrideAttrs &lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;old&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;dontDisableStatic&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;cn&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-8&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb7-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;ncurses&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;ncurses&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;override &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;enableStatic&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;cn&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-9&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb7-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;zlib&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;zlib&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;static&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-10&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb7-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;numactl&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;numactl&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;overrideAttrs &lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;oldAttrs&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-11&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb7-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;va&quot;&gt;configureFlags&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;oldAttrs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;configureFlags &lt;span class=&quot;kw&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-12&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb7-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;st&quot;&gt;&quot;--enable-static&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-13&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb7-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;st&quot;&gt;&quot;--disable-shared&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-14&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb7-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-15&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb7-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-16&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb7-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;figcaption&gt;
nix/static-deps.nix
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This file lists the dependency libraries and the GHC toolchain. Notice how we override each libraryâ€™s config to make it statically-linkable. Iâ€™ve included some additional libraries here (&lt;code&gt;gmp6&lt;/code&gt; and &lt;code&gt;ncurses&lt;/code&gt;) that are generally used by Haskell projects, but we donâ€™t use them in this project. You may have to add more of such libraries depending on your projectâ€™s dependencies.&lt;/p&gt;
&lt;p&gt;We already saw how we use this file in &lt;code&gt;package-static.nix&lt;/code&gt;. Now, we use it to create Nix GC roots:&lt;/p&gt;
&lt;figure&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb8&quot;&gt;&lt;pre class=&quot;sourceCode nix noNumberSource&quot;&gt;&lt;code class=&quot;sourceCode nix&quot;&gt;&lt;span id=&quot;cb8-1&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-2&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;arch&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-3&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;ghcVersion&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bu&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;./nix/nixpkgs.nix&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;}).&lt;/span&gt;haskellPackages&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;ghc&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;version&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-4&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;:&lt;/span&gt;
&lt;span id=&quot;cb8-5&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-6&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;pkgsOrig&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;./nix/nixpkgs-static-ghc.nix&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;inherit&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;arch&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;ghcVersion&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-7&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;pkgs&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; pkgsOrig&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;pkgsMusl&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-8&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;in&lt;/span&gt; pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;symlinkJoin &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-9&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;static-deps&quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-10&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;paths&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;builtins&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;attrValues &lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bu&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;./nix/static-deps.nix&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;inherit&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;pkgs&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-11&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;figcaption&gt;
package-static-deps.nix
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;code&gt;package-static-deps.nix&lt;/code&gt; simply gathers all dependencies from &lt;code&gt;nix/static-deps.nix&lt;/code&gt; and creates a directory with symlinks to them. This brings us to the finale.&lt;/p&gt;
&lt;h2 id=&quot;finale&quot;&gt;Finale&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#finale&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We create a bash script &lt;code&gt;build-static.sh&lt;/code&gt; that builds the statically-linked executable, and creates Nix GC roots for all dependencies and the toolchain:&lt;/p&gt;
&lt;figure&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb9&quot;&gt;&lt;pre class=&quot;sourceCode bash noNumberSource&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb9-1&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb9-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;#!/usr/bin/env bash&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-2&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb9-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;bu&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;-euo&lt;/span&gt; pipefail&lt;/span&gt;
&lt;span id=&quot;cb9-3&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb9-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-4&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb9-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;nix-build&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;--argstr&lt;/span&gt; arch &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt; package-static.nix&lt;/span&gt;
&lt;span id=&quot;cb9-5&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb9-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;nix-store&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;--add-root&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;.gcroots/static-deps-&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-6&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb9-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;at&quot;&gt;--realise&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;ex&quot;&gt;nix-instantiate&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;--argstr&lt;/span&gt; arch &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;--quiet&lt;/span&gt; package-static-deps.nix&lt;span class=&quot;va&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-7&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb9-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; /dev/null&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;figcaption&gt;
build-static.sh
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The root is created at &lt;code&gt;.gcroots/static-deps-x86_64&lt;/code&gt; for X86-64 architecture, for example. You can use &lt;a href=&quot;https://github.com/utdemir/nix-tree&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;&lt;code&gt;nix-tree&lt;/code&gt;&lt;/a&gt; to explore it.&lt;/p&gt;
&lt;p&gt;This concludes our short tutorial on how to build statically-linked executables for Haskell projects with Nix.&lt;/p&gt;
&lt;h2 id=&quot;bonus-building-a-docker-image&quot;&gt;Bonus: Building a Docker Image&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#bonus-building-a-docker-image&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One more thing static builds are great for: wrapping them into &lt;a href=&quot;https://www.docker.com/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Docker&lt;/a&gt; images. Since they are much smaller than dynamically-linked executables and their dependencies combined, they are better to package as Docker images. Hereâ€™s how we do it:&lt;/p&gt;
&lt;figure&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb10&quot;&gt;&lt;pre class=&quot;sourceCode nix noNumberSource&quot;&gt;&lt;code class=&quot;sourceCode nix&quot;&gt;&lt;span id=&quot;cb10-1&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;arch&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;:&lt;/span&gt;
&lt;span id=&quot;cb10-2&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-3&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;pkgs&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;./nix/nixpkgs.nix&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;system&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; arch &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;-linux&quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-4&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;ftr&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;./package-static.nix&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;inherit&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;arch&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-5&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-6&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;dockerTools&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;buildLayeredImage &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-7&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;ftr&quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-8&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;tag&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;latest&quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-9&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;contents&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;[&lt;/span&gt; pkgs&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;dockerTools&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;caCertificates ftr &lt;span class=&quot;op&quot;&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-10&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-11&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;extraCommands&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;''&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-12&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;    mkdir -p var/lib/ftr var/cache/ftr etc/ftr&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-13&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;    echo 'ftr:x:1000:1000::/var/lib/ftr:/sbin/nologin' &amp;gt; etc/passwd&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-14&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;    echo 'ftr:x:1000:' &amp;gt; etc/group&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-15&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;  ''&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-16&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;fakeRootCommands&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;''&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-17&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;    chown -R 1000:1000 var/lib/ftr var/cache/ftr&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-18&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;st&quot;&gt;  ''&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-19&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;enableFakechroot&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;cn&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-20&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-21&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-22&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;va&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;1000:1000&quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-23&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;va&quot;&gt;Cmd&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;/bin/ftr&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-24&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;va&quot;&gt;Volumes&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-25&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;st&quot;&gt;&quot;/var/lib/ftr&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-26&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-26&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;st&quot;&gt;&quot;/var/cache/ftr&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-27&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-27&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;st&quot;&gt;&quot;/etc/ftr&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-28&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-28&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-29&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-29&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-30&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-30&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;figcaption&gt;
docker.nix
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This image also shows how to package extra Nix packages in images, setting up a non-root user to run the executable, and setting up user-owned directories to expose as volumes. We can build the image by running:&lt;/p&gt;
&lt;pre class=&quot;plain&quot;&gt;&lt;code&gt;$ nix-build --argstr arch x86_64 docker.nix
[snip]
/nix/store/cdghjrgdcf7vm0jbgjl5556zx3j4zjj1-ftr.tar.gz&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we can load and run the image on Docker like so:&lt;/p&gt;
&lt;pre class=&quot;plain&quot;&gt;&lt;code&gt;$ docker load -i /nix/store/cdghjrgdcf7vm0jbgjl5556zx3j4zjj1-ftr.tar.gz&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This post shows how to configure GHC and Haskell projects to build statically-linked executables that are fully portable and independent. If your Haskell project has any complex requirements, such as custom dependency versions, patched dependencies, custom non-Haskell dependencies etc., this setup may not scale. In such case you can either grow this setup by learning Nix in more depth with the help of the official &lt;a href=&quot;https://wiki.nixos.org/w/index.php?title=Haskell&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot; title=&quot;How to develop with Haskell and Nix&quot;&gt;Haskell with Nix docs&lt;/a&gt; and this &lt;a href=&quot;https://github.com/Gabriella439/haskell-nix&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot; title=&quot;haskell-nix&quot;&gt;great tutorial&lt;/a&gt;, or switch to using a framework like &lt;a href=&quot;https://input-output-hk.github.io/haskell.nix/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;haskell.nix&lt;/a&gt; or &lt;a href=&quot;https://github.com/srid/haskell-flake&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;haskell-flake&lt;/a&gt;. For dealing with complex static builds, &lt;a href=&quot;https://github.com/nh2/static-haskell-nix/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;static-haskell-nix&lt;/a&gt; project may be of help.&lt;/p&gt;
&lt;p class=&quot;like-msg&quot;&gt;
If you have any questions or comments, please leave a comment below. If you liked this post, please share it. Thanks for reading!
&lt;/p&gt;
&lt;section class=&quot;footnotes footnotes-end-of-document&quot; id=&quot;footnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;&lt;p&gt;I have tested this setup for GHC 9.10+ and X86-64 and AArch64 architectures only.&lt;a class=&quot;footnote-back&quot; href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#fnref1&quot;&gt;â†©ï¸�&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn2&quot;&gt;&lt;p&gt;Without this config, Nix will build a separate GHC for building Haskell-based tools used in Nix.&lt;a class=&quot;footnote-back&quot; href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#fnref2&quot;&gt;â†©ï¸�&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn3&quot;&gt;&lt;p&gt;You may need a remote Nix Linux builder to build GHC and your package if you are not on Linux or not on the right architecture. You may set up a &lt;a href=&quot;https://nix.dev/manual/nix/latest/advanced-topics/distributed-builds.html&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;remote builder&lt;/a&gt; or &lt;a href=&quot;https://nixos.org/manual/nixpkgs/stable/#sec-darwin-builder&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Linux builder on macOS&lt;/a&gt;.&lt;a class=&quot;footnote-back&quot; href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#fnref3&quot;&gt;â†©ï¸�&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn4&quot;&gt;&lt;p&gt;Building GHC is memory intensive. You may require few GBs of RAM.&lt;a class=&quot;footnote-back&quot; href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#fnref4&quot;&gt;â†©ï¸�&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn5&quot;&gt;&lt;p&gt;Some of your projectâ€™s dependency libraries may link to &lt;a href=&quot;https://gmplib.org/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;GMP&lt;/a&gt; directly. In such cases, the libraries provide Cabal flags to remove GMP dependency. If you donâ€™t want GMP linked to your executable, youâ€™ll need to override the Nix derivation for such libraries to pass those Cabal flags.&lt;a class=&quot;footnote-back&quot; href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#fnref5&quot;&gt;â†©ï¸�&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn6&quot;&gt;&lt;p&gt;I learned about using these flags from the post &lt;a href=&quot;https://brandon.si/code/linking-smaller-haskell-binaries/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;â€œLinking Smaller Haskell Binariesâ€�&lt;/a&gt;. It mentions few mores tricks that may be useful to you.&lt;a class=&quot;footnote-back&quot; href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#fnref6&quot;&gt;â†©ï¸�&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn7&quot;&gt;&lt;p&gt;Note that we get the tools &lt;code&gt;lld&lt;/code&gt; and &lt;code&gt;upx&lt;/code&gt; from &lt;code&gt;pkgsOrig&lt;/code&gt;, the original nixpkgs, not the musl one. We donâ€™t need musl version of these tools for them to work, and doing that would simply cause our builds to take longer.&lt;a class=&quot;footnote-back&quot; href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#fnref7&quot;&gt;â†©ï¸�&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;&lt;section class=&quot;series-info&quot;&gt;
  &lt;p&gt;This post is a part of the series: &lt;strong&gt;Nix for Haskell&lt;/strong&gt;.&lt;/p&gt;
  &lt;ol&gt;
    &lt;li&gt;
      
       &lt;a href=&quot;https://abhinavsarkar.net/posts/nix-for-haskell/?mtm_campaign=feed&quot;&gt;Getting Started&lt;/a&gt; 
    &lt;/li&gt;
    &lt;li&gt;
       &lt;strong&gt;Static Builds&lt;/strong&gt; ğŸ‘ˆ
      
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/section&gt;
&lt;hr /&gt;&lt;p&gt;Thanks for reading this post via feed. Feeds are great, and you're great for using them. â™¥&lt;/p&gt;&lt;p&gt;This post was originally published on &lt;a href=&quot;https://abhinavsarkar.net/posts/nix-for-haskell-static-builds/?mtm_campaign=feed&quot;&gt;abhinavsarkar.net&lt;/a&gt;.&lt;/p&gt;&lt;h3&gt;Like, repost, or comment on:&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;a class=&quot;u-syndication&quot; href=&quot;https://fantastic.earth/@abnv/116771376765182410&quot; rel=&quot;syndication&quot; target=&quot;_blank&quot;&gt;Fediverse&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;u-syndication&quot; href=&quot;https://lobste.rs/s/medvuo&quot; rel=&quot;syndication&quot; target=&quot;_blank&quot;&gt;Lobsters&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;u-syndication&quot; href=&quot;https://www.reddit.com/r/haskell/comments/1u98wau/&quot; rel=&quot;syndication&quot; target=&quot;_blank&quot;&gt;Reddit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;u-syndication&quot; href=&quot;https://discourse.haskell.org/t//14287&quot; rel=&quot;syndication&quot; target=&quot;_blank&quot;&gt;Discourse&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/nix-for-haskell-static-builds/?mtm_campaign=feed#comment-container&quot;&gt;My website&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Read more of my &lt;a href=&quot;https://abhinavsarkar.net/posts/&quot;&gt;posts&lt;/a&gt; and &lt;a href=&quot;https://abhinavsarkar.net/notes/&quot;&gt;notes&lt;/a&gt;.&lt;/p&gt;&lt;img alt=&quot;&quot; src=&quot;https://anna.abhinavsarkar.net/matomo.php?idsite=1&amp;amp;rec=1&quot; style=&quot;border: 0;&quot; /&gt;</description>
	<pubDate>Thu, 18 Jun 2026 00:00:00 +0000</pubDate>
	<author>abhinav@abhinavsarkar.net (Abhinav Sarkar)</author>
</item>
<item>
	<title>Haskell Interlude: 83: POPL 2026 - Part 2</title>
	<guid isPermaLink="false">Buzzsprout-19343611</guid>
	<link></link>
	<description>&lt;p&gt;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.&lt;br /&gt;&lt;br /&gt;In this episode we talk about: symbolic execution monads, what a lazy linear core in Haskell might have in common with Rust, hyperfunctions, the hallway track, and how to deal with rejection.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;</description>
	<pubDate>Sun, 14 Jun 2026 18:00:00 +0000</pubDate>
        <enclosure url="https://www.buzzsprout.com/1817535/episodes/19343611-83-popl-2026-part-2.mp3" length="32340349" type="audio/mpeg"/>
</item>
<item>
	<title>Tweag I/O: Writing static checks to an unsuspecting library with Liquid Haskell</title>
	<guid isPermaLink="true">https://tweag.io/blog/2026-06-11-diff-package-static-checks/</guid>
	<link>https://tweag.io/blog/2026-06-11-diff-package-static-checks/</link>
	<description>&lt;p&gt;This post presents a little epic to insert static checks in Haskell’s &lt;a href=&quot;https://hackage.haskell.org/package/Diff&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Diff&lt;/code&gt; package&lt;/a&gt; using &lt;a href=&quot;https://ucsd-progsys.github.io/liquidhaskell/&quot;&gt;Liquid Haskell&lt;/a&gt; (LH).&lt;sup id=&quot;fnref-1&quot;&gt;&lt;a class=&quot;footnote-ref&quot; href=&quot;https://www.tweag.io/rss.xml#fn-1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;
Static or compile-time checks are helpful to confirm formerly implicit assumptions in the implementation,
providing an additional layer of assurance.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Making illegal states unrepresentable&lt;/em&gt; at an affordable cognitive cost is a staple of statically typed functional programming.
Endeavors like &lt;a href=&quot;https://ghc.serokell.io/dh&quot;&gt;Dependent Haskell&lt;/a&gt; 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.&lt;/p&gt;
&lt;p&gt;Liquid Haskell was created by the &lt;a href=&quot;https://ucsd-progsys.github.io/liquidhaskell/papers/#people&quot;&gt;UCSD Programming Systems group&lt;/a&gt;
and these days is mainly maintained and further improved by my colleague Facundo Domínguez.
&lt;a href=&quot;https://dl.acm.org/doi/10.1145/2633357.2633366&quot;&gt;Applying Liquid Haskell to strengthen libraries&lt;/a&gt; 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 &lt;a href=&quot;https://github.com/tweag/ormolu&quot;&gt;Ormolu&lt;/a&gt;,
of which &lt;code class=&quot;language-text&quot;&gt;Diff&lt;/code&gt; is a transitive dependency and a more suitable commitment given the engineering time I could bestow upon it.&lt;sup id=&quot;fnref-2&quot;&gt;&lt;a class=&quot;footnote-ref&quot; href=&quot;https://www.tweag.io/rss.xml#fn-2&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;h2 id=&quot;diff-will-never-be-the-same&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#diff-will-never-be-the-same&quot;&gt;&lt;/a&gt;&lt;code class=&quot;language-text&quot;&gt;Diff&lt;/code&gt; will never be the same&lt;/h2&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;Diff&lt;/code&gt; package is a small and (relatively) self-contained library implementing the &lt;a href=&quot;https://publications.mpi-cbg.de/Myers_1986_6330.pdf&quot;&gt;Myers diff algorithm&lt;/a&gt;.
As a provider of basic functionality in the Haskell ecosystem,
adding formal guarantees to it is of intrinsic value to the community.&lt;/p&gt;
&lt;p&gt;From the get-go, my objective was adding static checks to strengthen this library
in a contribution guided by two opposing desiderata:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Minimize source changes&lt;/li&gt;
&lt;li&gt;Maximize checked invariants&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;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 &lt;em&gt;specification annotations&lt;/em&gt;.
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.&lt;/p&gt;
&lt;p&gt;My first milestone was filling the mind gap between the &lt;code class=&quot;language-text&quot;&gt;Diff&lt;/code&gt; 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.&lt;sup id=&quot;fnref-3&quot;&gt;&lt;a class=&quot;footnote-ref&quot; href=&quot;https://www.tweag.io/rss.xml#fn-3&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;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 &lt;a href=&quot;https://pages.cs.wisc.edu/~remzi/Naur.pdf&quot;&gt;theory in its writer’s mind&lt;/a&gt;,
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.&lt;/p&gt;
&lt;p&gt;For example, I added a post-condition to this function haddock&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-haskell&quot;&gt;&lt;code class=&quot;language-haskell&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;PolyDiff&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;First&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Second&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Both&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;b&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- | Like 'getGroupedDiff' but accepts a custom equality predicate.&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;--&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;-- Postcondition: the output list is guaranteed to be /chunked/. i.e. no two adjacent&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;-- elements share the same constructor.&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;getGroupedDiffBy&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Bool&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PolyDiff&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-haskell&quot;&gt;&lt;code class=&quot;language-haskell&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- | Line Range: start, end and contents.&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;--&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;-- The following invariants hold:&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;--&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;-- &amp;gt; snd lrNumbers &amp;gt;= fst lrNumbers&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;-- &amp;gt; snd lrNumbers - fst lrNumbers + 1 == length lrContents&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;--&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;-- which imply @lrContents@ cannot be empty.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;LineRange&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;LineRange&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;lrNumbers&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;LineNo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;LineNo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                           &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;lrContents&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
                           &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;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!&lt;/p&gt;
&lt;p&gt;Engineering the static checks took me into a tight feedback loop between the documentation process,
coming up with refactorings&lt;sup id=&quot;fnref-4&quot;&gt;&lt;a class=&quot;footnote-ref&quot; href=&quot;https://www.tweag.io/rss.xml#fn-4&quot;&gt;4&lt;/a&gt;&lt;/sup&gt; 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 &lt;a href=&quot;https://www.tweag.io/blog/2026-04-16-doc-it-like-its-hot/&quot;&gt;&lt;em&gt;doc it like it’s hot&lt;/em&gt;&lt;/a&gt; philosophy.&lt;/p&gt;
&lt;h2 id=&quot;from-dry-code-to-liquid-types&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#from-dry-code-to-liquid-types&quot;&gt;&lt;/a&gt;From dry code to liquid types&lt;/h2&gt;
&lt;p&gt;After &lt;a href=&quot;https://ucsd-progsys.github.io/liquidhaskell/install/&quot;&gt;installing LH&lt;/a&gt;, 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&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Existing specifications are fulfilled&lt;/li&gt;
&lt;li&gt;Recursive functions terminate&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The first condition is not limited to local specifications;
LH comes bundled with &lt;a href=&quot;https://www.tweag.io/blog/2023-06-22-lh-assumption-imports/#new-solution-packages-with-assumptions&quot;&gt;specifications for many boot package functions&lt;/a&gt;.
For instance, many of Prelude’s partial functions are &lt;em&gt;refined&lt;/em&gt; this way to be total,
so LH tries to prove that all their uses are safe.&lt;/p&gt;
&lt;p&gt;One prominent example is &lt;code class=&quot;language-text&quot;&gt;head&lt;/code&gt;, which was the only failure of the first condition in &lt;code class=&quot;language-text&quot;&gt;Diff&lt;/code&gt;:
it was not certain that the list passed to &lt;code class=&quot;language-text&quot;&gt;head&lt;/code&gt; in its &lt;code class=&quot;language-text&quot;&gt;ses&lt;/code&gt; function is &lt;em&gt;always&lt;/em&gt; 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 &lt;a href=&quot;https://en.wikipedia.org/wiki/Refinement_type&quot;&gt;refinement types&lt;/a&gt;, found along the call stack.
Such specifications are introduced using a special comment syntax &lt;code class=&quot;language-text&quot;&gt;{-@ ... @-}&lt;/code&gt;
whose contents are processed to generate a set of constraints for an external &lt;a href=&quot;https://en.wikipedia.org/wiki/Satisfiability_modulo_theories&quot;&gt;SMT solver&lt;/a&gt; to verify.
This allows us to mechanically check function specifications, formed out of pre- and post-conditions,
and data invariants expressed as &lt;em&gt;simple&lt;/em&gt; 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 &lt;a href=&quot;https://ucsd-progsys.github.io/liquidhaskell/specifications/&quot;&gt;spec reference documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The same comment syntax is also used to set LH directives,
like the &lt;code class=&quot;language-text&quot;&gt;ignore&lt;/code&gt; annotation I used to skip checks in the body of the offending &lt;code class=&quot;language-text&quot;&gt;ses&lt;/code&gt; function.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-haskell&quot;&gt;&lt;code class=&quot;language-haskell&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;{-@ ignore ses @-}&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;ses&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Bool&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;DI&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;ses&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;eq&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;bs&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;head&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;dropWhile&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;dl&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;poi&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;dl&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;lena&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;poj&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;dl&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;lenb&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt;
            &lt;span class=&quot;token builtin&quot;&gt;concat&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;iterate&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;dstep&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;cd&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;addsnake&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;$&lt;/span&gt;
            &lt;span class=&quot;token constant&quot;&gt;DL&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;poi&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;poj&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;canDiag&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;eq&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;bs&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;lena&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;lenb&lt;/span&gt;
                  &lt;span class=&quot;token hvariable&quot;&gt;lena&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;lenb&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;bs&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;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 &lt;a href=&quot;https://ucsd-progsys.github.io/liquidhaskell/specifications/#termination-metrics&quot;&gt;termination metric&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;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 &lt;a href=&quot;https://ucsd-progsys.github.io/liquidhaskell/specifications/#default-termination-metrics&quot;&gt;associated size metric&lt;/a&gt; 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 &lt;code class=&quot;language-text&quot;&gt;doPrefix&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;doSuffix&lt;/code&gt;,
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 &lt;a href=&quot;https://ucsd-progsys.github.io/liquidhaskell/specifications/#lexicographic-termination-metrics&quot;&gt;lexicographic metric&lt;/a&gt;,
annotated with the syntax &lt;code class=&quot;language-text&quot;&gt;/ [metric1, metric2, ...]&lt;/code&gt; at the end of a function refinement,
to prove their termination:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-haskell&quot;&gt;&lt;code class=&quot;language-haskell&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Diff&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;PolyDiff&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;c&lt;/span&gt;

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

&lt;span class=&quot;token comment&quot;&gt;{-@ doSuffix :: hunk : [Diff [c]] -&amp;gt; [Diff [c]] / [len hunk, 1]@-}&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;doSuffix&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Diff&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Diff&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;doSuffix&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;doSuffix&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Both&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;xs&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;ys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Both&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;take&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;contextSize&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;xs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;take&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;contextSize&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;ys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;doSuffix&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Both&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;xs&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;ys&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;more&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;xs&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;contextSize&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Both&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;xs&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;ys&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;doPrefix&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;more&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;otherwise&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
      &lt;span class=&quot;token constant&quot;&gt;Both&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;take&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;contextSize&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;xs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;take&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;contextSize&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;ys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token hvariable&quot;&gt;doPrefix&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Both&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;drop&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;contextSize&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;xs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;drop&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;contextSize&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;ys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;more&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;doSuffix&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;d&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;ds&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;d&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;doSuffix&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;ds&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Using this metric LH checks that either the input &lt;code class=&quot;language-text&quot;&gt;hunk&lt;/code&gt; (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 &lt;code class=&quot;language-text&quot;&gt;doPrefix&lt;/code&gt; (0) from &lt;code class=&quot;language-text&quot;&gt;doSuffix&lt;/code&gt; (1) to be a strict reduction.
This second fallback metric is needed because of the third equation of &lt;code class=&quot;language-text&quot;&gt;doSuffix&lt;/code&gt; (second guard),
where &lt;code class=&quot;language-text&quot;&gt;doPrefix&lt;/code&gt; 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.&lt;/p&gt;
&lt;p&gt;Here I’ve presented instances of two general strategies to handle LH errors:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Fight: Fix the failing termination checks by introducing &lt;em&gt;metrics&lt;/em&gt;
and offending functions calls by adding specifications.&lt;/li&gt;
&lt;li&gt;Flight: Disable checks by using an &lt;em&gt;escape hatch&lt;/em&gt;, e.g. the &lt;code class=&quot;language-text&quot;&gt;{-@ lazy myRecursiveFunction @-}&lt;/code&gt; annotation to circumvent termination checking,
the &lt;code class=&quot;language-text&quot;&gt;{-@ ignore myOffendingFunction @-}&lt;/code&gt; to disable all checks within a function’s body
or the &lt;code class=&quot;language-text&quot;&gt;{-@ assume myFunction :: ... spec ... @-}&lt;/code&gt; to set a function specification as true without verification.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;em&gt;A priori&lt;/em&gt; it’s desirable to minimize the use of escape hatches,
but they’re also tools to prioritize static checking efforts.&lt;/p&gt;
&lt;h2 id=&quot;invariant-static-checking&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#invariant-static-checking&quot;&gt;&lt;/a&gt;Invariant static checking&lt;/h2&gt;
&lt;p&gt;One thing that made &lt;code class=&quot;language-text&quot;&gt;Diff&lt;/code&gt; particularly suitable for this effort is that a detailed specification of it existed in the form of a research paper.
Indeed, my &lt;a href=&quot;https://github.com/seereason/Diff/pull/21&quot;&gt;first documentation contribution&lt;/a&gt; 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 &lt;em&gt;edit grid&lt;/em&gt; to an endpoint,&lt;sup id=&quot;fnref-5&quot;&gt;&lt;a class=&quot;footnote-ref&quot; href=&quot;https://www.tweag.io/rss.xml#fn-5&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;
the latter representing the complete transformation of one input to the other.
The algorithm is in fact tersely expressed in the &lt;code class=&quot;language-text&quot;&gt;ses&lt;/code&gt; 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 &lt;em&gt;wave front&lt;/em&gt; 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.&lt;/p&gt;
&lt;p&gt;A wave front is defined as a list of nodes at the same &lt;em&gt;depth&lt;/em&gt;,
i.e. the edit trace length,
which is iterated upon by the &lt;code class=&quot;language-text&quot;&gt;dstep&lt;/code&gt; 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 &lt;a href=&quot;https://en.wikipedia.org/wiki/Lemma_(mathematics)&quot;&gt;lemmas&lt;/a&gt; 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 &lt;code class=&quot;language-text&quot;&gt;wfDiags&lt;/code&gt; 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.&lt;/p&gt;
&lt;p&gt;I encoded the fixed depth of nodes and their diagonal configuration using &lt;a href=&quot;https://ucsd-progsys.github.io/liquidhaskell/specifications/#type-aliases&quot;&gt;refinement type aliases&lt;/a&gt; to obtain a wave front specification.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-haskell&quot;&gt;&lt;code class=&quot;language-haskell&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- | A node representing the tip of a path in the edit grid.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;DL&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;DL&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;DI&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;   &lt;span class=&quot;token comment&quot;&gt;-- ^ The edit trace accumulated so far&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;deriving&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Show&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Eq&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- A node at a fixed edit trace length (depth).&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;{-@ type DLN D = { x : DL | len (path x) = D } @-}&lt;/span&gt;

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

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

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

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

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

&lt;span class=&quot;token comment&quot;&gt;{-@ type Hunk c = { h : [ValidListDiff c c] | noStuttering h} @-}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The interesting part here is the check for the &lt;code class=&quot;language-text&quot;&gt;noStuttering&lt;/code&gt; invariant in the specification of the main &lt;code class=&quot;language-text&quot;&gt;Hunk&lt;/code&gt; 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 &lt;code class=&quot;language-text&quot;&gt;doPrefix&lt;/code&gt;,
that is part of it,
for the check to pass.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-haskell&quot;&gt;&lt;code class=&quot;language-haskell&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;{-@ doPrefix ::  h : Hunk c
             -&amp;gt; {v : [ValidListDiff c c] | noFFSS v
                 &amp;amp;&amp;amp; ... other auxiliary post-conditions ... } / [len h, 0] @-}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Essentially, this function traverses a given &lt;code class=&quot;language-text&quot;&gt;Hunk&lt;/code&gt; and chops and splits &lt;code class=&quot;language-text&quot;&gt;Both&lt;/code&gt; elements to a context size argument.
After doing so the &lt;code class=&quot;language-text&quot;&gt;Hunk&lt;/code&gt; “stutters” on such elements,
so it stops being a &lt;code class=&quot;language-text&quot;&gt;Hunk&lt;/code&gt; in the &lt;em&gt;refined&lt;/em&gt; 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 &lt;code class=&quot;language-text&quot;&gt;noFFSS&lt;/code&gt; helper characterizes the resulting list;
it is like &lt;code class=&quot;language-text&quot;&gt;noStuttering&lt;/code&gt;, but just for the other &lt;code class=&quot;language-text&quot;&gt;PolyDiff&lt;/code&gt; constructors: &lt;code class=&quot;language-text&quot;&gt;First&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;Second&lt;/code&gt;.
Other auxiliary post-conditions (not shown) stating that input and output lists shared head constructors were also necessary for this check.&lt;/p&gt;
&lt;p&gt;The verification of these and other invariants followed a similar outline:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Identify and document the invariant&lt;/li&gt;
&lt;li&gt;Encode it in refinements&lt;/li&gt;
&lt;li&gt;Write the specifications&lt;/li&gt;
&lt;li&gt;Please the compiler&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;For instance,
the last step to get back a &lt;code class=&quot;language-text&quot;&gt;Hunk&lt;/code&gt; after the &lt;code class=&quot;language-text&quot;&gt;doPrefix&lt;/code&gt;-&lt;code class=&quot;language-text&quot;&gt;doSuffix&lt;/code&gt; operation required passing a lemma within a local dead binding for the specification to be verified.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-haskell&quot;&gt;&lt;code class=&quot;language-haskell&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;{-@ assume lemmaReverseNoStuttering
      :: xs:_ -&amp;gt; { noStuttering (reverse xs) = noStuttering xs } @-}&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;lemmaReverseNoStuttering&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Hunk&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;lemmaReverseNoStuttering&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- | Split a 'Diff' list at consecutive 'Both'-'Both' boundaries.&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;{-@ splitBothBoth :: {ds:[ValidListDiff c c] | noFFSS ds} -&amp;gt; [Hunk c] @-}&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;splitBothBoth&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Diff&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Hunk&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;splitBothBoth&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;where&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;{-@ go
          :: g:Hunk c
          -&amp;gt; {xs : [ValidListDiff c c] | noFFSS xs &amp;amp;&amp;amp; not (headAlike g xs) }
          -&amp;gt; [Hunk c] / [len xs]
      @-}&lt;/span&gt;
    &lt;span class=&quot;token hvariable&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Hunk&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Diff&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Hunk&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token hvariable&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Both&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Both&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;xs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;reverse&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;xs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;where&lt;/span&gt;
        &lt;span class=&quot;token hvariable&quot;&gt;lemma&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;lemmaReverseNoStuttering&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token hvariable&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;xs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;xs&lt;/span&gt;
    &lt;span class=&quot;token hvariable&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;reverse&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;where&lt;/span&gt;
        &lt;span class=&quot;token hvariable&quot;&gt;lemma&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;lemmaReverseNoStuttering&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;g&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;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 &lt;code class=&quot;language-text&quot;&gt;reverse&lt;/code&gt; preserves the &lt;code class=&quot;language-text&quot;&gt;noStuttering&lt;/code&gt; of a &lt;code class=&quot;language-text&quot;&gt;PolyDiff&lt;/code&gt; list,
so I provided it.&lt;/p&gt;
&lt;p&gt;I decided to &lt;code class=&quot;language-text&quot;&gt;assume&lt;/code&gt; 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.&lt;/p&gt;
&lt;h2 id=&quot;lifting-a-dam&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#lifting-a-dam&quot;&gt;&lt;/a&gt;Lifting a dam&lt;/h2&gt;
&lt;p&gt;After this work I’m flooded with many thoughts and feelings about LH from the user perspective,
but also ideas for important future developments.&lt;/p&gt;
&lt;p&gt;One particular source of difficulty I found is differentiating between the existing means of &lt;em&gt;lifting&lt;/em&gt; a Haskell function into the logic:
&lt;code class=&quot;language-text&quot;&gt;reflect&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;inline&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;measure&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;define&lt;/code&gt;.
By default, Haskell functions like &lt;code class=&quot;language-text&quot;&gt;wfDiag&lt;/code&gt; 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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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 &lt;code class=&quot;language-text&quot;&gt;Diff&lt;/code&gt; 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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h2 id=&quot;clearing-up-the-waters&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#clearing-up-the-waters&quot;&gt;&lt;/a&gt;Clearing up the waters&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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!&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn-1&quot;&gt;At the time of writing, the static checks are about to be proposed for upstream integration. But they can be found in the &lt;a href=&quot;https://github.com/ucsd-progsys/liquidhaskell/tree/5e043ad25987fed9d11c8df365ac7fae396262d6/tests/Diff&quot;&gt;Liquid Haskell test suite&lt;/a&gt; as well.&lt;a class=&quot;footnote-backref&quot; href=&quot;https://www.tweag.io/rss.xml#fnref-1&quot;&gt;↩&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn-2&quot;&gt;A nice perk of working at Tweag is being supported to do open source contributions during or in-between client projects.&lt;a class=&quot;footnote-backref&quot; href=&quot;https://www.tweag.io/rss.xml#fnref-2&quot;&gt;↩&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn-3&quot;&gt;Found in &lt;a href=&quot;https://github.com/seereason/Diff/pull/21&quot;&gt;https://github.com/seereason/Diff/pull/21&lt;/a&gt; and &lt;a href=&quot;https://github.com/seereason/Diff/pull/23&quot;&gt;https://github.com/seereason/Diff/pull/23&lt;/a&gt;&lt;a class=&quot;footnote-backref&quot; href=&quot;https://www.tweag.io/rss.xml#fnref-3&quot;&gt;↩&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn-4&quot;&gt;Found in &lt;a href=&quot;https://github.com/seereason/Diff/pull/24&quot;&gt;https://github.com/seereason/Diff/pull/24&lt;/a&gt;, &lt;a href=&quot;https://github.com/seereason/Diff/pull/25&quot;&gt;https://github.com/seereason/Diff/pull/25&lt;/a&gt;, &lt;a href=&quot;https://github.com/seereason/Diff/pull/26&quot;&gt;https://github.com/seereason/Diff/pull/26&lt;/a&gt; and &lt;a href=&quot;https://github.com/seereason/Diff/pull/27&quot;&gt;https://github.com/seereason/Diff/pull/27&lt;/a&gt;.&lt;a class=&quot;footnote-backref&quot; href=&quot;https://www.tweag.io/rss.xml#fnref-4&quot;&gt;↩&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn-5&quot;&gt;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.&lt;a class=&quot;footnote-backref&quot; href=&quot;https://www.tweag.io/rss.xml#fnref-5&quot;&gt;↩&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description>
	<pubDate>Thu, 11 Jun 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Stackage Blog: Stackage talk at Haskell Ecosystem Workshop 2026</title>
	<guid isPermaLink="true">https://www.stackage.org/blog/2026/06/hashell-ecosystem-ws-2026-talk</guid>
	<link>https://www.stackage.org/blog/2026/06/hashell-ecosystem-ws-2026-talk</link>
	<description>&lt;h2&gt;Stackage talk at Haskell Ecosystem Workshop 2026&lt;/h2&gt;
&lt;p&gt;Jens Petersen gave a talk about Stackage at
the Haskell Ecosystem Workshop 2026 (4th June),
organized by the Haskell Foundation before Zurihac.&lt;/p&gt;
&lt;p&gt;Here are the html &lt;a href=&quot;https://petersen.fedorapeople.org/talks/hew-2026-stackage.html&quot;&gt;slides&lt;/a&gt; (&lt;a href=&quot;https://petersen.fedorapeople.org/talks/hew-2026-stackage-single.html&quot;&gt;single page html&lt;/a&gt;).&lt;/p&gt;</description>
	<pubDate>Mon, 08 Jun 2026 16:00:00 +0000</pubDate>
</item>
<item>
	<title>Gabriella Gonzalez: Ergonomic overrides for Nixpkgs</title>
	<guid isPermaLink="true">https://haskellforall.com/2026/06/ergonomic-overrides-for-nixpkgs</guid>
	<link>https://haskellforall.com/2026/06/ergonomic-overrides-for-nixpkgs</link>
	<description>Announcement post for the override-utils Nix package</description>
	<pubDate>Sat, 06 Jun 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Philip Wadler: Professor Emeritus</title>
	<guid isPermaLink="false">tag:blogger.com,1999:blog-9757377.post-7786446406428155110</guid>
	<link>https://wadler.blogspot.com/2026/06/professor-emeritus.html</link>
	<description>&lt;div class=&quot;separator&quot;&gt;&lt;p style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; class=&quot;alignleft size-medium wp-image-217956&quot; height=&quot;640&quot; src=&quot;https://www.angrymetalguy.com/wp-content/uploads/2025/06/Professor-Emeritus_A-Land-Long-Gone-01-350x350.jpg&quot; width=&quot;640&quot; /&gt;&lt;/p&gt;&lt;/div&gt;&lt;p style=&quot;font-style: normal; line-height: normal; margin: 0px;&quot;&gt;&lt;span style=&quot;font-size: large;&quot;&gt;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.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;font-style: normal; line-height: normal; margin: 0px;&quot;&gt;&lt;span style=&quot;font-family: times;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;font-style: normal; line-height: normal; margin: 0px; text-align: center;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: times;&quot;&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p style=&quot;font-style: normal; line-height: normal; margin: 0px; text-align: center;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: times;&quot;&gt;Special Minute&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p style=&quot;font-style: normal; line-height: normal; margin: 0px; text-align: center;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: times;&quot;&gt;Professor Philip Wadler BSc, MSc, PhD, FRSE, FACM, FRS&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p style=&quot;font-style: normal; line-height: normal; margin: 0px; text-align: center;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: times;&quot;&gt;Emeritus Professor of Theoretical Computer Science&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p style=&quot;font-style: normal; line-height: normal; margin: 0px;&quot;&gt;&lt;span style=&quot;font-family: times;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;font-style: normal; line-height: normal; margin: 0px;&quot;&gt;&lt;span style=&quot;font-family: times;&quot;&gt;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.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;font-style: normal; line-height: normal; margin: 0px;&quot;&gt;&lt;span style=&quot;font-family: times;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;font-style: normal; line-height: normal; margin: 0px;&quot;&gt;&lt;span style=&quot;font-family: times;&quot;&gt;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 &lt;/span&gt;&lt;span style=&quot;font-family: times;&quot;&gt;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.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;font-style: normal; line-height: normal; margin: 0px;&quot;&gt;&lt;span style=&quot;font-family: times;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;font-style: normal; line-height: normal; margin: 0px;&quot;&gt;&lt;span style=&quot;font-family: times;&quot;&gt;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 &lt;/span&gt;&lt;span style=&quot;font-family: times;&quot;&gt;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 &lt;/span&gt;&lt;span style=&quot;font-family: times;&quot;&gt;and developer conferences. In 2016, his sixtieth birthday was marked by a two-day &lt;/span&gt;&lt;i style=&quot;font-family: times;&quot;&gt;Wadlerfest&lt;/i&gt;&lt;span style=&quot;font-family: times;&quot;&gt;, and an accompanying festschrift published by Springer.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;font-style: normal; line-height: normal; margin: 0px;&quot;&gt;&lt;span style=&quot;font-family: times;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;font-style: normal; line-height: normal; margin: 0px;&quot;&gt;&lt;span style=&quot;font-family: times;&quot;&gt;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 &lt;/span&gt;&lt;span style=&quot;font-family: times;&quot;&gt;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.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;font-style: normal; line-height: normal; margin: 0px;&quot;&gt;&lt;span style=&quot;font-family: times;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;font-style: normal; line-height: normal; margin: 0px;&quot;&gt;&lt;span style=&quot;font-family: times;&quot;&gt;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 &lt;/span&gt;&lt;span style=&quot;font-family: times;&quot;&gt;of his online text for the proof assistant Agda updated to the proof assistant Lean. He will appear again this summer at the Fringe.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;font-style: normal; line-height: normal; margin: 0px;&quot;&gt;&lt;span style=&quot;font-family: times;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;font-style: normal; line-height: normal; margin: 0px;&quot;&gt;&lt;span style=&quot;font-family: times;&quot;&gt;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 &lt;/span&gt;&lt;span style=&quot;font-family: times;&quot;&gt;Professor on Professor Wadler would honour his substantial contributions to the University of Edinburgh and the broader scientific community.&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style=&quot;font-style: normal; line-height: normal; margin: 0px;&quot;&gt;&lt;span style=&quot;font-family: times;&quot;&gt;&lt;/span&gt;&lt;/p&gt;</description>
	<pubDate>Thu, 04 Jun 2026 17:46:04 +0000</pubDate>
	<author>noreply@blogger.com (Philip Wadler)</author>
</item>
<item>
	<title>Well-Typed.Com: Faster Cabal Haskell builds by eliminating redundant work</title>
	<guid isPermaLink="false">http://www.well-typed.com/blog/2026/05/faster-haskell-builds</guid>
	<link>https://well-typed.com/blog/2026/05/faster-haskell-builds</link>
	<description>&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; Build your Haskell projects 10-15% faster with this one simple trick!
(Spoiler: the simple trick is to wait for the next major &lt;code&gt;cabal-install&lt;/code&gt; release.)&lt;/p&gt;
&lt;p&gt;In &lt;a href=&quot;https://well-typed.com/blog/2023/10/sovereign-tech-fund-invests-in-cabal/&quot;&gt;previous work&lt;/a&gt; (paid for by the Sovereign Tech Fund) we
did a lot of heavy lifting to make a major architectural change to &lt;code&gt;Cabal&lt;/code&gt;. That
work is now paying off with practical benefits. This post covers follow-on
architectural improvements to &lt;code&gt;cabal-install&lt;/code&gt; which then enable us to eliminate
redundant work in the &lt;code&gt;configure&lt;/code&gt; phase, yielding significant reductions in
build times.&lt;/p&gt;
&lt;p&gt;The changes will be available to everyone in the next major &lt;code&gt;cabal-install&lt;/code&gt;
release. For a large project like &lt;code&gt;pandoc&lt;/code&gt; (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 &lt;code&gt;--semaphore&lt;/code&gt;. No user changes are needed to take advantage
of this improvement.&lt;/p&gt;

&lt;h3 id=&quot;history-cabal-and-cabal-install&quot;&gt;History: &lt;code&gt;Cabal&lt;/code&gt; and &lt;code&gt;cabal-install&lt;/code&gt;&lt;/h3&gt;
&lt;h4 id=&quot;the-genesis-the-cabal-specification&quot;&gt;The genesis: the &lt;code&gt;Cabal&lt;/code&gt; specification&lt;/h4&gt;
&lt;p&gt;First, there was &lt;code&gt;Cabal&lt;/code&gt;. Its design was laid out in &lt;a href=&quot;https://www.haskell.org/cabal/proposal/pkg-spec.pdf&quot;&gt;A Common Architecture for Building Applications
and Tools&lt;/a&gt;. Fundamentally, it defines the notion of a package, with
each package being built and installed with the following sequence of commands:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; hc Setup.hs
&amp;gt; ./Setup configure
&amp;gt; ./Setup build
&amp;gt; ./Setup install&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each package must be built in dependency order, with &lt;code&gt;hc-pkg&lt;/code&gt; registering each
installed library into a package database.&lt;/p&gt;
&lt;h4 id=&quot;orchestrating-the-build-of-multiple-packages&quot;&gt;Orchestrating the build of multiple packages&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;cabal-install&lt;/code&gt; 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.&lt;/p&gt;
&lt;p&gt;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:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What Haskell compiler are we using?&lt;/li&gt;
&lt;li&gt;What system libraries are available (&lt;code&gt;pkgconfig-depends&lt;/code&gt;)?&lt;/li&gt;
&lt;li&gt;What build tools are available (&lt;code&gt;build-tool-depends&lt;/code&gt;)?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This means that &lt;code&gt;cabal-install&lt;/code&gt; 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 &lt;code&gt;./Setup configure&lt;/code&gt; phase. However,
the command-line interface of &lt;code&gt;./Setup configure&lt;/code&gt; makes it practically
impossible to do so: passing a fully resolved dependency graph would require many
additions to the &lt;a href=&quot;https://hackage-content.haskell.org/package/Cabal/docs/Distribution-Simple-Setup.html#t:ConfigFlags&quot;&gt;already bloated &lt;code&gt;ConfigFlags&lt;/code&gt; datatype&lt;/a&gt;,
and a lot more data being serialised/deserialised.&lt;/p&gt;
&lt;p&gt;Because of this limitation, &lt;code&gt;cabal-install&lt;/code&gt;’s approach was to take its hard-won
build plan and convert it into &lt;code&gt;ConfigFlags&lt;/code&gt; that specify exact dependency
versions and flag assignments. This amounts to passing &lt;code&gt;./Setup configure&lt;/code&gt;
an already fully constrained configuration; the &lt;code&gt;configure&lt;/code&gt; step would then
re-probe the system, re-read package databases… only to re-discover exactly
what &lt;code&gt;cabal-install&lt;/code&gt; already knew!&lt;/p&gt;
&lt;h3 id=&quot;a-new-architecture-for-cabal-install&quot;&gt;A new architecture for &lt;code&gt;cabal-install&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The paradigm shift proposed in &lt;a href=&quot;https://well-typed.com/blog/2023/10/sovereign-tech-fund-invests-in-cabal/&quot;&gt;our Sovereign Tech Fund proposal&lt;/a&gt;
is that &lt;code&gt;cabal-install&lt;/code&gt; should be responsible for orchestrating the whole build
process instead of running the conceptually independent build systems provided by
each package. With &lt;code&gt;cabal-install&lt;/code&gt; now in control, it can directly call &lt;code&gt;Cabal&lt;/code&gt;
library functions, which in turn allows skipping steps in the &lt;code&gt;configure&lt;/code&gt; phase
that waste time re-discovering information that &lt;code&gt;cabal-install&lt;/code&gt; is already
aware of.&lt;/p&gt;
&lt;p&gt;To implement such a change, we first needed to prepare the terrain: when invoking
an external executable such as the &lt;code&gt;Setup&lt;/code&gt; executable – say via the
&lt;a href=&quot;https://hackage.haskell.org/package/process&quot;&gt;&lt;code&gt;process&lt;/code&gt; library&lt;/a&gt; as &lt;code&gt;Cabal&lt;/code&gt; uses – we can set the working
directory, environment variables and redirect input/output handles.
It was not possible to do this directly via the &lt;code&gt;Cabal&lt;/code&gt; library, so we first
needed to add &lt;code&gt;Cabal&lt;/code&gt; library support for &lt;a href=&quot;https://github.com/haskell/cabal/pull/9718&quot;&gt;setting the working directory&lt;/a&gt;
and for &lt;a href=&quot;https://github.com/haskell/cabal/pull/11077&quot;&gt;choosing logging handles&lt;/a&gt;. Once this was done,
it allowed us to refactor &lt;code&gt;cabal-install&lt;/code&gt; to &lt;a href=&quot;https://github.com/haskell/cabal/pull/11703&quot;&gt;directly call &lt;code&gt;Cabal&lt;/code&gt; library functions to build packages&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;performance-impact&quot;&gt;Performance impact&lt;/h3&gt;
&lt;p&gt;This architectural change provides a solid foundation for further improvements.
The two main time sinks in the &lt;code&gt;Cabal&lt;/code&gt; &lt;code&gt;configure&lt;/code&gt; phase were determined to be
(using a new &lt;a href=&quot;https://github.com/haskell/cabal/pull/11769&quot;&gt;&lt;code&gt;--build-timings&lt;/code&gt; flag to &lt;code&gt;cabal-install&lt;/code&gt;&lt;/a&gt;):&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;(~50% of &lt;code&gt;configure&lt;/code&gt; time) Re-configuring the compiler program database.
The compiler and &lt;code&gt;hc-pkg&lt;/code&gt; were already pre-configured, but other programs
such as &lt;code&gt;haddock&lt;/code&gt;, &lt;code&gt;ar&lt;/code&gt;, &lt;code&gt;ld&lt;/code&gt; etc were re-configured anew for each package.&lt;/li&gt;
&lt;li&gt;(~40% of &lt;code&gt;configure&lt;/code&gt; time) Re-probing the installed package database, via &lt;code&gt;hc-pkg dump&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We can skip this extra work by &lt;a href=&quot;https://github.com/haskell/cabal/pull/11768&quot;&gt;pre-configuring the compiler &lt;code&gt;ProgramDb&lt;/code&gt;&lt;/a&gt;
and &lt;a href=&quot;https://github.com/haskell/cabal/pull/11767&quot;&gt;keeping a running &lt;code&gt;InstalledPackageIndex&lt;/code&gt;&lt;/a&gt;. These
two changes, taken together, reduce the time spent in the &lt;code&gt;configure&lt;/code&gt; phase by
over 90%.&lt;/p&gt;
&lt;p&gt;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 &lt;code&gt;aeson&lt;/code&gt; with &lt;code&gt;-j1&lt;/code&gt;, we saw a reduction
in total build time of ~16.6% (std.dev. 1.9pp) in our benchmarks.&lt;/p&gt;
&lt;p&gt;The fact that the &lt;code&gt;configure&lt;/code&gt; phase is inherently serial also means that these
improvements have a notable impact when combined with &lt;a href=&quot;https://well-typed.com/blog/2023/08/reducing-haskell-parallel-build-times/&quot;&gt;the &lt;code&gt;-jsem&lt;/code&gt; feature&lt;/a&gt;.
This is because the &lt;code&gt;-jsem&lt;/code&gt; feature allows us to assign more capabilities to
the &lt;code&gt;build&lt;/code&gt; phase. As per &lt;a href=&quot;https://en.wikipedia.org/wiki/Amdahl%27s_law&quot;&gt;Amdahl’s law&lt;/a&gt;, this results in the
&lt;code&gt;configure&lt;/code&gt; phase becoming more of a bottleneck. For example, when compiling
&lt;code&gt;pandoc&lt;/code&gt; with &lt;code&gt;cabal install pandoc -j16 --semaphore&lt;/code&gt;, we saw a reduction in
total build time of ~10% (std.dev. 0.6pp).&lt;/p&gt;
&lt;h3 id=&quot;further-improvements&quot;&gt;Further improvements&lt;/h3&gt;
&lt;p&gt;These improvements provide a small glimpse of what is possible after our changes
to &lt;code&gt;cabal-install&lt;/code&gt;’s architecture. A more ambitious long-term goal would be for
&lt;code&gt;cabal-install&lt;/code&gt; to manage a “giant build graph” on a finer granularity level
than whole Cabal components. For example, if package &lt;code&gt;q&lt;/code&gt; depends only
on module &lt;code&gt;P1&lt;/code&gt; from package &lt;code&gt;p&lt;/code&gt;, we could imagine starting to compile &lt;code&gt;q&lt;/code&gt; after
compiling &lt;code&gt;P1&lt;/code&gt; but before we have finished compiling the rest of &lt;code&gt;p&lt;/code&gt;. This
would unlock build-time reductions by increasing available parallelism,
and also enable more accurate progress and error reporting.&lt;/p&gt;</description>
	<pubDate>Thu, 28 May 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Theory Lunch (Institute of Cybernetics, Tallinn): A Remarkable Property of Real-Valued Functions on Intervals of the Real Line</title>
	<guid isPermaLink="false">http://theorylunch.wordpress.com/?p=1809</guid>
	<link>https://theorylunch.wordpress.com/2019/10/17/a-remarkable-property-of-real-valued-functions-on-intervals-of-the-real-line/</link>
	<description>&lt;p class=&quot;wp-block-paragraph&quot;&gt;Today the 17 October 2019 I discussed a very remarkable fixed point theorem discovered by the Ukrainian mathematician &lt;a href=&quot;https://en.wikipedia.org/wiki/Oleksandr_Mykolayovych_Sharkovsky&quot;&gt;Oleksandr Micholayovych Sharkovsky&lt;/a&gt;.&lt;/p&gt;



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



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



&lt;span id=&quot;more-1809&quot;&gt;&lt;/span&gt;



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



&lt;p class=&quot;wp-block-paragraph&quot;&gt;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.&lt;/p&gt;



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



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



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



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



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



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



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



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



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



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



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



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



&lt;p class=&quot;wp-block-paragraph&quot;&gt;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.&lt;/p&gt;



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



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



&lt;li&gt;Sort the pairs with &lt;img alt=&quot;m&amp;gt;1&quot; class=&quot;latex&quot; src=&quot;https://s0.wp.com/latex.php?latex=m%3E1&amp;amp;bg=ffffff&amp;amp;fg=333333&amp;amp;s=0&amp;amp;c=20201002&quot; /&gt; in lexicographic order.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;For example, &lt;img alt=&quot;17\rhd243&quot; class=&quot;latex&quot; src=&quot;https://s0.wp.com/latex.php?latex=17%5Crhd243&amp;amp;bg=ffffff&amp;amp;fg=333333&amp;amp;s=0&amp;amp;c=20201002&quot; /&gt; and &lt;img alt=&quot;4095\rhd6&quot; class=&quot;latex&quot; src=&quot;https://s0.wp.com/latex.php?latex=4095%5Crhd6&amp;amp;bg=ffffff&amp;amp;fg=333333&amp;amp;s=0&amp;amp;c=20201002&quot; /&gt;&lt;/li&gt;



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



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



&lt;p class=&quot;wp-block-paragraph&quot;&gt;The set of positive integer with the Sharkowsky ordering has then the form:&lt;/p&gt;



&lt;p class=&quot;has-text-align-center wp-block-paragraph&quot;&gt;&lt;img alt=&quot;3\rhd5\rhd7\rhd\ldots\rhd6\rhd10\rhd14\rhd\ldots\rhd12\rhd20\rhd28\rhd\ldots\rhd8\rhd4\rhd2\rhd1&quot; class=&quot;latex&quot; src=&quot;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;amp;bg=ffffff&amp;amp;fg=333333&amp;amp;s=0&amp;amp;c=20201002&quot; /&gt;&lt;/p&gt;



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



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



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



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



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Bibliography:&lt;/p&gt;



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



&lt;li&gt;Robert L. Devaney, &lt;em&gt;An Introduction to Chaotic Dynamical Systems&lt;/em&gt;, Second Edition, Westview Press 2003.&lt;/li&gt;



&lt;li&gt;Shlomo Sternberg, &lt;em&gt;Dynamical Systems&lt;/em&gt;, Dover 2010.&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;/p&gt;</description>
	<pubDate>Fri, 22 May 2026 15:51:36 +0000</pubDate>
</item>
<item>
	<title>Haskell Interlude: 82: Fraser Tweedale</title>
	<guid isPermaLink="false">Buzzsprout-19202127</guid>
	<link></link>
	<description>&lt;p&gt;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.&lt;/p&gt;</description>
	<pubDate>Tue, 19 May 2026 12:00:00 +0000</pubDate>
        <enclosure url="https://www.buzzsprout.com/1817535/episodes/19202127-82-fraser-tweedale.mp3" length="34957725" type="audio/mpeg"/>
</item>
<item>
	<title>Gabriella Gonzalez: Type out the code</title>
	<guid isPermaLink="true">https://haskellforall.com/2026/05/type-out-the-code</guid>
	<link>https://haskellforall.com/2026/05/type-out-the-code</link>
	<description>Freecoding improves broader programming proficiency</description>
	<pubDate>Tue, 19 May 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Eric Kidd: Redoubtful: Linux agent sandbox progress</title>
	<guid isPermaLink="true">http://www.randomhacks.net/2026/05/17/redoubtful-agent-sandbox-progress/</guid>
	<link>http://www.randomhacks.net/2026/05/17/redoubtful-agent-sandbox-progress/</link>
	<description>&lt;p&gt;I’ve also been experimenting with agent sandboxes lately. &lt;a href=&quot;https://github.com/emk/redoubtful&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;redoubtful&lt;/code&gt;&lt;/a&gt; is a work-in-progress sandbox that supports:&lt;/p&gt;

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

&lt;p&gt;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 &lt;em&gt;very&lt;/em&gt; 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.&lt;/p&gt;

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

&lt;h3 id=&quot;modular-configuration-profiles&quot;&gt;Modular configuration “profiles”&lt;/h3&gt;

&lt;p&gt;One of the &lt;em&gt;slightly&lt;/em&gt; 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:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;redoubtful run &lt;span class=&quot;nt&quot;&gt;--uses&lt;/span&gt; pi &lt;span class=&quot;nt&quot;&gt;--uses&lt;/span&gt; llama-server pi
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here, we’re running the &lt;a href=&quot;https://pi.dev/&quot;&gt;pi.dev&lt;/a&gt; coding agent with a locally-served Qwen3.6 27B via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;llama-server&lt;/code&gt;. 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.&lt;/p&gt;

&lt;p&gt;To set up these two profiles, we first define a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node&lt;/code&gt; profile:&lt;/p&gt;

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

&lt;p&gt;Then let’s make Rust work:&lt;/p&gt;

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

&lt;p&gt;And then basic &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git&lt;/code&gt; is easy—we just need enough config to read &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;user.name&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;user.email&lt;/code&gt;:&lt;/p&gt;

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

&lt;p&gt;And then finally, we can set up &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pi&lt;/code&gt; itself:&lt;/p&gt;

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

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

&lt;h3 id=&quot;whats-left&quot;&gt;What’s left?&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;</description>
	<pubDate>Sun, 17 May 2026 18:50:36 +0000</pubDate>
</item>
<item>
	<title>Eric Kidd: Lab notebook: Edit completion #1</title>
	<guid isPermaLink="true">http://www.randomhacks.net/2026/05/16/lab-notebook-edit-completion-1/</guid>
	<link>http://www.randomhacks.net/2026/05/16/lab-notebook-edit-completion-1/</link>
	<description>&lt;p&gt;I &lt;a href=&quot;https://www.randomhacks.net/2026/05/13/edit-completion-with-qwen36/&quot;&gt;continue to be interested&lt;/a&gt; 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?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;I like and use agentic workflows. But as many people are realizing, &lt;a href=&quot;https://blog.k10s.dev/im-going-back-to-writing-code-by-hand/&quot;&gt;it’s &lt;em&gt;super&lt;/em&gt; easy to lose track of what’s happening in your code, with terrible consequences&lt;/a&gt;. So I want to reinvest in human-in-the-loop tools, too. (And slightly weaker agentic models, but more on that later.)&lt;/li&gt;
  &lt;li&gt;The new-school edit completion offered by Copilot and &lt;a href=&quot;https://zed.dev/blog/zeta2&quot;&gt;Zed’s Zeta2&lt;/a&gt; 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 &lt;em&gt;really fast&lt;/em&gt; touch typing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h3 id=&quot;initial-experiments&quot;&gt;Initial experiments&lt;/h3&gt;

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

&lt;p&gt;&lt;strong&gt;New-school models (generating diffs).&lt;/strong&gt; 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.&lt;/p&gt;

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

&lt;ul&gt;
  &lt;li&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ggml-org/Qwen2.5-Coder-7B-Q8_0-GGUF:Q8_0&lt;/code&gt;: The classic, default choice. This isn’t &lt;em&gt;terrible&lt;/em&gt;, 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.&lt;/li&gt;
  &lt;li&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mradermacher/Seed-Coder-8B-Base-i1-GGUF:Q6_K&lt;/code&gt;. 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.&lt;/li&gt;
  &lt;li&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JetBrains/Mellum-4b-base-gguf:Q8_0&lt;/code&gt;. Downloaded, but not yet tested.&lt;/li&gt;
  &lt;li&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unsloth/Qwen3.6-35B-A3B-GGUF:IQ4_XS&lt;/code&gt;. This is &lt;a href=&quot;https://www.randomhacks.net/2026/05/13/edit-completion-with-qwen36/&quot;&gt;unexpectedly good&lt;/a&gt;! Worth further experimentation.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;refining-qwen36-35b-a3b-changing-order-from-psm-to-spm&quot;&gt;Refining Qwen3.6 35B A3B: Changing order from PSM to SPM&lt;/h2&gt;

&lt;p&gt;Qwen typically uses FIM, “Fill in the Middle” completion. This uses 3 magic tokens:&lt;/p&gt;

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

&lt;p&gt;We have two possible flavors. The original is “PSM” compeletion, “prefix, suffix, middle”:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-txt&quot;&gt;{PRE}{prefix}{SUF}{suffix}{MID}
&lt;/code&gt;&lt;/pre&gt;

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

&lt;pre&gt;&lt;code class=&quot;language-txt&quot;&gt;{SUF}{suffix}{PRE}{prefix}{MID}
&lt;/code&gt;&lt;/pre&gt;

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

&lt;p&gt;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 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/completion&lt;/code&gt;, and translates PSM to SPM please.”&lt;/p&gt;

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

&lt;pre&gt;&lt;code class=&quot;language-txt&quot;&gt;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}
&lt;/code&gt;&lt;/pre&gt;

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

&lt;p&gt;&lt;strong&gt;Possible next steps:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;What if we modify the proxy to transform &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/completion&lt;/code&gt; into a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/chat/completions&lt;/code&gt; request, with a real prompt, real text inputs, and tool for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;insert_at_cursor(text)&lt;/code&gt;? Can we access more of the model’s intelligence?&lt;/li&gt;
  &lt;li&gt;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 &lt;a href=&quot;https://tree-sitter.github.io/tree-sitter/&quot;&gt;tree-sitter&lt;/a&gt; to generate custom completion examples. Would that give us something useful?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I also notice that FIM-style models are &lt;em&gt;notoriously&lt;/em&gt; 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 &lt;em&gt;good&lt;/em&gt; stopping places?&lt;/p&gt;</description>
	<pubDate>Sat, 16 May 2026 15:49:55 +0000</pubDate>
</item>
<item>
	<title>Oskar Wickström: Coding on Paper</title>
	<guid isPermaLink="true">https://wickstrom.tech/2026-05-16-coding-on-paper.html</guid>
	<link>https://wickstrom.tech/2026-05-16-coding-on-paper.html</link>
	<description>&lt;p&gt;About three months ago, I bought the &lt;a href=&quot;https://shop.boox.com/products/boox-mira-procolor-version&quot;&gt;Onyx BOOX 25.3” Mira Pro Color&lt;/a&gt;, 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.&lt;/p&gt; &lt;p&gt;This is &lt;em&gt;not&lt;/em&gt; a sponsored post, and it is &lt;em&gt;not&lt;/em&gt; a product review. I wrote a very similar post about the &lt;a href=&quot;https://wickstrom.tech/2025-10-10-programming-in-the-sun-a-year-with-the-daylight-computer.html&quot;&gt;Daylight DC-1&lt;/a&gt; last year.&lt;/p&gt; &lt;figure&gt; &lt;img alt=&quot;Neovim in the morning sunlight.&quot; src=&quot;https://wickstrom.tech/assets/mira-pro-1.webp&quot; /&gt; &lt;figcaption&gt;Neovim in the morning sunlight.&lt;/figcaption&gt; &lt;/figure&gt; &lt;p&gt;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.&lt;/p&gt; &lt;p&gt;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.&lt;/p&gt; &lt;figure&gt; &lt;img alt=&quot;Spending a workday in the garden.&quot; src=&quot;https://wickstrom.tech/assets/mira-pro-2.webp&quot; /&gt; &lt;figcaption&gt;Spending a workday in the garden.&lt;/figcaption&gt; &lt;/figure&gt; &lt;p&gt;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.&lt;/p&gt; &lt;p&gt;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.&lt;/p&gt; &lt;p&gt;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.&lt;/p&gt; &lt;p&gt;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.&lt;/p&gt; &lt;p&gt;The monitor has a clunky menu system with which you can change rendering modes; things like contrast and speed. I found &lt;a href=&quot;https://github.com/ipodnerd3019/mira-js&quot;&gt;an open-source reverse-engineered NodeJS package&lt;/a&gt; that I use with Hyprland keybindings to easily change rendering modes and manually refresh. No need for the built-in menu.&lt;/p&gt; &lt;p&gt;In practice I use two modes:&lt;/p&gt; &lt;dl&gt; &lt;dt&gt;Reading:&lt;/dt&gt; &lt;dd&gt; &lt;p&gt;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.&lt;/p&gt; &lt;/dd&gt; &lt;dt&gt;Writing:&lt;/dt&gt; &lt;dd&gt; &lt;p&gt;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.&lt;/p&gt; &lt;/dd&gt; &lt;/dl&gt; &lt;p&gt;See the following photos for a close-up comparison:&lt;/p&gt; &lt;figure&gt; &lt;img alt=&quot;Reading mode, where colored regions are pretty smooth and text looks sharp.&quot; src=&quot;https://wickstrom.tech/assets/mira-pro-5.webp&quot; /&gt; &lt;figcaption&gt;Reading mode, where colored regions are pretty smooth and text looks sharp.&lt;/figcaption&gt; &lt;/figure&gt; &lt;figure&gt; &lt;img alt=&quot;Writing mode, where colored regions (light gray, red, green) are grainy and text is a bit blurry.&quot; src=&quot;https://wickstrom.tech/assets/mira-pro-6.webp&quot; /&gt; &lt;figcaption&gt;Writing mode, where colored regions (light gray, red, green) are grainy and text is a bit blurry.&lt;/figcaption&gt; &lt;/figure&gt; &lt;p&gt;What about latency? Here’s the two short clips of me typing with the reading and writing modes:&lt;/p&gt; &lt;figure&gt; &lt;video controls=&quot;&quot; src=&quot;https://wickstrom.tech/assets/mira-pro-slow.mp4&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/assets/mira-pro-slow.mp4&quot;&gt;Reading mode, with horrible latency for typing.&lt;/a&gt;&lt;/video&gt; &lt;figcaption&gt;Reading mode, with horrible latency for typing.&lt;/figcaption&gt; &lt;/figure&gt; &lt;figure&gt; &lt;video controls=&quot;&quot; src=&quot;https://wickstrom.tech/assets/mira-pro-fast.mp4&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/assets/mira-pro-fast.mp4&quot;&gt;Writing mode, with some but acceptable latency.&lt;/a&gt;&lt;/video&gt; &lt;figcaption&gt;Writing mode, with some but acceptable latency.&lt;/figcaption&gt; &lt;/figure&gt; &lt;p&gt;Ghosting? In my writing mode it’s minimal. It really doesn’t bother me.&lt;/p&gt; &lt;p&gt;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.&lt;/p&gt; &lt;p&gt;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):&lt;/p&gt; &lt;figure&gt; &lt;img alt=&quot;Color vs Monochrome e-ink panels without backlight.&quot; src=&quot;https://wickstrom.tech/assets/mira-pro-7.webp&quot; /&gt; &lt;figcaption&gt;Color vs Monochrome e-ink panels without backlight.&lt;/figcaption&gt; &lt;/figure&gt; &lt;p&gt;Unless the room has great diffuse lighting, natural or otherwise, the color panel does require &lt;em&gt;some&lt;/em&gt; 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.&lt;/p&gt; &lt;p&gt;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.&lt;/p&gt; &lt;p&gt;My custom themes and keybindings can be found &lt;a href=&quot;https://github.com/owickstrom/nixos/tree/master&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;</description>
	<pubDate>Fri, 15 May 2026 22:00:00 +0000</pubDate>
</item>
<item>
	<title>Eric Kidd: I should blog more</title>
	<guid isPermaLink="true">http://www.randomhacks.net/2026/05/13/i-should-blog-more/</guid>
	<link>http://www.randomhacks.net/2026/05/13/i-should-blog-more/</link>
	<description>&lt;p&gt;This blog is ancient, in blog years. The first post was on June 30, 1998, and it featured a &lt;a href=&quot;https://www.randomhacks.net/1998/06/30/randomhacks-online-mathmap/&quot;&gt;randomized emboss for MathMap&lt;/a&gt;. 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 &lt;a href=&quot;https://w1mx.mit.edu/flea-at-mit/&quot;&gt;the MIT Swapfest&lt;/a&gt;, and it lived under my desk.&lt;/p&gt;

&lt;p&gt;Google hadn’t been incoporated yet. The Internet bubble was still inflating.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

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

&lt;p&gt;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 &lt;a href=&quot;https://notes.andymatuschak.org/Work_with_the_garage_door_up&quot;&gt;work with the garage door up&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So maybe it’s time to get back this site’s roots. I don’t have any &lt;a href=&quot;https://www.complang.tuwien.ac.at/schani/mathmap/dist/&quot;&gt;MathMap&lt;/a&gt; snippets for you today, sadly, because the last release seems to have been in 2004. &lt;a href=&quot;http://www.randomhacks.net/2026/05/13/edit-completion-with-qwen36/&quot;&gt;But here’s a cool trick!&lt;/a&gt;&lt;/p&gt;</description>
	<pubDate>Wed, 13 May 2026 05:04:52 +0000</pubDate>
</item>
<item>
	<title>Eric Kidd: Edit completion works with Qwen3.6 35B A3B!</title>
	<guid isPermaLink="true">http://www.randomhacks.net/2026/05/13/edit-completion-with-qwen36/</guid>
	<link>http://www.randomhacks.net/2026/05/13/edit-completion-with-qwen36/</link>
	<description>&lt;p&gt;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 &lt;a href=&quot;https://api-docs.deepseek.com/guides/fim_completion&quot;&gt;“FIM completion”&lt;/a&gt;. And the classic model for doing this is &lt;a href=&quot;https://huggingface.co/Qwen/Qwen2.5-Coder-7B&quot;&gt;Qwen2.5 Coder 7B&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;So let’s fire it up using &lt;a href=&quot;https://github.com/ggml-org/llama.cpp&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;llama-server&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;

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

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

&lt;p&gt;Then, we can configure it using &lt;a href=&quot;https://zed.dev/&quot;&gt;Zed&lt;/a&gt;:&lt;/p&gt;

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

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;But this is an actual, working, 100% local autocomplete. And it’s &lt;em&gt;close&lt;/em&gt; to being actually good.&lt;/p&gt;</description>
	<pubDate>Wed, 13 May 2026 05:04:52 +0000</pubDate>
</item>
<item>
	<title>Oskar Wickström: Catching Typos on My Website with Browser Testing</title>
	<guid isPermaLink="true">https://wickstrom.tech/2026-05-13-catching-typos-website-browser-testing.html</guid>
	<link>https://wickstrom.tech/2026-05-13-catching-typos-website-browser-testing.html</link>
	<description>&lt;p&gt;One neat thing about &lt;a href=&quot;https://antithesishq.github.io/bombadil/3-specification-language.html#specification-language&quot;&gt;Bombadil’s specification language&lt;/a&gt; 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.&lt;/p&gt; &lt;dl&gt; &lt;dt&gt;The inner loop (spell-checking):&lt;/dt&gt; &lt;dd&gt; &lt;p&gt;Bombadil randomly walks the website and collects misspelled words as property violations. The specification uses &lt;a href=&quot;https://github.com/wooorm/nspell&quot;&gt;nspell&lt;/a&gt; with &lt;a href=&quot;https://github.com/wooorm/dictionaries/tree/main/dictionaries/en&quot;&gt;American and British English dictionaries&lt;/a&gt; and a personal word list in the repository. This is &lt;em&gt;fast&lt;/em&gt; and &lt;em&gt;strict&lt;/em&gt;.&lt;/p&gt; &lt;/dd&gt; &lt;dt&gt;The outer loop (triage):&lt;/dt&gt; &lt;dd&gt; &lt;p&gt;I’m running Claude Code with a spell-checking skill, a triage loop that goes something like this:&lt;/p&gt; &lt;ol type=&quot;1&quot;&gt; &lt;li&gt;Run Bombadil against the local development server for 5 minutes and capture the output. If no words flagged, we’re done.&lt;/li&gt; &lt;li&gt;Collect each flagged word and the URL it appeared on.&lt;/li&gt; &lt;li&gt;Triage each word into one of these buckets: &lt;ul&gt; &lt;li&gt;Real typo: fix the markdown source&lt;/li&gt; &lt;li&gt;Legitimate common word: add to the custom dictionary&lt;/li&gt; &lt;li&gt;Legitimate uncommon or very technical word: mark inline with &lt;code&gt;spellcheck=&quot;false&quot;&lt;/code&gt;&lt;/li&gt; &lt;li&gt;Extraction noise: add a unit test and fix the word extractor&lt;/li&gt; &lt;/ul&gt;&lt;/li&gt; &lt;li&gt;Run Bombadil against each failing URL to confirm the corrections.&lt;/li&gt; &lt;li&gt;Go to step 1.&lt;/li&gt; &lt;/ol&gt; &lt;p&gt;This is &lt;em&gt;slow&lt;/em&gt; and &lt;em&gt;loose&lt;/em&gt;.&lt;/p&gt; &lt;/dd&gt; &lt;/dl&gt; &lt;p&gt;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. &lt;span&gt;Example typos include “forseeable”, “similiar”, “perculiar”, “occured”. Some of these were 10 years old.&lt;/span&gt;&lt;/p&gt; &lt;p&gt;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.&lt;/p&gt; &lt;p&gt;Note that using an LLM is entirely optional. It just saves me some time. You can do triage on your own.&lt;/p&gt; &lt;p&gt;Why not spell-check the sources directly? Yes, that is often preferable, and I use &lt;code&gt;spell&lt;/code&gt; 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 &lt;a href=&quot;https://crates.io/crates/typos-cli&quot;&gt;typos&lt;/a&gt; and &lt;a href=&quot;https://github.com/codespell-project/codespell&quot;&gt;codespell&lt;/a&gt;, 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.&lt;/p&gt; &lt;p&gt;Speaking of source-level checking: since the custom dictionary is a plain word list, I point Neovim’s &lt;code&gt;spellfile&lt;/code&gt; at it and use &lt;code&gt;zg&lt;/code&gt; to add words while I edit. A single source of truth that both tools write to.&lt;/p&gt; &lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode lua&quot;&gt;&lt;code class=&quot;sourceCode lua&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb1-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;va&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;opt&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;spellfile&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;/path/to/custom.utf-8.add&quot;&lt;/span&gt;&lt;/span&gt; &lt;span id=&quot;cb1-2&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb1-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;va&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;opt&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;spelllang&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;en&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; &lt;p&gt;Being able to use NPM packages in specifications has turned out to be more useful than I expected. In addition to &lt;code&gt;nspell&lt;/code&gt;, I’m using &lt;a href=&quot;https://www.npmjs.com/package/tlds&quot;&gt;tlds&lt;/a&gt; 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.&lt;/p&gt; &lt;p&gt;If you’re interested in setting up something like this on your own, you’ll find the sources in &lt;a href=&quot;https://github.com/owickstrom/bombadil-playground/tree/master/wickstrom.tech&quot;&gt;my Bombadil playground&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;&lt;em&gt;Disclosure: I’m the original author and lead for the Bombadil project at Antithesis.&lt;/em&gt;&lt;/p&gt;</description>
	<pubDate>Tue, 12 May 2026 22:00:00 +0000</pubDate>
</item>
<item>
	<title>Well-Typed.Com: Exception Annotations: Lay of the Land</title>
	<guid isPermaLink="false">http://www.well-typed.com/blog/2026/05/lay-annotation-land</guid>
	<link>https://well-typed.com/blog/2026/05/lay-annotation-land</link>
	<description>&lt;p&gt;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.&lt;/p&gt;

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

&lt;section class=&quot;footnotes footnotes-end-of-document&quot; id=&quot;footnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;&lt;p&gt;We will ignore calls to &lt;code&gt;withFrozenCallStack&lt;/code&gt;, which hide some internal
functions from the &lt;code&gt;HasCallStack&lt;/code&gt; backtrace. This makes the backtrace slightly
more readable, but does not otherwise change anything. See
&lt;a href=&quot;https://github.com/haskell/core-libraries-committee/issues/387&quot;&gt;CLC #387&lt;/a&gt;.&lt;a class=&quot;footnote-back&quot; href=&quot;https://well-typed.com/blog/rss2.xml#fnref1&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn2&quot;&gt;&lt;p&gt;Some versions of &lt;code&gt;base&lt;/code&gt; distinguish
between &lt;code&gt;catchExceptionNoPropagate&lt;/code&gt; and &lt;code&gt;catchNoPropagate&lt;/code&gt;, which differ only in
some strictness annotations. Strictness can make a big difference, especially
when IO actions are &lt;code&gt;undefined&lt;/code&gt; rather than throwing an exception. However, this
is its own can of worms, and outside the scope of this blog post. See &lt;a href=&quot;https://github.com/haskell/core-libraries-committee/issues/383&quot;&gt;CLC
proposal #383&lt;/a&gt; for some discussion.&lt;a class=&quot;footnote-back&quot; href=&quot;https://well-typed.com/blog/rss2.xml#fnref2&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn3&quot;&gt;&lt;p&gt;In GHC 9.10, &lt;code&gt;displayException&lt;/code&gt; &lt;em&gt;did&lt;/em&gt; show
annotaitons, but this got rolled back in 9.12; see &lt;a href=&quot;https://github.com/haskell/core-libraries-committee/issues/285&quot;&gt;CLC #285&lt;/a&gt; for a
detailed discussion.&lt;a class=&quot;footnote-back&quot; href=&quot;https://well-typed.com/blog/rss2.xml#fnref3&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
	<pubDate>Fri, 08 May 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Oleg Grenrus: Compatibility packages in 2026</title>
	<guid isPermaLink="true">https://oleg.fi/gists/posts/2026-05-07-compatibility-packages-b.html</guid>
	<link>https://oleg.fi/gists/posts/2026-05-07-compatibility-packages-b.html</link>
	<description>&lt;div class=&quot;info&quot;&gt;
    Posted on 2026-05-07
    
        by Oleg Grenrus
    

    &lt;a href=&quot;https://oleg.fi/tags/engineering.html&quot; title=&quot;All pages tagged 'engineering'.&quot;&gt;engineering&lt;/a&gt;
&lt;/div&gt;

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

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

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

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

&lt;p&gt;
This makes it easier to make a change, fix the errors caused by the change and
then return to where I was.
&lt;/p&gt;
&lt;div class=&quot;taglist&quot;&gt;&lt;a href=&quot;https://magnus.therning.org/tags.html&quot;&gt;&lt;span class=&quot;tag-label&quot;&gt;Tags&lt;/span&gt;&lt;/a&gt;&lt;span class=&quot;tag-separator&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;taglist__tags&quot;&gt;&lt;a class=&quot;tag&quot; href=&quot;https://magnus.therning.org/tag-emacs.html&quot;&gt;emacs&lt;/a&gt; &lt;a class=&quot;tag&quot; href=&quot;https://magnus.therning.org/tag-evil.html&quot;&gt;evil&lt;/a&gt; &lt;/span&gt;&lt;/div&gt;</description>
	<pubDate>Mon, 04 May 2026 06:16:00 +0000</pubDate>
</item>
<item>
	<title>Magnus Therning: Follow-up on switching to eglot</title>
	<guid isPermaLink="true">https://magnus.therning.org/2026-05-02-follow-up-on-switching-to-eglot.html</guid>
	<link>https://magnus.therning.org/2026-05-02-follow-up-on-switching-to-eglot.html</link>
	<description>&lt;p&gt;
Jan G sent me a two-part comment.
&lt;/p&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-org3a78e0b&quot;&gt;
&lt;h2 id=&quot;org3a78e0b&quot;&gt;Part one&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-org3a78e0b&quot;&gt;
&lt;blockquote&gt;
&lt;p&gt;
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.
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
I wouldn't know. All I can say is that it would be nice if package managers that
hook into, or completely redefines &lt;code&gt;use-package&lt;/code&gt;, would document if they deviate
from the behaviour of &quot;vanilla &lt;code&gt;use-package&lt;/code&gt;&quot; in some way.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgac4cab1&quot;&gt;
&lt;h2 id=&quot;orgac4cab1&quot;&gt;Part two&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgac4cab1&quot;&gt;
&lt;blockquote&gt;
&lt;p&gt;
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.
&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;
The README for Elpaca says that
&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;
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.
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
but that seems like a very big hammer and as I understand it I'd have to move
the whole &lt;code&gt;:init&lt;/code&gt; block for &lt;code&gt;python-mode&lt;/code&gt; into the hook in that case. Playing
around with the various blocks for &lt;code&gt;use-package&lt;/code&gt; isn't too time consuming and I
think it's a good first thing to try.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;taglist&quot;&gt;&lt;a href=&quot;https://magnus.therning.org/tags.html&quot;&gt;Tags&lt;/a&gt;: &lt;a href=&quot;https://magnus.therning.org/tag-emacs.html&quot;&gt;emacs&lt;/a&gt; &lt;/div&gt;</description>
	<pubDate>Sat, 02 May 2026 11:20:00 +0000</pubDate>
</item>
<item>
	<title>Magnus Therning: Secrets when connecting to DBs</title>
	<guid isPermaLink="true">https://magnus.therning.org/2026-05-02-secrets-when-connecting-to-dbs.html</guid>
	<link>https://magnus.therning.org/2026-05-02-secrets-when-connecting-to-dbs.html</link>
	<description>&lt;p&gt;
I should have dealt with comments I got to my posts on how I deal with secrets
in my work notes, &lt;a href=&quot;https://magnus.therning.org/2024-09-01-improving-how-i-handle-secrets-in-my-work-notes.html&quot;&gt;here&lt;/a&gt;, and &lt;a href=&quot;https://magnus.therning.org/2024-09-09-followup-on-secrets-in-my-work-notes.html&quot;&gt;here&lt;/a&gt;. Better late than never though, I hope.
&lt;/p&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgad48ff7&quot;&gt;
&lt;h2 id=&quot;orgad48ff7&quot;&gt;Comment from Stefano R&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgad48ff7&quot;&gt;
&lt;p&gt;
The first one is a link to post titled &lt;a href=&quot;https://stefanorodighiero.net/blog/how-i-use-dbconnection-in-org.html&quot;&gt;How I use :dbconnection in org files&lt;/a&gt;. It
describes a nice way of setting &lt;code&gt;sql-connection-alist&lt;/code&gt; based on the contents of
a file, in his case &lt;code&gt;~/.pgppass&lt;/code&gt;.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-org4a61064&quot;&gt;
&lt;h2 id=&quot;org4a61064&quot;&gt;Comment from Harald J&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-org4a61064&quot;&gt;
&lt;p&gt;
The other starts with a function for searching &lt;code&gt;~/.authinfo.gpg&lt;/code&gt; for entries of
the form
&lt;/p&gt;

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

&lt;p&gt;
and then setting &lt;code&gt;sql-password-search-wallet-function&lt;/code&gt; and &lt;code&gt;sql-password-wallet&lt;/code&gt;
to tell &lt;code&gt;sql-mode&lt;/code&gt; to use it
&lt;/p&gt;

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

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

&lt;p&gt;
The value for &lt;code&gt;sql-connection-alist&lt;/code&gt; is then as normal
&lt;/p&gt;

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

&lt;p&gt;
and the blocks in orgmode looks like this
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-org&quot;&gt;&lt;code&gt;&lt;span class=&quot;org-org-modern-block-name&quot;&gt;&lt;span class=&quot;org-org-block-begin-line&quot;&gt;SRC&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-org-block-begin-line&quot;&gt; sql-mode :product oracle :dbconnection i3v1e-ro :results raw
&lt;/span&gt;&lt;span class=&quot;org-org-block&quot;&gt;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;
&lt;/span&gt;&lt;span class=&quot;org-org-modern-block-name&quot;&gt;&lt;span class=&quot;org-org-block-end-line&quot;&gt;SRC&lt;/span&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-org6448d06&quot;&gt;
&lt;h2 id=&quot;org6448d06&quot;&gt;Thoughts&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-org6448d06&quot;&gt;
&lt;p&gt;
Both of these feel closer to the intent of &lt;code&gt;sql-mode&lt;/code&gt; in a way. I'll have to try
using &lt;code&gt;sql-connection-alist&lt;/code&gt; at some point.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;taglist&quot;&gt;&lt;a href=&quot;https://magnus.therning.org/tags.html&quot;&gt;Tags&lt;/a&gt;: &lt;a href=&quot;https://magnus.therning.org/tag-emacs.html&quot;&gt;emacs&lt;/a&gt; &lt;/div&gt;</description>
	<pubDate>Sat, 02 May 2026 10:41:00 +0000</pubDate>
</item>
<item>
	<title>Oskar Wickström: The Bombadil Terminal Experiment</title>
	<guid isPermaLink="true">https://wickstrom.tech/2026-04-30-bombadil-terminal-experiment.html</guid>
	<link>https://wickstrom.tech/2026-04-30-bombadil-terminal-experiment.html</link>
	<description>&lt;p&gt;Last week at &lt;a href=&quot;https://antithesis.com/bugbash/conference2026/&quot;&gt;Bug Bash 2026&lt;/a&gt;, I had a bunch of interesting discussions about testing non-web interfaces with &lt;a href=&quot;http://bombadil.bot/&quot;&gt;Bombadil&lt;/a&gt;, our new property-based testing framework for user interfaces. One direction that I already wanted to explore is &lt;em&gt;terminal user interfaces&lt;/em&gt; (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.&lt;/p&gt; &lt;figure&gt; &lt;video controls=&quot;&quot; src=&quot;https://wickstrom.tech/assets/tetris-stuck.mp4&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/assets/tetris-stuck.mp4&quot;&gt;The fuzzer in action, finding a bug in vitetris. (CW: flashing!)&lt;/a&gt;&lt;/video&gt; &lt;figcaption&gt;The fuzzer in action, finding a bug in vitetris. (CW: flashing!)&lt;/figcaption&gt; &lt;/figure&gt; &lt;p&gt;It’s built on top of two key crates:&lt;/p&gt; &lt;ol type=&quot;1&quot;&gt; &lt;li&gt;&lt;a href=&quot;https://crates.io/crates/portable-pty&quot;&gt;portable-pty&lt;/a&gt;, a pseudo-teletype in Rust that runs the program under test, and&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://crates.io/crates/libghostty-vt&quot;&gt;libghostty-vt&lt;/a&gt;, 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.&lt;/li&gt; &lt;/ol&gt; &lt;p&gt;With these two in place, I built a &lt;em&gt;very&lt;/em&gt; 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.&lt;/p&gt; &lt;p&gt;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:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a href=&quot;https://github.com/vicgeralds/vitetris&quot;&gt;vitetris&lt;/a&gt; has a bug where if you enter just a number in the host name (e.g. &lt;code&gt;6&lt;/code&gt;) and try to connect to a remote game, the UI freezes.&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://github.com/aristocratos/btop&quot;&gt;btop&lt;/a&gt; has two different bugs, &lt;a href=&quot;https://github.com/aristocratos/btop/issues/1010&quot;&gt;one recently fixed&lt;/a&gt; that I confirmed fixed with the latest version (1.4.6), and &lt;a href=&quot;https://github.com/aristocratos/btop/issues/1627&quot;&gt;one that I just reported&lt;/a&gt;. Both were triggered by this fuzzer.&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://github.com/hanslub42/rlwrap&quot;&gt;rlwrap&lt;/a&gt; got into a segfault which I haven’t yet been able to troubleshoot.&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;Pretty cool. Today, I merged this work to &lt;code&gt;main&lt;/code&gt; in Bombadil. It’s not yet released, but if you’re curious you can try it already by downloading a &lt;code&gt;bombadil-terminal&lt;/code&gt; binary from the &lt;a href=&quot;https://github.com/antithesishq/bombadil/actions/workflows/ci.yml&quot;&gt;CI&lt;/a&gt; artifacts. On macOS you’ll need to remove the quarantine bit to bypass GateKeeper.&lt;/p&gt; &lt;p&gt;Now, the work remains to make this a solid tool. Here are some future goals:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;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 &lt;code&gt;querySelector&lt;/code&gt; that could parse and traverse panels drawn with box-drawing characters. You probably also want to validate that those borders line up correctly.&lt;/li&gt; &lt;li&gt;Generate a lot more diverse input and terminal actions. For instance, generate sequences from the &lt;a href=&quot;https://sw.kovidgoyal.net/kitty/keyboard-protocol/&quot;&gt;Kitty keyboard protocol&lt;/a&gt;.&lt;/li&gt; &lt;li&gt;Make the test runner’s user interface better. Perhaps a TUI?!&lt;/li&gt; &lt;li&gt;Make this part of the ordinary &lt;code&gt;bombadil&lt;/code&gt; binary, I think. There could be subcommands for &lt;code&gt;browser&lt;/code&gt; and &lt;code&gt;terminal&lt;/code&gt; testing tools.&lt;/li&gt; &lt;li&gt;Run it in Antithesis to see what that fuzzer can find.&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;All right, short post today — I just wanted to share my excitement and early results.&lt;/p&gt; &lt;p&gt;&lt;em&gt;A huge thanks to &lt;a href=&quot;https://github.com/Uzaaft&quot;&gt;Uzair Aftab&lt;/a&gt;, maintainer of &lt;a href=&quot;https://github.com/Uzaaft/libghostty-rs&quot;&gt;libghostty-rs&lt;/a&gt;, for helping me get libghostty-vt building under Nix!&lt;/em&gt;&lt;/p&gt;</description>
	<pubDate>Wed, 29 Apr 2026 22:00:00 +0000</pubDate>
</item>
<item>
	<title>Donnacha Oisín Kidney: Tries for Polynomials</title>
	<guid isPermaLink="true">https://doisinkidney.com/posts/2026-04-28-poly-trie.html</guid>
	<link>https://doisinkidney.com/posts/2026-04-28-poly-trie.html</link>
	<description>&lt;div class=&quot;info&quot;&gt;
    Posted on April 28, 2026
&lt;/div&gt;
&lt;div class=&quot;info&quot;&gt;
    
&lt;/div&gt;
&lt;div class=&quot;info&quot;&gt;
    
        Tags: &lt;a href=&quot;https://doisinkidney.com/tags/Haskell.html&quot; rel=&quot;tag&quot; title=&quot;All pages tagged 'Haskell'.&quot;&gt;Haskell&lt;/a&gt;
    
&lt;/div&gt;

&lt;p&gt;One of my favourite Haskell papers is McIlroyâ€™s wonderful â€œPower
Series, Power Seriousâ€� &lt;span class=&quot;citation&quot;&gt;(&lt;a href=&quot;https://doisinkidney.com/rss.xml#ref-mcilroy_power_1999&quot;&gt;1999&lt;/a&gt;)&lt;/span&gt;. The paper is about &lt;em&gt;power
series&lt;/em&gt;, which are a type of infinite sums that behave like
(infinite) polynomials. For example,
&amp;lt;semantics&amp;gt;cos&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;\cos&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;
can be represented by the following power series:&lt;/p&gt;
&lt;p&gt;&amp;lt;semantics&amp;gt;cos⁡(x)=1âˆ’x22!+x44!âˆ’x66!+x88!âˆ’x1010!+â‹¯&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;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&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;&lt;/p&gt;
&lt;p&gt;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:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb1-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PowerSeries&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;Rational&lt;/span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In this encoding, we can write
&amp;lt;semantics&amp;gt;cos&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;\cos&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;
as the following:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb2-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb2-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;cos&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PowerSeries&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb2-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;cos&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;zipWith&lt;/span&gt; (&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt;) (&lt;span class=&quot;fu&quot;&gt;cycle&lt;/span&gt; [&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;]) (&lt;span class=&quot;fu&quot;&gt;scanl&lt;/span&gt; (&lt;span class=&quot;op&quot;&gt;/&lt;/span&gt;) &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt; [&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;..&lt;/span&gt;])&lt;/span&gt;
&lt;span id=&quot;cb2-3&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb2-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-4&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb2-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;cos&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-5&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb2-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;[&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;24&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;720&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can also build
&amp;lt;semantics&amp;gt;sin&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;\sin&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb3&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb3-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb3-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;sin&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;zipWith&lt;/span&gt; (&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt;) (&lt;span class=&quot;fu&quot;&gt;cycle&lt;/span&gt; [&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;]) (&lt;span class=&quot;fu&quot;&gt;scanl&lt;/span&gt; (&lt;span class=&quot;op&quot;&gt;/&lt;/span&gt;) &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt; [&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;..&lt;/span&gt;])&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;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:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb4&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb4-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb4-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PowerSeries&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb4-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-3&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb4-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  (x&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;xs) &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; (y&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;ys) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; (x&lt;span class=&quot;op&quot;&gt;+&lt;/span&gt;y) &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; (xs &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; ys)&lt;/span&gt;
&lt;span id=&quot;cb4-4&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb4-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-5&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb4-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  (x&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;xs) &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; ys &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;map&lt;/span&gt; (x&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt;) ys &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; (&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; xs &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; ys)&lt;/span&gt;
&lt;span id=&quot;cb4-6&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb4-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-7&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb4-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;negate&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;negate&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-8&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb4-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-9&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb4-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;fromInteger&lt;/span&gt; n &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fromInteger&lt;/span&gt; n &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;repeat&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(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)&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;citation&quot;&gt;McIlroy (&lt;a href=&quot;https://doisinkidney.com/rss.xml#ref-mcilroy_power_1999&quot;&gt;1999&lt;/a&gt;)&lt;/span&gt;
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:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb5&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb5-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb5-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Polynomial&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;Rational&lt;/span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;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:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb6&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb6-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb6-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Polynomial&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb6-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-3&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb6-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  []     &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; ys     &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ys&lt;/span&gt;
&lt;span id=&quot;cb6-4&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb6-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  xs     &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; []     &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; xs&lt;/span&gt;
&lt;span id=&quot;cb6-5&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb6-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  (x&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;xs) &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; (y&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;ys) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; (x&lt;span class=&quot;op&quot;&gt;+&lt;/span&gt;y) &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; (xs &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; ys)&lt;/span&gt;
&lt;span id=&quot;cb6-6&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb6-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-7&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb6-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  []     &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; _  &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; []&lt;/span&gt;
&lt;span id=&quot;cb6-8&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb6-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  (x&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;xs) &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; ys &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;map&lt;/span&gt; (x&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt;) ys &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; (&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; xs &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; ys)&lt;/span&gt;
&lt;span id=&quot;cb6-9&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb6-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-10&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb6-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;negate&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;negate&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-11&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb6-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-12&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb6-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;fromInteger&lt;/span&gt; n &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; [&lt;span class=&quot;fu&quot;&gt;fromInteger&lt;/span&gt; n]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The only semantic trickiness with this representation is that itâ€™s
important to quotient by trailing zeroes.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb7&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb7-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb7-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Polynomial&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb7-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  [] &lt;span class=&quot;op&quot;&gt;==&lt;/span&gt; ys &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;all&lt;/span&gt; (&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;==&lt;/span&gt;) ys&lt;/span&gt;
&lt;span id=&quot;cb7-3&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb7-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  xs &lt;span class=&quot;op&quot;&gt;==&lt;/span&gt; [] &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;all&lt;/span&gt; (&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;==&lt;/span&gt;) xs&lt;/span&gt;
&lt;span id=&quot;cb7-4&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb7-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  (x&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;xs) &lt;span class=&quot;op&quot;&gt;==&lt;/span&gt; (y&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;ys) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; (x &lt;span class=&quot;op&quot;&gt;==&lt;/span&gt; y) &lt;span class=&quot;op&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (xs &lt;span class=&quot;op&quot;&gt;==&lt;/span&gt; ys)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;evaluation-and-horners-rule&quot;&gt;Evaluation and Hornerâ€™s Rule&lt;/h2&gt;
&lt;p&gt;The definition of a power series above suggests that we should
implement evaluation using exponentiation and indices:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb8&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb8-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb8-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;eval ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Polynomial&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rational&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rational&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb8-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;eval p x &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;sum&lt;/span&gt; (&lt;span class=&quot;fu&quot;&gt;zipWith&lt;/span&gt; (\a i &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; a &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; x&lt;span class=&quot;op&quot;&gt;^&lt;/span&gt;i) p [&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;..&lt;/span&gt;])&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And this does in fact give us the correct answer. Consider the
polynomial
&amp;lt;semantics&amp;gt;4+2x+5x2âˆ’x3&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;4 + 2x + 5x^2 - x^3&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb9&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb9-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb9-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;poly &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; [&lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;] &lt;span class=&quot;co&quot;&gt;-- 4 + 2x + 5xÂ² - xÂ³&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb9-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;eval poly x &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; eval [&lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;] x&lt;/span&gt;
&lt;span id=&quot;cb9-3&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb9-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;sum&lt;/span&gt; (&lt;span class=&quot;fu&quot;&gt;zipWith&lt;/span&gt; (\a i &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; a &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; x &lt;span class=&quot;op&quot;&gt;^&lt;/span&gt; i) [&lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;] [&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;..&lt;/span&gt;])&lt;/span&gt;
&lt;span id=&quot;cb9-4&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb9-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt;x&lt;span class=&quot;op&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt;x&lt;span class=&quot;op&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt;x&lt;span class=&quot;op&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; (&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;)&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt;x&lt;span class=&quot;op&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-5&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb9-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt;x &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt;x&lt;span class=&quot;op&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;-&lt;/span&gt; x&lt;span class=&quot;op&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;However, this evaluation algorithm is unsatisfactory in one respect:
it performs a &lt;em&gt;lot&lt;/em&gt; 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
&amp;lt;semantics&amp;gt;2x=2Ã—x&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;2x = 2 \times x&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;,
two for
&amp;lt;semantics&amp;gt;5x2=5Ã—xÃ—x&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;5x^2 = 5 \times x \times x&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;,
and three for
&amp;lt;semantics&amp;gt;âˆ’x3=âˆ’1Ã—xÃ—xÃ—x&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;-x^3 = -1 \times x \times x \times x&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;.
In general, for a polynomial of degree
&amp;lt;semantics&amp;gt;n&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;n&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;,
the above implementation of &lt;code class=&quot;sourceCode haskell&quot;&gt;eval&lt;/code&gt;
will perform
&amp;lt;semantics&amp;gt;ğ�’ª(n2)&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;\mathcal{O}(n^2)&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;
multiplications.&lt;/p&gt;
&lt;p&gt;There is, however, a trick that can bring the number of
multiplications down to
&amp;lt;semantics&amp;gt;ğ�’ª(n)&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;\mathcal{O}(n)&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;:
Hornerâ€™s rule. The basic idea is to rewrite the expanded polynomial
&amp;lt;semantics&amp;gt;4+2x+5x2âˆ’x3&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;4 + 2x + 5x^2 - x^3&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;
into a factorised form:
&amp;lt;semantics&amp;gt;4+x(2+x(5+x(âˆ’1)))&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;4 + x(2 + x(5 + x(-1)))&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;.
If we evaluate &lt;em&gt;this&lt;/em&gt; 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 &lt;span class=&quot;citation&quot;&gt;(&lt;a href=&quot;https://doisinkidney.com/rss.xml#ref-gibbons_horners_2011&quot;&gt;Gibbons
2011&lt;/a&gt;)&lt;/span&gt;. Indeed, the representation I develop in this post is
basically a data structure encoding of Hornerâ€™s rule.&lt;/p&gt;
&lt;p&gt;Before getting there, however, letâ€™s return to our list-based
polynomial, and look at using Hornerâ€™s rule to implement &lt;code class=&quot;sourceCode haskell&quot;&gt;eval&lt;/code&gt;. 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.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb10&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb10-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb10-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;eval ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Polynomial&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rational&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rational&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb10-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;eval xs x &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;foldr&lt;/span&gt; (\a p &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; a &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; x &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; p) &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; xs&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;multiple-variables&quot;&gt;Multiple Variables&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb11&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb11-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb11-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TwoVar&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;Polynomial&lt;/span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To save us having to write a separate &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt;&lt;/code&gt; instance
for &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;TwoVar&lt;/span&gt;&lt;/code&gt;, we can
instead generalise the &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt;&lt;/code&gt; instance
on &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;Polynomial&lt;/span&gt;&lt;/code&gt;
above:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb12&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb12-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb12-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt; [a] &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The rest of the instance is the same. Now, we can write &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;^&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Polynomial&lt;/span&gt;&lt;/code&gt;
or &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dv&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TwoVar&lt;/span&gt;&lt;/code&gt;
and it will just work.&lt;/p&gt;
&lt;p&gt;We also have to generalise the type of &lt;code class=&quot;sourceCode haskell&quot;&gt;eval&lt;/code&gt; slightly:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb13&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb13-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb13-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;eval ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; [a] &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; a&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;but again, the implementation remains the same.&lt;/p&gt;
&lt;p&gt;With this machinery, we can now write and evaluate polynomials in 2
variables:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb14&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb14-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb14-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;eval2 ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TwoVar&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rational&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rational&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rational&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb14-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;eval2 p x y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; eval (eval p [x]) y&lt;/span&gt;
&lt;span id=&quot;cb14-3&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb14-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-4&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb14-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;var ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; [a]&lt;/span&gt;
&lt;span id=&quot;cb14-5&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb14-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;var &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; [&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb14-6&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb14-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-7&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb14-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;x &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; var&lt;/span&gt;
&lt;span id=&quot;cb14-8&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb14-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; [var]&lt;/span&gt;
&lt;span id=&quot;cb14-9&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb14-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-10&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb14-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;poly &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; x &lt;span class=&quot;op&quot;&gt;^&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;-&lt;/span&gt; y &lt;span class=&quot;op&quot;&gt;^&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-11&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb14-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-12&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb14-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; poly&lt;/span&gt;
&lt;span id=&quot;cb14-13&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb14-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;[[&lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;,&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;],[&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;],[&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;]]&lt;/span&gt;
&lt;span id=&quot;cb14-14&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb14-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-15&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb14-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; eval2 poly &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-16&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb14-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;15&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can even use some typeclass shenanigans to build a generalised
evaluator that works with any fixed number of variables.&lt;/p&gt;
&lt;details&gt;

Implementation of an Evaluator for Polynomials in Arbitrary Variables

&lt;div class=&quot;sourceCode&quot; id=&quot;cb15&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb15-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb15-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt; n &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt; (e &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; n) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb15-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb15-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;fromInteger&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fromInteger&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb15-3&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb15-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  (f &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; g) x &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; f x &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; g x&lt;/span&gt;
&lt;span id=&quot;cb15-4&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb15-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  (f &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; g) x &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; f x &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; g x&lt;/span&gt;
&lt;span id=&quot;cb15-5&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb15-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb15-6&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb15-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;abs&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; (&lt;span class=&quot;fu&quot;&gt;abs&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb15-7&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb15-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;signum&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; (&lt;span class=&quot;fu&quot;&gt;signum&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb15-8&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb15-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;negate&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; (&lt;span class=&quot;fu&quot;&gt;negate&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb15-9&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb15-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb15-10&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb15-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt; r &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; p r &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; p &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; r, r &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; p &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb15-11&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb15-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;  evalN ::&lt;/span&gt; p &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; r&lt;/span&gt;
&lt;span id=&quot;cb15-12&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb15-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb15-13&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb15-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Integer&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Integer&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb15-14&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb15-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  evalN &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;id&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb15-15&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb15-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb15-16&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb15-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; p r &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; [p] (&lt;span class=&quot;dt&quot;&gt;Integer&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; r) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb15-17&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb15-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  evalN xs x &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;foldr&lt;/span&gt; (\a s &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; evalN a &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fromInteger&lt;/span&gt; x &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; s) &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; xs&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/details&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb16&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb16-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb16-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; evalN poly &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb16-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;15&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-3&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb16-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-4&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb16-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; [[var]]&lt;/span&gt;
&lt;span id=&quot;cb16-5&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb16-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-6&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb16-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; evalN (poly &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; z) &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-7&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb16-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;14&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;sums-of-products&quot;&gt;Sums of Products&lt;/h2&gt;
&lt;p&gt;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:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb17&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb17-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb17-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;newtype&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; {&lt;span class=&quot;ot&quot;&gt; terms ::&lt;/span&gt; [([v], c)] }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here, a value of type &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c&lt;/code&gt; is a
polynomial with coefficients drawn from &lt;code class=&quot;sourceCode haskell&quot;&gt;c&lt;/code&gt; and variables from &lt;code class=&quot;sourceCode haskell&quot;&gt;v&lt;/code&gt;. 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.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb18&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb18-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb18-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Var&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Z&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb18-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb18-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb18-3&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb18-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;poly ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Var&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Integer&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb18-4&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb18-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;poly &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; [([&lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;,&lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;,&lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;],&lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;),([&lt;span class=&quot;dt&quot;&gt;Z&lt;/span&gt;],&lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;),([&lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;,&lt;span class=&quot;dt&quot;&gt;Z&lt;/span&gt;],&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;)]&lt;/span&gt;
&lt;span id=&quot;cb18-5&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb18-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- 5xyÂ² + 3z + 2yz&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note that this representation requires some normalisation:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb19&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb19-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb19-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;norm ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Ord&lt;/span&gt; v, &lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt; c, &lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt; c) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; [([v],c)] &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; [([v],c)]&lt;/span&gt;
&lt;span id=&quot;cb19-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb19-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;norm &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; Map.toList &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; Map.fromListWith (&lt;span class=&quot;op&quot;&gt;+&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;filter&lt;/span&gt; ((&lt;span class=&quot;op&quot;&gt;/=&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;)&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;snd&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb19-3&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb19-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-4&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb19-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt; c, &lt;span class=&quot;dt&quot;&gt;Ord&lt;/span&gt; v, &lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt; c) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-5&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb19-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  (&lt;span class=&quot;op&quot;&gt;==&lt;/span&gt;) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; (&lt;span class=&quot;op&quot;&gt;==&lt;/span&gt;) &lt;span class=&quot;ot&quot;&gt;`on`&lt;/span&gt; norm &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; terms&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And we have the following &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt;&lt;/code&gt;
instance:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb20&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb20-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb20-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt; c &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb20-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;fromInteger&lt;/span&gt; n &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; [([],&lt;span class=&quot;fu&quot;&gt;fromInteger&lt;/span&gt; n)]&lt;/span&gt;
&lt;span id=&quot;cb20-3&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb20-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; xs &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; ys &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; (xs &lt;span class=&quot;op&quot;&gt;++&lt;/span&gt; ys)&lt;/span&gt;
&lt;span id=&quot;cb20-4&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb20-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  xs &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; ys &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; [ (xv &lt;span class=&quot;op&quot;&gt;++&lt;/span&gt; yv, xc &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; yc) &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; (xv,xc) &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; terms xs, (yv,yc) &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; terms ys ]&lt;/span&gt;
&lt;span id=&quot;cb20-5&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb20-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;negate&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;map&lt;/span&gt; (&lt;span class=&quot;fu&quot;&gt;fmap&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;negate&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; terms&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;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
&amp;lt;semantics&amp;gt;2xy+y2âˆ’3&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;2xy + y^2 - 3&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;
corresponds to the value &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; [([&lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;,&lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;],&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;),([&lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;,&lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;],&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;),([],&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;)]&lt;/code&gt;.
The previous representation (&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;TwoVar&lt;/span&gt;&lt;/code&gt;) would
represent the same expression as the enigmatic &lt;code class=&quot;sourceCode haskell&quot;&gt;[[&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;],[&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;]]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;However, there are some wrinkles to this type that are worth noting.
First we can see that multiplication is &lt;em&gt;not&lt;/em&gt; commutative (even
after normalisation).&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb21&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb21-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb21-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;x &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; [([&lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;],&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;)]&lt;/span&gt;
&lt;span id=&quot;cb21-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb21-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; [([&lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;],&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;)]&lt;/span&gt;
&lt;span id=&quot;cb21-3&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb21-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-4&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb21-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;x &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; y &lt;span class=&quot;op&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; [([&lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;,&lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;],&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;)]&lt;/span&gt;
&lt;span id=&quot;cb21-5&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb21-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;y &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; x &lt;span class=&quot;op&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; [([&lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;,&lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;],&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;)]&lt;/span&gt;
&lt;span id=&quot;cb21-6&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb21-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;x &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; y &lt;span class=&quot;op&quot;&gt;/=&lt;/span&gt; y &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; x&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is in contrast to &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;TwoVar&lt;/span&gt;&lt;/code&gt;, where
both
&amp;lt;semantics&amp;gt;xy&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;xy&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;
and
&amp;lt;semantics&amp;gt;yx&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;yx&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;
would be represented as &lt;code class=&quot;sourceCode haskell&quot;&gt;[[&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;],[&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;]]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Conceptually, polynomials are a kind of &lt;em&gt;free&lt;/em&gt; structure: they
represent the normalised and quotiented syntax of an algebraic theory.
The fact that &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt;&lt;/code&gt; above
doesnâ€™t have commutative multiplication just tells us that the
underlying algebraic theory in question here is &lt;em&gt;non&lt;/em&gt;commutative
rings, rather than commutative rings.&lt;/p&gt;
&lt;p&gt;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 &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt;&lt;/code&gt; to blow
up:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb22&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb22-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb22-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;poly &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; (&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; x) &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; (&lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; (y &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb22-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb22-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb22-3&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb22-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; terms poly&lt;/span&gt;
&lt;span id=&quot;cb22-4&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb22-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;[([&lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;],&lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;),([],&lt;span class=&quot;dv&quot;&gt;6&lt;/span&gt;),([&lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;],&lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;),([],&lt;span class=&quot;dv&quot;&gt;8&lt;/span&gt;),([&lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;,&lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;],&lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;),([&lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;],&lt;span class=&quot;dv&quot;&gt;6&lt;/span&gt;),([&lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;,&lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;],&lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;),([&lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;],&lt;span class=&quot;dv&quot;&gt;8&lt;/span&gt;)]&lt;/span&gt;
&lt;span id=&quot;cb22-5&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb22-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb22-6&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb22-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; norm (terms poly)&lt;/span&gt;
&lt;span id=&quot;cb22-7&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb22-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;[([],&lt;span class=&quot;dv&quot;&gt;14&lt;/span&gt;),([&lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;],&lt;span class=&quot;dv&quot;&gt;14&lt;/span&gt;),([&lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;,&lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;],&lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;),([&lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;],&lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;)]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And indeed it does, as you can see above. To counteract this, we can
represent our polynomial as a &lt;em&gt;mapping&lt;/em&gt; from monics (strings of
variables) to coefficients:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb23&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb23-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb23-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;newtype&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; {&lt;span class=&quot;ot&quot;&gt; terms ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt; [v] c }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;details&gt;

&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt;&lt;/code&gt;
instance for &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt;&lt;/code&gt;-based
polynomial

&lt;div class=&quot;sourceCode&quot; id=&quot;cb24&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb24-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb24-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Ord&lt;/span&gt; v, &lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt; c) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb24-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;fromInteger&lt;/span&gt; n &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; (Map.singleton [] (&lt;span class=&quot;fu&quot;&gt;fromInteger&lt;/span&gt; n))&lt;/span&gt;
&lt;span id=&quot;cb24-3&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb24-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; xs &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; ys &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; (Map.unionWith (&lt;span class=&quot;op&quot;&gt;+&lt;/span&gt;) xs ys)&lt;/span&gt;
&lt;span id=&quot;cb24-4&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb24-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  xs &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; ys &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; (Map.fromListWith (&lt;span class=&quot;op&quot;&gt;+&lt;/span&gt;) [ (xv &lt;span class=&quot;op&quot;&gt;++&lt;/span&gt; yv, xc &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; yc)&lt;/span&gt;
&lt;span id=&quot;cb24-5&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb24-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                                       &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; (xv,xc) &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; Map.toList (terms xs)&lt;/span&gt;
&lt;span id=&quot;cb24-6&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb24-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                                       , (yv,yc) &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; Map.toList (terms ys) ])&lt;/span&gt;
&lt;span id=&quot;cb24-7&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb24-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;negate&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fmap&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;negate&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; terms&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/details&gt;
&lt;p&gt;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 &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt;&lt;/code&gt; 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.&lt;/p&gt;
&lt;p&gt;This also brings the second observation about inefficiency into
focus: we have lost our neat evaluation with Hornerâ€™s rule.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb25&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb25-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb25-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;eval ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt; c &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; (v &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; c) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; c&lt;/span&gt;
&lt;span id=&quot;cb25-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb25-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;eval (&lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; mp) v &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; Map.foldrWithKey (\vs c s &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;foldr&lt;/span&gt; ((&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; v) c vs &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; s) &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; mp&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Weâ€™re back to performing
&amp;lt;semantics&amp;gt;n&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;n&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;
multiplications per term.&lt;/p&gt;
&lt;p&gt;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 &lt;em&gt;trie&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&quot;a-trie&quot;&gt;A Trie&lt;/h2&gt;
&lt;p&gt;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
&amp;lt;semantics&amp;gt;(2+3xâˆ’5y)2&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;(2 + 3x - 5y) ^ 2&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;,
and multiply it out to
&amp;lt;semantics&amp;gt;4+12x+9x2âˆ’15xyâˆ’20yâˆ’15yx+25y2&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;4 + 12x + 9x^2 - 15xy - 20y - 15yx + 25y^2&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;.
We can still factor this expression to remove common prefixes, like
so:&lt;/p&gt;
&lt;p&gt;&amp;lt;semantics&amp;gt;4+x(12+9xâˆ’15y)+y(âˆ’20âˆ’15x+25y)&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;4 + x(12 + 9x - 15y) + y(-20 - 15x + 25y)&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;&lt;/p&gt;
&lt;p&gt;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 &lt;em&gt;list&lt;/em&gt; has a single tail in
the cons case,&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb26&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb26-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb26-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;List&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nil&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb26-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb26-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Cons&lt;/span&gt; a (&lt;span class=&quot;dt&quot;&gt;List&lt;/span&gt; a)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The multivariate version of the same thing will be a
&lt;em&gt;tree&lt;/em&gt;&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb27&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb27-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb27-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Tree&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nil&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb27-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb27-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Cons&lt;/span&gt; a [&lt;span class=&quot;dt&quot;&gt;Tree&lt;/span&gt; a]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Or, more specifically, a &lt;em&gt;trie&lt;/em&gt;, where the subtree mapping is
based on variables.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb28&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb28-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb28-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; c &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt; v (&lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A polynomial is a constant coefficient &lt;code class=&quot;sourceCode haskell&quot;&gt;c&lt;/code&gt; plus the sum of variables drawn from
&lt;code class=&quot;sourceCode haskell&quot;&gt;v&lt;/code&gt; each multiplied by another
polynomial. The polynomial above is represented with this type as the
following:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb29&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb29-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb29-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; {(&lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;12&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; {(&lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;9&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; {}),(&lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;,(&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;15&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; {})}),(&lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;,(&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;20&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; {(&lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;,(&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;15&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; {}),(&lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;,&lt;span class=&quot;dv&quot;&gt;25&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; {})})}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h2 id=&quot;the-numeric-functions-on-tries&quot;&gt;The numeric functions on
Tries&lt;/h2&gt;
&lt;p&gt;Letâ€™s first write evaluation:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb30&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb30-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb30-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;eval ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt; c &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; (v &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; c) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; c&lt;/span&gt;
&lt;span id=&quot;cb30-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb30-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;eval f (c &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; vs) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; c &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; Map.foldrWithKey (\v p s &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; f v &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; eval f p &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; s) &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; vs&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;(for those concerned with performance, it might be worth swapping out
&lt;code class=&quot;sourceCode haskell&quot;&gt;foldrWithKey&lt;/code&gt; with a strict
variant. (also, this is somewhat unrelated but a bit of a pet peeve of
mine: this is &lt;em&gt;not&lt;/em&gt; a place where &lt;code class=&quot;sourceCode haskell&quot;&gt;foldl'&lt;/code&gt; is the best option! &lt;code class=&quot;sourceCode haskell&quot;&gt;foldl'&lt;/code&gt; is not a panacea!))&lt;/p&gt;
&lt;p&gt;The numeric operations on this data structure can be implemented as
follows:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb31&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb31-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb31-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Functor&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v)&lt;/span&gt;
&lt;span id=&quot;cb31-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb31-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb31-3&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb31-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Ord&lt;/span&gt; v, &lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt; c, &lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt; c) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb31-4&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb31-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;fromInteger&lt;/span&gt; n &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fromInteger&lt;/span&gt; n &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; Map.empty&lt;/span&gt;
&lt;span id=&quot;cb31-5&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb31-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  (n &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; ns) &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; (m &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; ms) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; (n &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; m) &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; Map.unionWith (&lt;span class=&quot;op&quot;&gt;+&lt;/span&gt;) ns ms&lt;/span&gt;
&lt;span id=&quot;cb31-6&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb31-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  (n &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; ns) &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; ms &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fmap&lt;/span&gt; (n&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt;) ms &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; (&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fmap&lt;/span&gt; (&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt;ms) ns)&lt;/span&gt;
&lt;span id=&quot;cb31-7&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb31-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;negate&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fmap&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;negate&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;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 &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;Data.Map&lt;/span&gt;&lt;/code&gt;â€™s
efficient &lt;code class=&quot;sourceCode haskell&quot;&gt;unionWith&lt;/code&gt; on single
variables; and multiplication doesnâ€™t have to expand out any Cartesian
product.&lt;/p&gt;
&lt;p&gt;I will note that we do have to perform a little bit of normalisation
for the derived &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt;&lt;/code&gt; 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
&amp;lt;semantics&amp;gt;x(2+y)+y(0)&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;x(2 + y) + y(0)&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;
should be pruned to
&amp;lt;semantics&amp;gt;x(2+y)&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;x(2 + y)&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;).
This can be done without really changing the efficiency of the
operations above, but it does make them slightly more verbose.&lt;/p&gt;
&lt;details&gt;

Normalising &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt;&lt;/code&gt; instance

&lt;p&gt;For this version, we will rely on the extremely efficient &lt;a href=&quot;https://hackage.haskell.org/package/containers-0.8/docs/Data-Map-Merge-Strict.html&quot;&gt;custom
merge operations in containers&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb32&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb32-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb32-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;+?&lt;/span&gt; ns &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; Map.null ns &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb32-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;n &lt;span class=&quot;op&quot;&gt;&amp;lt;+?&lt;/span&gt; ns &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; (n &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; ns)&lt;/span&gt;
&lt;span id=&quot;cb32-3&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb32-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-4&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb32-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Ord&lt;/span&gt; v, &lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt; c, &lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt; c) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-5&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb32-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;fromInteger&lt;/span&gt; n &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fromInteger&lt;/span&gt; n &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; Map.empty&lt;/span&gt;
&lt;span id=&quot;cb32-6&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb32-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-7&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb32-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  a &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; fromMaybe &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; (add a b)&lt;/span&gt;
&lt;span id=&quot;cb32-8&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb32-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-9&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb32-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      add (n &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; ns) (m &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; ms) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-10&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb32-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        (n &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; m) &lt;span class=&quot;op&quot;&gt;&amp;lt;+?&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-11&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb32-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          Map.merge&lt;/span&gt;
&lt;span id=&quot;cb32-12&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb32-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            Map.preserveMissing&lt;/span&gt;
&lt;span id=&quot;cb32-13&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb32-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            Map.preserveMissing&lt;/span&gt;
&lt;span id=&quot;cb32-14&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb32-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            (Map.zipWithMaybeMatched (&lt;span class=&quot;fu&quot;&gt;const&lt;/span&gt; add))&lt;/span&gt;
&lt;span id=&quot;cb32-15&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb32-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            ns ms&lt;/span&gt;
&lt;span id=&quot;cb32-16&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb32-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-17&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb32-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  _ &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; (&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; ms) &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; Map.null ms &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; Map.empty&lt;/span&gt;
&lt;span id=&quot;cb32-18&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb32-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  (&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; ns) &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; ms &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fmap&lt;/span&gt; (&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt;ms) ns&lt;/span&gt;
&lt;span id=&quot;cb32-19&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb32-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  (n &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; ns) &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; ms &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fmap&lt;/span&gt; (n&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt;) ms &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; (&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fmap&lt;/span&gt; (&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt;ms) ns)&lt;/span&gt;
&lt;span id=&quot;cb32-20&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb32-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-21&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb32-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-22&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb32-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;negate&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fmap&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;negate&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-23&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb32-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;abs&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fmap&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;abs&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-24&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb32-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;signum&lt;/span&gt; (n &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; _) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;signum&lt;/span&gt; n &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; Map.empty&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/details&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb33&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb33-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb33-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Var&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Ord&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Show&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb33-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb33-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-3&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb33-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;var ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt; c &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; v &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c&lt;/span&gt;
&lt;span id=&quot;cb33-4&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb33-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;var v &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; Map.singleton v (&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; Map.empty)&lt;/span&gt;
&lt;span id=&quot;cb33-5&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb33-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-6&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb33-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;x,&lt;span class=&quot;ot&quot;&gt;y ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Var&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Integer&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-7&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb33-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;x &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; var &lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-8&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb33-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; var &lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-9&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb33-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-10&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb33-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;poly &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; (&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; x &lt;span class=&quot;op&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; y) &lt;span class=&quot;op&quot;&gt;^&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-11&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb33-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; poly&lt;/span&gt;
&lt;span id=&quot;cb33-12&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb33-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt;(&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;20&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;25&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt;(&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;15&lt;/span&gt;)) &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt;(&lt;span class=&quot;dv&quot;&gt;12&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt;(&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;15&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;9&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;lenses-and-division&quot;&gt;Lenses and Division&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=cefnmjtAolY&quot;&gt;Lenses&lt;/a&gt; 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 (&lt;a href=&quot;https://gist.github.com/oisdk/0306b5849207e1e03fc23d79148d4c3d&quot;&gt;gist
link&lt;/a&gt;).&lt;/p&gt;
&lt;details&gt;

Tweet Trie

&lt;div class=&quot;sourceCode&quot; id=&quot;cb34&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb34-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb34-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE RankNTypes #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb34-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-3&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb34-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Control.Comonad.Cofree&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-4&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb34-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Control.Lens&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;hiding&lt;/span&gt; ((:&amp;lt;))&lt;/span&gt;
&lt;span id=&quot;cb34-5&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb34-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;qualified&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Data.Map&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-6&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb34-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Data.Map&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb34-7&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb34-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Prelude&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;hiding&lt;/span&gt; (lookup)&lt;/span&gt;
&lt;span id=&quot;cb34-8&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb34-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Data.Maybe&lt;/span&gt; (isJust)&lt;/span&gt;
&lt;span id=&quot;cb34-9&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb34-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Test.QuickCheck&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-10&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb34-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-11&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb34-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Trie&lt;/span&gt; a b &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Cofree&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt; a) (&lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; b)&lt;/span&gt;
&lt;span id=&quot;cb34-12&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb34-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-13&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb34-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;string ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ord&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; [a] &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Lens'&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Trie&lt;/span&gt; a b) (&lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; b)&lt;/span&gt;
&lt;span id=&quot;cb34-14&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb34-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;string &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-15&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb34-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; &lt;span class=&quot;fu&quot;&gt;foldr&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-16&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb34-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   (\x r &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; _unwrap &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; at x &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; anon (&lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;lt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;mempty&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb34-17&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb34-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                                  (\(v &lt;span class=&quot;op&quot;&gt;:&amp;lt;&lt;/span&gt; m) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;null&lt;/span&gt; v &lt;span class=&quot;op&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;null&lt;/span&gt; m) &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; r)&lt;/span&gt;
&lt;span id=&quot;cb34-18&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb34-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;   _extract&lt;/span&gt;
&lt;span id=&quot;cb34-19&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb34-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-20&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb34-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-21&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb34-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;insert ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ord&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; [a] &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Trie&lt;/span&gt; a b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Trie&lt;/span&gt; a b&lt;/span&gt;
&lt;span id=&quot;cb34-22&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb34-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;insert xs x &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; string xs &lt;span class=&quot;op&quot;&gt;.~&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; x&lt;/span&gt;
&lt;span id=&quot;cb34-23&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb34-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-24&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb34-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;lookup&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ord&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; [a] &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Trie&lt;/span&gt; a b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; b&lt;/span&gt;
&lt;span id=&quot;cb34-25&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb34-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;lookup&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; view &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; string&lt;/span&gt;
&lt;span id=&quot;cb34-26&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb34-26&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-27&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb34-27&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;delete ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ord&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; [a] &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Trie&lt;/span&gt; a b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Trie&lt;/span&gt; a b&lt;/span&gt;
&lt;span id=&quot;cb34-28&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb34-28&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;delete xs &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; string xs &lt;span class=&quot;op&quot;&gt;.~&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/details&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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
&amp;lt;semantics&amp;gt;2x2+y&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;2x^2 + y&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;?&lt;/p&gt;
&lt;p&gt;It turns out that lookups corresponds to &lt;em&gt;division&lt;/em&gt;. For
example, dividing the polynomial
&amp;lt;semantics&amp;gt;2x2+y&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;2x^2 + y&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;
by the monic
&amp;lt;semantics&amp;gt;xx&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;xx&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;
gives us a quotient
&amp;lt;semantics&amp;gt;2&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;2&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;
and remainder
&amp;lt;semantics&amp;gt;y&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;y&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb35&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb35-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb35-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;divMod&lt;/span&gt; (&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; x &lt;span class=&quot;op&quot;&gt;^&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; y) [&lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;,&lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb35-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb35-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;(&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;, y)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;But thatâ€™s a little vague. Letâ€™s construct the actual lenses here, in
the van Laarhoven style:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb36&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb36-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb36-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;constant ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Lens'&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c) c&lt;/span&gt;
&lt;span id=&quot;cb36-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb36-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;constant f (c &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; vs) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fmap&lt;/span&gt; (&lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; vs) (f c)&lt;/span&gt;
&lt;span id=&quot;cb36-3&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb36-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb36-4&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb36-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;vars ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Lens&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c) (&lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v' c) (&lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt; v (&lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c)) (&lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt; v' (&lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v' c))&lt;/span&gt;
&lt;span id=&quot;cb36-5&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb36-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;vars f (c &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; vs) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fmap&lt;/span&gt; (c &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt;) (f vs)&lt;/span&gt;
&lt;span id=&quot;cb36-6&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb36-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb36-7&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb36-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;isZero ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt; c, &lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt; c) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Bool&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb36-8&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb36-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;isZero (n &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; ns) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; (&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;==&lt;/span&gt; n) &lt;span class=&quot;op&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; Map.null ns&lt;/span&gt;
&lt;span id=&quot;cb36-9&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb36-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb36-10&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb36-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;factored ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Ord&lt;/span&gt; v, &lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt; c, &lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt; c) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; [v] &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Lens'&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c) (&lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c)&lt;/span&gt;
&lt;span id=&quot;cb36-11&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb36-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;factored &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;foldr&lt;/span&gt; (\v vs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; vars &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; at v &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; anon &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; isZero &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; vs) &lt;span class=&quot;fu&quot;&gt;id&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This last lens does indeed give us an interface that looks like
division:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb37&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb37-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb37-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; view (factored [&lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;,&lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;]) (&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt;x&lt;span class=&quot;op&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; y)&lt;/span&gt;
&lt;span id=&quot;cb37-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb37-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb37-3&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb37-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb37-4&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb37-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; set (factored [&lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;,&lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;]) &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; (&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt;x&lt;span class=&quot;op&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; y)&lt;/span&gt;
&lt;span id=&quot;cb37-5&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb37-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If we want to define an actual division function, we can define it in
terms of &lt;code class=&quot;sourceCode haskell&quot;&gt;factored&lt;/code&gt;, in a fun
example of the kind of golfy code that lens enables.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb38&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb38-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb38-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;divMod&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Ord&lt;/span&gt; v, &lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt; c, &lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt; c) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; [v] &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c,&lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c)&lt;/span&gt;
&lt;span id=&quot;cb38-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb38-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;divMod&lt;/span&gt; p vs &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; factored vs (,&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;) p&lt;/span&gt;
&lt;span id=&quot;cb38-3&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb38-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb38-4&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb38-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt;x&lt;span class=&quot;op&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; y) &lt;span class=&quot;ot&quot;&gt;`divMod`&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;,&lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb38-5&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb38-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;(&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;,&lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;grÃ¶bner-bases&quot;&gt;GrÃ¶bner Bases&lt;/h2&gt;
&lt;p&gt;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 &lt;span class=&quot;citation&quot;&gt;Sturmfels (&lt;a href=&quot;https://doisinkidney.com/rss.xml#ref-sturmfels_what_2005&quot;&gt;2005&lt;/a&gt;)&lt;/span&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A GrÃ¶bner basis is a set of multivariate polynomials that has
desirable algorithmic properties&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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 &lt;em&gt;non&lt;/em&gt;commutative, and the literature on computing
GrÃ¶bner bases for noncommutative rings is comparatively smaller. I have
been following Xiuâ€™s thesis &lt;span class=&quot;citation&quot;&gt;(&lt;a href=&quot;https://doisinkidney.com/rss.xml#ref-xiu_noncommutative_2012&quot;&gt;2012&lt;/a&gt;)&lt;/span&gt; for this project. It outlines a
noncommutative version of Buchbergerâ€™s algorithm, and a few
optimisations that I was able to implement.&lt;/p&gt;
&lt;p&gt;One slightly annoying aspect of these algorithms is that they tend to
use &lt;em&gt;monomials&lt;/em&gt; 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.&lt;/p&gt;
&lt;h2 id=&quot;monomial-orderings&quot;&gt;Monomial Orderings&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;&amp;lt;semantics&amp;gt;a&amp;lt;bâŸ¹aâ€¢c&amp;lt;bâ€¢c&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;a &amp;lt; b \implies a \bullet c &amp;lt; b \bullet c&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;semantics&amp;gt;a&amp;lt;bâŸ¹câ€¢a&amp;lt;câ€¢b&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;a &amp;lt; b \implies c \bullet a &amp;lt; c \bullet b&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;&lt;/p&gt;
&lt;p&gt;These constraints rule out the usual lexicographic ordering on
strings. Instead, weâ€™ll go with &lt;em&gt;graded&lt;/em&gt; 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.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb39&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb39-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb39-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;grlex ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ord&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; [a] &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; [a] &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ordering&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb39-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb39-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;grlex xs ys&lt;/span&gt;
&lt;span id=&quot;cb39-3&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb39-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;length&lt;/span&gt; xs &lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;length&lt;/span&gt; ys &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;LT&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb39-4&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb39-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;length&lt;/span&gt; xs &lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;length&lt;/span&gt; ys &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;GT&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb39-5&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb39-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;otherwise&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;compare&lt;/span&gt; xs ys&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can improve the efficiency of the above function somewhat by using
one of my favourite monoids: the monoid instance on &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;Ordering&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb40&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb40-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb40-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;grlex ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ord&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; [a] &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; [a] &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ordering&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb40-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb40-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;grlex &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; go &lt;span class=&quot;dt&quot;&gt;EQ&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb40-3&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb40-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb40-4&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb40-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    go &lt;span class=&quot;op&quot;&gt;!&lt;/span&gt;a []     []     &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; a&lt;/span&gt;
&lt;span id=&quot;cb40-5&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb40-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    go &lt;span class=&quot;op&quot;&gt;!&lt;/span&gt;a []     (_&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;_)  &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;LT&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb40-6&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb40-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    go &lt;span class=&quot;op&quot;&gt;!&lt;/span&gt;a (_&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;_)  []     &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;GT&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb40-7&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb40-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    go &lt;span class=&quot;op&quot;&gt;!&lt;/span&gt;a (x&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;xs) (y&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;ys) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; go (a &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;compare&lt;/span&gt; x y) xs ys&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;Another admissible order we could use is &lt;em&gt;reverse&lt;/em&gt; grlex,
which basically amounts to reversing the lists before the comparison.
The trie structure means that weâ€™re basically forced to use &lt;code class=&quot;sourceCode haskell&quot;&gt;grlex&lt;/code&gt;, but I will include an
implementation of &lt;code class=&quot;sourceCode haskell&quot;&gt;grevlex&lt;/code&gt; here
because I think itâ€™s cute.&lt;/p&gt;
&lt;details&gt;

Implementations of &lt;code class=&quot;sourceCode haskell&quot;&gt;grevlex&lt;/code&gt;

&lt;div class=&quot;sourceCode&quot; id=&quot;cb41&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb41-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb41-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;grevlex ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ord&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; [a] &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; [a] &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ordering&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb41-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb41-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;grevlex []     []     &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EQ&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb41-3&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb41-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;grevlex (_&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;_)  []     &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;GT&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb41-4&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb41-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;grevlex []     (_&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;_)  &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;LT&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb41-5&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb41-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;grevlex (x&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;xs) (y&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;ys) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; grevlex xs ys &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;compare&lt;/span&gt; x y&lt;/span&gt;
&lt;span id=&quot;cb41-6&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb41-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb41-7&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb41-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- This version is tail-recursive, but it also might unnecessarily compare&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb41-8&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb41-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- elements. However, that should be cheaper than building up the list of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb41-9&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb41-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- comparisons.&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb41-10&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb41-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;grevlex ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ord&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; [a] &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; [a] &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ordering&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb41-11&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb41-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;grevlex &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; go &lt;span class=&quot;dt&quot;&gt;EQ&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb41-12&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb41-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb41-13&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb41-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    go &lt;span class=&quot;op&quot;&gt;!&lt;/span&gt;a []     []     &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; a&lt;/span&gt;
&lt;span id=&quot;cb41-14&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb41-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    go &lt;span class=&quot;op&quot;&gt;!&lt;/span&gt;a (_&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;_)  []     &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;GT&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb41-15&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb41-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    go &lt;span class=&quot;op&quot;&gt;!&lt;/span&gt;a []     (_&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;_)  &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;LT&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb41-16&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb41-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    go &lt;span class=&quot;op&quot;&gt;!&lt;/span&gt;a (x&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;xs) (y&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;ys) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; go (&lt;span class=&quot;fu&quot;&gt;compare&lt;/span&gt; x y &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; a) xs ys&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/details&gt;
&lt;h2 id=&quot;enumerating-monomials&quot;&gt;Enumerating Monomials&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;To demonstrate the problem, letâ€™s take a look at an algorithm that
enumerates the monomials of a polynomial in lexicographic order:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb42&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb42-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb42-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;monos ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt; c, &lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt; c) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; [([v],c)]&lt;/span&gt;
&lt;span id=&quot;cb42-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb42-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;monos p &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; search [] p []&lt;/span&gt;
&lt;span id=&quot;cb42-3&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb42-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb42-4&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb42-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    cons vs &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; ms &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ms&lt;/span&gt;
&lt;span id=&quot;cb42-5&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb42-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    cons vs c ms &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; (&lt;span class=&quot;fu&quot;&gt;reverse&lt;/span&gt; vs,c) &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; ms&lt;/span&gt;
&lt;span id=&quot;cb42-6&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb42-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb42-7&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb42-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    search sv (n &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; ns) ms &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; cons sv n (Map.foldrWithKey (search &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; (&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;sv)) ms ns)&lt;/span&gt;
&lt;span id=&quot;cb42-8&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb42-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb42-9&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb42-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; monos ((&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt;x &lt;span class=&quot;op&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt;y) &lt;span class=&quot;op&quot;&gt;^&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb42-10&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb42-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;[([],&lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;),([&lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;],&lt;span class=&quot;dv&quot;&gt;12&lt;/span&gt;),([&lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;,&lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;],&lt;span class=&quot;dv&quot;&gt;9&lt;/span&gt;),([&lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;,&lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;],&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;15&lt;/span&gt;),([&lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;],&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;20&lt;/span&gt;),([&lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;,&lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;],&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;15&lt;/span&gt;),([&lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;,&lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;],&lt;span class=&quot;dv&quot;&gt;25&lt;/span&gt;)]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Notice that the function &lt;code class=&quot;sourceCode haskell&quot;&gt;search&lt;/code&gt; emits the monomial &lt;code class=&quot;sourceCode haskell&quot;&gt;(&lt;span class=&quot;fu&quot;&gt;reverse&lt;/span&gt; sv, n)&lt;/code&gt;
straight away (if &lt;code class=&quot;sourceCode haskell&quot;&gt;n &lt;span class=&quot;op&quot;&gt;/=&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;&lt;/code&gt;),
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 &lt;code class=&quot;sourceCode haskell&quot;&gt;ns&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;However, we canâ€™t just flip the order of consing in &lt;code class=&quot;sourceCode haskell&quot;&gt;search&lt;/code&gt;: notice that even if we
reversed the output, we still wouldnâ€™t get an admissible monomial
ordering (the singleton list &lt;code class=&quot;sourceCode haskell&quot;&gt;[&lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;]&lt;/code&gt; should be
grouped with the other singleton lists). The problem is that &lt;code class=&quot;sourceCode haskell&quot;&gt;monos&lt;/code&gt; is performing a
&lt;em&gt;depth&lt;/em&gt;-first search. What we need is &lt;em&gt;breadth&lt;/em&gt;-first.&lt;/p&gt;
&lt;p&gt;I happen to be a little &lt;a href=&quot;https://doisinkidney.com/series/Breadth-First%20Traversals.html&quot;&gt;obsessed&lt;/a&gt; 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.&lt;/p&gt;
&lt;p&gt;For this case, I started with the &lt;code class=&quot;sourceCode haskell&quot;&gt;levels&lt;/code&gt; function.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb43&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb43-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb43-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;levels ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt; c, &lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt; c) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; [[([v],c)]]&lt;/span&gt;
&lt;span id=&quot;cb43-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb43-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;levels p &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; search [] p []&lt;/span&gt;
&lt;span id=&quot;cb43-3&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb43-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb43-4&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb43-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    cons _  &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; ms &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ms&lt;/span&gt;
&lt;span id=&quot;cb43-5&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb43-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    cons vs c ms &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; (&lt;span class=&quot;fu&quot;&gt;reverse&lt;/span&gt; vs,c) &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; ms&lt;/span&gt;
&lt;span id=&quot;cb43-6&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb43-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb43-7&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb43-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    search sv (n &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; ns) []     &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; cons sv n [] &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; Map.foldrWithKey (search &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; (&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;sv)) [] ns&lt;/span&gt;
&lt;span id=&quot;cb43-8&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb43-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    search sv (n &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; ns) (q&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;qs) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; cons sv n  q &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; Map.foldrWithKey (search &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; (&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;sv)) qs ns&lt;/span&gt;
&lt;span id=&quot;cb43-9&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb43-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb43-10&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb43-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; levels ((&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt;x &lt;span class=&quot;op&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt;y) &lt;span class=&quot;op&quot;&gt;^&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb43-11&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb43-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;[[([],&lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;)],[([&lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;],&lt;span class=&quot;dv&quot;&gt;12&lt;/span&gt;),([&lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;],&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;20&lt;/span&gt;)],[([&lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;,&lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;],&lt;span class=&quot;dv&quot;&gt;9&lt;/span&gt;),([&lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;,&lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;],&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;15&lt;/span&gt;),([&lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;,&lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;],&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;15&lt;/span&gt;),([&lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;,&lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;],&lt;span class=&quot;dv&quot;&gt;25&lt;/span&gt;)]]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I have written about levels &lt;a href=&quot;https://doisinkidney.com/posts/2019-05-28-linear-phases.html&quot;&gt;before&lt;/a&gt; &lt;span class=&quot;citation&quot;&gt;(see also
&lt;a href=&quot;https://doisinkidney.com/rss.xml#ref-gibbons_breadthfirst_2015&quot;&gt;Gibbons
2015&lt;/a&gt;; &lt;a href=&quot;https://doisinkidney.com/rss.xml#ref-jones_lineartime_1993&quot;&gt;Jones and Gibbons 1993&lt;/a&gt;)&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;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
&lt;code class=&quot;sourceCode haskell&quot;&gt;sv&lt;/code&gt; thatâ€™s passed to &lt;code class=&quot;sourceCode haskell&quot;&gt;search&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;In reality, this isnâ€™t actually a flaw: we can just call &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;fu&quot;&gt;concat&lt;/span&gt;&lt;/code&gt; 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 &lt;span class=&quot;citation&quot;&gt;(&lt;a href=&quot;https://doisinkidney.com/rss.xml#ref-jones_lineartime_1993&quot;&gt;1993&lt;/a&gt;)&lt;/span&gt;, I finally arrived at the
following solution:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb44&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb44-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb44-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Knots&lt;/span&gt; a&lt;/span&gt;
&lt;span id=&quot;cb44-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb44-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Knot&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb44-3&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb44-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  {&lt;span class=&quot;ot&quot;&gt; tied ::&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;dt&quot;&gt;Bool&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb44-4&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb44-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ,&lt;span class=&quot;ot&quot;&gt; yank ::&lt;/span&gt; [a]&lt;/span&gt;
&lt;span id=&quot;cb44-5&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb44-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ,&lt;span class=&quot;ot&quot;&gt; ends ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Knots&lt;/span&gt; a }&lt;/span&gt;
&lt;span id=&quot;cb44-6&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb44-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb44-7&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb44-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;tighten ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Knots&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Knots&lt;/span&gt; a&lt;/span&gt;
&lt;span id=&quot;cb44-8&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb44-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;tighten &lt;span class=&quot;op&quot;&gt;~&lt;/span&gt;(&lt;span class=&quot;dt&quot;&gt;Knot&lt;/span&gt; t y e) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Knot&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt; (&lt;span class=&quot;kw&quot;&gt;if&lt;/span&gt; t &lt;span class=&quot;kw&quot;&gt;then&lt;/span&gt; y &lt;span class=&quot;kw&quot;&gt;else&lt;/span&gt; []) (tighten e)&lt;/span&gt;
&lt;span id=&quot;cb44-9&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb44-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb44-10&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb44-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;monos ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt; c, &lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt; c) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; [([v],c)]&lt;/span&gt;
&lt;span id=&quot;cb44-11&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb44-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;monos p &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; y&lt;/span&gt;
&lt;span id=&quot;cb44-12&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb44-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb44-13&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb44-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;Knot&lt;/span&gt; _ y e &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; tie [] p (tighten e)&lt;/span&gt;
&lt;span id=&quot;cb44-14&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb44-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    cons sv &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; ms &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ms&lt;/span&gt;
&lt;span id=&quot;cb44-15&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb44-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    cons sv c ms &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; (&lt;span class=&quot;fu&quot;&gt;reverse&lt;/span&gt; sv, c) &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; ms&lt;/span&gt;
&lt;span id=&quot;cb44-16&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb44-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    tie sv (n &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; m) (&lt;span class=&quot;dt&quot;&gt;Knot&lt;/span&gt; _ ms ps) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Knot&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; (cons sv n ms) (Map.foldrWithKey (tie &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; (&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;sv)) ps m)&lt;/span&gt;
&lt;span id=&quot;cb44-17&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb44-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb44-18&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb44-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; monos ((&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; x &lt;span class=&quot;op&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; y) &lt;span class=&quot;op&quot;&gt;^&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb44-19&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb44-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;[([],&lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;),([&lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;],&lt;span class=&quot;dv&quot;&gt;12&lt;/span&gt;),([&lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;],&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;20&lt;/span&gt;),([&lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;,&lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;],&lt;span class=&quot;dv&quot;&gt;9&lt;/span&gt;),([&lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;,&lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;],&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;15&lt;/span&gt;),([&lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;,&lt;span class=&quot;dt&quot;&gt;X&lt;/span&gt;],&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;15&lt;/span&gt;),([&lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;,&lt;span class=&quot;dt&quot;&gt;Y&lt;/span&gt;],&lt;span class=&quot;dv&quot;&gt;25&lt;/span&gt;)]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;While this does order the output according to grlex, itâ€™s ordered
from smallest to largest, which is the &lt;em&gt;reverse&lt;/em&gt; 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.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb45&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb45-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb45-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;pull ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Knots&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; [a]&lt;/span&gt;
&lt;span id=&quot;cb45-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb45-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;pull (&lt;span class=&quot;dt&quot;&gt;Knot&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; _ e) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; pull e&lt;/span&gt;
&lt;span id=&quot;cb45-3&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb45-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;pull (&lt;span class=&quot;dt&quot;&gt;Knot&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt; y _) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; y&lt;/span&gt;
&lt;span id=&quot;cb45-4&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb45-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb45-5&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb45-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;monosDesc ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt; c, &lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt; c) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; [([v],c)]&lt;/span&gt;
&lt;span id=&quot;cb45-6&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb45-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;monosDesc p &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; pull r&lt;/span&gt;
&lt;span id=&quot;cb45-7&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb45-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb45-8&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb45-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    r &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; tie [] p (&lt;span class=&quot;dt&quot;&gt;Knot&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt; [] (tighten r))&lt;/span&gt;
&lt;span id=&quot;cb45-9&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb45-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    cons sv &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; ms &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ms&lt;/span&gt;
&lt;span id=&quot;cb45-10&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb45-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    cons sv c ms &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; (&lt;span class=&quot;fu&quot;&gt;reverse&lt;/span&gt; sv, c) &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; ms&lt;/span&gt;
&lt;span id=&quot;cb45-11&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb45-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    tie sv (n &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; m) (&lt;span class=&quot;dt&quot;&gt;Knot&lt;/span&gt; _ ms ps) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Knot&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; (cons sv n ms) (Map.foldlWithKey (\a v p &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; tie (v&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;sv) p a) ps m)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;efficiently-popping-the-leading-monomial&quot;&gt;Efficiently Popping
the Leading Monomial&lt;/h2&gt;
&lt;p&gt;Unfortunately, as fun as &lt;code class=&quot;sourceCode haskell&quot;&gt;monosDesc&lt;/code&gt; 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 &lt;em&gt;all&lt;/em&gt; of the monomials of a
polynomial, usually we just want the &lt;em&gt;first&lt;/em&gt; one. And sadly,
while &lt;code class=&quot;sourceCode haskell&quot;&gt;monosDesc&lt;/code&gt; 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.&lt;/p&gt;
&lt;p&gt;The solution here will require us to use a new data structure in
place of the &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt;&lt;/code&gt; 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 &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt; v (&lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c)&lt;/code&gt;
for a &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt; v (&lt;span class=&quot;dt&quot;&gt;Word&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c)&lt;/code&gt;:
that solution would require us to walk over every entry in the map to
find the largest &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;Word&lt;/span&gt;&lt;/code&gt;. While it
would be an improvement in practical terms, it would still incur an
&amp;lt;semantics&amp;gt;ğ�’ª(widthÃ—depth)&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;\mathcal{O}(\text{width} \times \text{depth})&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;
cost to find the leading monomial.&lt;/p&gt;
&lt;p&gt;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 &lt;em&gt;priority queue&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Luckily, the combination of these two structures has been researched
before: &lt;span class=&quot;citation&quot;&gt;Hinze (&lt;a href=&quot;https://doisinkidney.com/rss.xml#ref-hinze_simple_2001&quot;&gt;2001&lt;/a&gt;)&lt;/span&gt;
wrote about â€œpriority search treesâ€�, a data structure that allows for
&amp;lt;semantics&amp;gt;ğ�’ª(log⁡n)&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;\mathcal{O}(\log n)&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;
lookup and insertion based on some ordered key, and separately allows
for a
&amp;lt;semantics&amp;gt;ğ�’ª(log⁡n)&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;\mathcal{O}(\log n)&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;
&lt;code class=&quot;sourceCode haskell&quot;&gt;popMin&lt;/code&gt; operation, based on some
separate priority. The &lt;a href=&quot;https://hackage.haskell.org/package/psqueues&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;psqueues&lt;/code&gt; package&lt;/a&gt; provides a few
implementations of this technique. The API isnâ€™t quite as extensive as,
say, &lt;a href=&quot;https://hackage.haskell.org/package/containers&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;containers&lt;/code&gt;&lt;/a&gt;, so some functions will
be slightly less efficient (we donâ€™t get a nice general &lt;code class=&quot;sourceCode haskell&quot;&gt;merge&lt;/code&gt; function, for example), but we
can basically drop in the &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;OrdPSQ&lt;/span&gt;&lt;/code&gt; as a
replacement for &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb46&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb46-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb46-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;SubTerms&lt;/span&gt; v c &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OrdPSQ&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Down&lt;/span&gt; v) (&lt;span class=&quot;dt&quot;&gt;Down&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Word&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c)&lt;/span&gt;
&lt;span id=&quot;cb46-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb46-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; c &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;SubTerms&lt;/span&gt; v c&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Iâ€™m using the &lt;a href=&quot;https://hackage.haskell.org/package/base-4.22.0.0/docs/Data-Ord.html#t:Down&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;Down&lt;/span&gt;&lt;/code&gt;
wrapper&lt;/a&gt; here because I want a &lt;em&gt;max&lt;/em&gt; heap, rather than a
min-heap. Iâ€™m using that wrapper on both the keys and priorities because
&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;OrdPSQ&lt;/span&gt;&lt;/code&gt;
breaks priority ties according to the keys, and I also want greater keys
returned first, to follow the &lt;code class=&quot;sourceCode haskell&quot;&gt;grlex&lt;/code&gt; ordering.&lt;/p&gt;
&lt;p&gt;The priority here is the &lt;em&gt;depth&lt;/em&gt; of the tree. It tells us the
length of the longest monomial contained:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb47&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb47-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb47-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;depth ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Word&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb47-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb47-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;depth (_ &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; ns) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;maybe&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; (\(_,&lt;span class=&quot;dt&quot;&gt;Down&lt;/span&gt; p,_) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;succ&lt;/span&gt; p) (Map.findMin ns)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This operation is
&amp;lt;semantics&amp;gt;ğ�’ª(1)&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;\mathcal{O}(1)&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;,
since finding the minimum entry in &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;OrdPSQ&lt;/span&gt;&lt;/code&gt; is
&amp;lt;semantics&amp;gt;ğ�’ª(1)&amp;lt;annotation encoding=&quot;application/x-tex&quot;&amp;gt;\mathcal{O}(1)&amp;lt;/annotation&amp;gt;&amp;lt;/semantics&amp;gt;.&lt;/p&gt;
&lt;p&gt;Iâ€™ll also use the following isomorphism, for the lensy things:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb48&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb48-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb48-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;entry ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt; c, &lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt; c) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Iso'&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Down&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Word&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c)) (&lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c)&lt;/span&gt;
&lt;span id=&quot;cb48-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb48-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;entry &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; iso (&lt;span class=&quot;fu&quot;&gt;maybe&lt;/span&gt; (&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; Map.empty) &lt;span class=&quot;fu&quot;&gt;snd&lt;/span&gt;) (\p &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;if&lt;/span&gt; isZero p &lt;span class=&quot;kw&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Down&lt;/span&gt; (depth p), p))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This lets us chain together lenses that index into an &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;OrdPSQ&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb49&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb49-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb49-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;factored ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Ord&lt;/span&gt; v, &lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt; c, &lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt; c) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; [v] &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Lens'&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c) (&lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c)&lt;/span&gt;
&lt;span id=&quot;cb49-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb49-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;factored &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;foldr&lt;/span&gt; (\v ls &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; vars &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; at (&lt;span class=&quot;dt&quot;&gt;Down&lt;/span&gt; v) &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; entry &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; ls) &lt;span class=&quot;fu&quot;&gt;id&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally, we can implement a function that pops the leading monomial
from a polynomial, efficiently:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb50&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb50-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb50-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;leading ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt; c, &lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt; c, &lt;span class=&quot;dt&quot;&gt;Ord&lt;/span&gt; v) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; (([v],c),&lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c)&lt;/span&gt;
&lt;span id=&quot;cb50-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb50-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;leading p &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; isZero p &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb50-3&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb50-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;leading (n &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; ns) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; (retrie (Map.alterMin step ns))&lt;/span&gt;
&lt;span id=&quot;cb50-4&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb50-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb50-5&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb50-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    retrie ((r,n'),ns') &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; (r, n' &lt;span class=&quot;op&quot;&gt;:&amp;lt;+&lt;/span&gt; ns')&lt;/span&gt;
&lt;span id=&quot;cb50-6&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb50-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb50-7&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb50-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    step &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ((([],n),&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;),&lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb50-8&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb50-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    step (&lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Down&lt;/span&gt; v, _, p)) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; (((v&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;vs,c),n), subTrie)&lt;/span&gt;
&lt;span id=&quot;cb50-9&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb50-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb50-10&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb50-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; ((vs,c),p') &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; leading p&lt;/span&gt;
&lt;span id=&quot;cb50-11&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb50-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        subTrie &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; isZero p' &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb50-12&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb50-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;otherwise&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Down&lt;/span&gt; v, &lt;span class=&quot;dt&quot;&gt;Down&lt;/span&gt; (depth p'), p')&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And it matches the earlier enumeration that we built:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb51&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb51-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb51-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;prop_leadingMonos ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Var&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Word&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Property&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb51-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb51-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;prop_leadingMonos p &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; monosDesc p &lt;span class=&quot;op&quot;&gt;===&lt;/span&gt; unfoldr leading p&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;next-steps&quot;&gt;Next Steps&lt;/h2&gt;
&lt;p&gt;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:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb52&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb52-1&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb52-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;divModPrefM ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Fractional&lt;/span&gt; c, &lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt; c, &lt;span class=&quot;dt&quot;&gt;Ord&lt;/span&gt; v) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; ([v],c) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c, &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c)&lt;/span&gt;
&lt;span id=&quot;cb52-2&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb52-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;divModPrefM p (vs, i) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; factored vs ((, &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fmap&lt;/span&gt; (&lt;span class=&quot;op&quot;&gt;/&lt;/span&gt;i)) p&lt;/span&gt;
&lt;span id=&quot;cb52-3&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb52-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-4&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb52-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;divModPref ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Fractional&lt;/span&gt; c, &lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt; c, &lt;span class=&quot;dt&quot;&gt;Ord&lt;/span&gt; v) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c, &lt;span class=&quot;dt&quot;&gt;Poly&lt;/span&gt; v c)&lt;/span&gt;
&lt;span id=&quot;cb52-5&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb52-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;divModPref num divisor &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; leading divisor &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-6&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb52-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;Divide by zero&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-7&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb52-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; (lt, rest) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; go &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; num&lt;/span&gt;
&lt;span id=&quot;cb52-8&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb52-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-9&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb52-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      go &lt;span class=&quot;op&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;quot&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;rem&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; divModPrefM &lt;span class=&quot;fu&quot;&gt;rem&lt;/span&gt; lt &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-10&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb52-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        (&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;, _) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; (&lt;span class=&quot;fu&quot;&gt;quot&lt;/span&gt;, &lt;span class=&quot;fu&quot;&gt;rem&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb52-11&quot;&gt;&lt;a href=&quot;https://doisinkidney.com/rss.xml#cb52-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        (q, rem') &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; go (&lt;span class=&quot;fu&quot;&gt;quot&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; q) (rem' &lt;span class=&quot;op&quot;&gt;-&lt;/span&gt; rest &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; q)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I feel that this doesnâ€™t make use of the benefits of the trie-based
representation. I have implemented Buchbergerâ€™s algorithm &lt;span class=&quot;citation&quot;&gt;(with most of the
improvements from &lt;a href=&quot;https://doisinkidney.com/rss.xml#ref-xiu_noncommutative_2012&quot;&gt;Xiu 2012&lt;/a&gt;)&lt;/span&gt;, but I have yet to really
research in depth what competitively fast systems do these days &lt;span class=&quot;citation&quot;&gt;(&lt;a href=&quot;https://doisinkidney.com/rss.xml#ref-heisinger_f4ncgb_2025&quot;&gt;Heisinger and
Hofstadler 2025&lt;/a&gt;; &lt;a href=&quot;https://doisinkidney.com/rss.xml#ref-cohen_gbnp_2026&quot;&gt;Cohen and Knopper 2026&lt;/a&gt;; &lt;a href=&quot;https://doisinkidney.com/rss.xml#ref-levandovskyy_letterplace_2020&quot;&gt;Levandovskyy, SchÃ¶nemann, and Zeid
2020&lt;/a&gt;)&lt;/span&gt;. 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 &lt;em&gt;not&lt;/em&gt; a good fit for Weyl algebras.&lt;/p&gt;
&lt;p&gt;I have looked a little bit at some other Haskell work on polynomials
and similar things; &lt;span class=&quot;citation&quot;&gt;Zucker (&lt;a href=&quot;https://doisinkidney.com/rss.xml#ref-zucker_division_2018&quot;&gt;2018&lt;/a&gt;)&lt;/span&gt;
implemented listed polynomials very similar to the ones I had at the
start of this post, as did &lt;span class=&quot;citation&quot;&gt;Manzyuk (&lt;a href=&quot;https://doisinkidney.com/rss.xml#ref-manzyuk_grobner_2012&quot;&gt;2012&lt;/a&gt;)&lt;/span&gt;
and &lt;span class=&quot;citation&quot;&gt;Buteau
(&lt;a href=&quot;https://doisinkidney.com/rss.xml#ref-buteau_polynomials_2013&quot;&gt;2013&lt;/a&gt;)&lt;/span&gt;. Iâ€™ve seen some bigger Haskell
packages that work with polynomials &lt;span class=&quot;citation&quot;&gt;(&lt;a href=&quot;https://doisinkidney.com/rss.xml#ref-malaquias_implementing_2007&quot;&gt;Malaquias
and Lopes 2007&lt;/a&gt;; &lt;a href=&quot;https://doisinkidney.com/rss.xml#ref-ishii_purely_2018&quot;&gt;Ishii 2018&lt;/a&gt;; &lt;a href=&quot;https://doisinkidney.com/rss.xml#ref-laurent_hspray_2024&quot;&gt;Laurent 2024&lt;/a&gt;)&lt;/span&gt;, though none seem to use a
representation similar to the trie here. I also had a look at calculi
&lt;span class=&quot;citation&quot;&gt;(&lt;a href=&quot;https://doisinkidney.com/rss.xml#ref-barton_calculi_2024&quot;&gt;Barton
2024&lt;/a&gt;)&lt;/span&gt;, 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).&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;gists&quot;&gt;Gists&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://gist.github.com/oisdk/67714b0e02259e972fa5e06071ab7c5e&quot;&gt;Listed
Polynomial with arbitrary variables&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gist.github.com/oisdk/a10b27a54a3fef6b489eb9202406387c&quot;&gt;Polynomial
Trie&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 class=&quot;unnumbered&quot; id=&quot;references&quot;&gt;References&lt;/h2&gt;
&lt;div class=&quot;references csl-bib-body hanging-indent&quot; id=&quot;refs&quot;&gt;
&lt;div class=&quot;csl-entry&quot; id=&quot;ref-barton_calculi_2024&quot;&gt;
Barton, Dave. 2024. &lt;span&gt;â€œCalculi.â€�&lt;/span&gt; &lt;a href=&quot;https://github.com/DaveBarton/calculi&quot;&gt;https://github.com/DaveBarton/calculi&lt;/a&gt;.
&lt;/div&gt;
&lt;div class=&quot;csl-entry&quot; id=&quot;ref-buteau_polynomials_2013&quot;&gt;
Buteau, Samuel. 2013. &lt;span&gt;â€œPolynomials - &lt;span&gt;School&lt;/span&gt; of
&lt;span&gt;Haskell&lt;/span&gt; &lt;span&gt;School&lt;/span&gt; of
&lt;span&gt;Haskell&lt;/span&gt;.â€�&lt;/span&gt; &lt;em&gt;School of Haskell&lt;/em&gt;. &lt;a href=&quot;https://www.schoolofhaskell.com/user/Sam567/computational-physics/beginner-s-tools/polynomials&quot;&gt;https://www.schoolofhaskell.com/user/Sam567/computational-physics/beginner-s-tools/polynomials&lt;/a&gt;.
&lt;/div&gt;
&lt;div class=&quot;csl-entry&quot; id=&quot;ref-cohen_gbnp_2026&quot;&gt;
Cohen, Arjeh M., and Jan Willem Knopper. 2026.
&lt;span&gt;â€œ&lt;span&gt;GBNP&lt;/span&gt;.â€�&lt;/span&gt; GAP packages. &lt;a href=&quot;https://github.com/gap-packages/gbnp&quot;&gt;https://github.com/gap-packages/gbnp&lt;/a&gt;.
&lt;/div&gt;
&lt;div class=&quot;csl-entry&quot; id=&quot;ref-gibbons_horners_2011&quot;&gt;
Gibbons, Jeremy. 2011. &lt;span&gt;â€œHornerâ€™s &lt;span&gt;Rule&lt;/span&gt;.â€�&lt;/span&gt;
&lt;em&gt;Patterns in Functional Programming&lt;/em&gt;. &lt;a href=&quot;https://patternsinfp.wordpress.com/2011/05/05/horners-rule/&quot;&gt;https://patternsinfp.wordpress.com/2011/05/05/horners-rule/&lt;/a&gt;.
&lt;/div&gt;
&lt;div class=&quot;csl-entry&quot; id=&quot;ref-gibbons_breadthfirst_2015&quot;&gt;
â€”â€”â€”. 2015. &lt;span&gt;â€œBreadth-&lt;span&gt;First Traversal&lt;/span&gt;.â€�&lt;/span&gt;
&lt;em&gt;Patterns in Functional Programming&lt;/em&gt;. &lt;a href=&quot;https://patternsinfp.wordpress.com/2015/03/05/breadth-first-traversal/&quot;&gt;https://patternsinfp.wordpress.com/2015/03/05/breadth-first-traversal/&lt;/a&gt;.
&lt;/div&gt;
&lt;div class=&quot;csl-entry&quot; id=&quot;ref-heisinger_f4ncgb_2025&quot;&gt;
Heisinger, Maximilian, and Clemens Hofstadler. 2025. &lt;span&gt;â€œF4ncgb:
&lt;span&gt;High Performance GrÃ¶bner Basis Computations&lt;/span&gt; in &lt;span&gt;Free
Algebras&lt;/span&gt;.â€�&lt;/span&gt; arXiv. doi:&lt;a href=&quot;https://doi.org/10.48550/arXiv.2505.19304&quot;&gt;10.48550/arXiv.2505.19304&lt;/a&gt;.
&lt;a href=&quot;https://arxiv.org/abs/2505.19304&quot;&gt;https://arxiv.org/abs/2505.19304&lt;/a&gt;.
&lt;/div&gt;
&lt;div class=&quot;csl-entry&quot; id=&quot;ref-hinze_simple_2001&quot;&gt;
Hinze, Ralf. 2001. &lt;span&gt;â€œA simple implementation technique for priority
search queues.â€�&lt;/span&gt; &lt;em&gt;SIGPLAN Not.&lt;/em&gt; 36 (10) (October): 110â€“121.
doi:&lt;a href=&quot;https://doi.org/10.1145/507669.507650&quot;&gt;10.1145/507669.507650&lt;/a&gt;.
&lt;/div&gt;
&lt;div class=&quot;csl-entry&quot; id=&quot;ref-ishii_purely_2018&quot;&gt;
Ishii, Hiromi. 2018. &lt;span&gt;â€œA &lt;span&gt;Purely Functional Computer Algebra
System Embedded&lt;/span&gt; in &lt;span&gt;Haskell&lt;/span&gt;.â€�&lt;/span&gt; In,
11088:288â€“303. doi:&lt;a href=&quot;https://doi.org/10.1007/978-3-319-99639-4_20&quot;&gt;10.1007/978-3-319-99639-4_20&lt;/a&gt;.
&lt;a href=&quot;https://arxiv.org/abs/1807.01456&quot;&gt;https://arxiv.org/abs/1807.01456&lt;/a&gt;.
&lt;/div&gt;
&lt;div class=&quot;csl-entry&quot; id=&quot;ref-jones_lineartime_1993&quot;&gt;
Jones, Geraint, and Jeremy Gibbons. 1993. &lt;em&gt;Linear-time breadth-first
tree algorithms: &lt;span&gt;An&lt;/span&gt; exercise in the arithmetic of folds and
zips&lt;/em&gt;. Dept of Computer Science, University of Auckland. &lt;a href=&quot;https://www.cs.ox.ac.uk/people/jeremy.gibbons/publications/linear.ps.gz&quot;&gt;https://www.cs.ox.ac.uk/people/jeremy.gibbons/publications/linear.ps.gz&lt;/a&gt;.
&lt;/div&gt;
&lt;div class=&quot;csl-entry&quot; id=&quot;ref-laurent_hspray_2024&quot;&gt;
Laurent, StÃ©phane. 2024. &lt;span&gt;â€œHspray.â€�&lt;/span&gt; &lt;a href=&quot;https://github.com/stla/hspray&quot;&gt;https://github.com/stla/hspray&lt;/a&gt;.
&lt;/div&gt;
&lt;div class=&quot;csl-entry&quot; id=&quot;ref-levandovskyy_letterplace_2020&quot;&gt;
Levandovskyy, Viktor, Hans SchÃ¶nemann, and Karim Abou Zeid. 2020.
&lt;span&gt;â€œLetterplace: A subsystem of singular for computations with free
algebras via letterplace embedding.â€�&lt;/span&gt; In &lt;em&gt;Proceedings of the
45th &lt;span&gt;International Symposium&lt;/span&gt; on &lt;span&gt;Symbolic&lt;/span&gt; and
&lt;span&gt;Algebraic Computation&lt;/span&gt;&lt;/em&gt;, 305â€“311. &lt;span&gt;ISSAC&lt;/span&gt;
â€™20. New York, NY, USA: Association for Computing Machinery. doi:&lt;a href=&quot;https://doi.org/10.1145/3373207.3404056&quot;&gt;10.1145/3373207.3404056&lt;/a&gt;.
&lt;/div&gt;
&lt;div class=&quot;csl-entry&quot; id=&quot;ref-malaquias_implementing_2007&quot;&gt;
Malaquias, JosÃ© Romildo, and Carlos Roberto Lopes. 2007.
&lt;span&gt;â€œImplementing a computer algebra system in
&lt;span&gt;Haskell&lt;/span&gt;.â€�&lt;/span&gt; &lt;em&gt;Applied Mathematics and
Computation&lt;/em&gt; 192 (1) (September): 120â€“134. doi:&lt;a href=&quot;https://doi.org/10.1016/j.amc.2007.02.126&quot;&gt;10.1016/j.amc.2007.02.126&lt;/a&gt;.
&lt;/div&gt;
&lt;div class=&quot;csl-entry&quot; id=&quot;ref-manzyuk_grobner_2012&quot;&gt;
Manzyuk, Oleksandr. 2012. &lt;span&gt;â€œGrÃ¶bner bases in &lt;span&gt;Haskell&lt;/span&gt;:
&lt;span&gt;Part I&lt;/span&gt;.â€�&lt;/span&gt; &lt;em&gt;Oleksandr Manzyukâ€™s Blog&lt;/em&gt;. &lt;a href=&quot;https://web.archive.org/web/20221206080655/https://oleksandrmanzyuk.wordpress.com/2012/10/25/grobner-bases-in-haskell-part-i/&quot;&gt;https://web.archive.org/web/20221206080655/https://oleksandrmanzyuk.wordpress.com/2012/10/25/grobner-bases-in-haskell-part-i/&lt;/a&gt;.
&lt;/div&gt;
&lt;div class=&quot;csl-entry&quot; id=&quot;ref-mcilroy_power_1999&quot;&gt;
McIlroy, M. Douglas. 1999. &lt;span&gt;â€œPower &lt;span&gt;Series&lt;/span&gt;, &lt;span&gt;Power
Serious&lt;/span&gt;.â€�&lt;/span&gt; &lt;em&gt;J. Funct. Program.&lt;/em&gt; 9 (3) (May):
325â€“337. doi:&lt;a href=&quot;https://doi.org/10.1017/S0956796899003299&quot;&gt;10.1017/S0956796899003299&lt;/a&gt;.
&lt;/div&gt;
&lt;div class=&quot;csl-entry&quot; id=&quot;ref-sturmfels_what_2005&quot;&gt;
Sturmfels, Bernd. 2005. &lt;span&gt;â€œWhat is... A &lt;span&gt;GrÃ¶bner
Basis&lt;/span&gt;?â€�&lt;/span&gt; &lt;em&gt;Notices of the AMS&lt;/em&gt; 52 (10) (November). &lt;a href=&quot;https://www.ams.org/journals/notices/200510/what-is.pdf&quot;&gt;https://www.ams.org/journals/notices/200510/what-is.pdf&lt;/a&gt;.
&lt;/div&gt;
&lt;div class=&quot;csl-entry&quot; id=&quot;ref-xiu_noncommutative_2012&quot;&gt;
Xiu, Xingqiang. 2012. &lt;span&gt;â€œNon-commutative &lt;span&gt;GrÃ¶bner Bases&lt;/span&gt;
and &lt;span&gt;Applications&lt;/span&gt;.â€�&lt;/span&gt; PhD thesis, UniversitÃ¤t Passau.
&lt;a href=&quot;https://opus4.kobv.de/opus4-uni-passau/frontdoor/index/index/docId/170&quot;&gt;https://opus4.kobv.de/opus4-uni-passau/frontdoor/index/index/docId/170&lt;/a&gt;.
&lt;/div&gt;
&lt;div class=&quot;csl-entry&quot; id=&quot;ref-zucker_division_2018&quot;&gt;
Zucker, Philip. 2018. &lt;span&gt;â€œDivision of polynomials in haskell.â€�&lt;/span&gt;
&lt;em&gt;Hey There Buddo!&lt;/em&gt; &lt;a href=&quot;https://www.philipzucker.com/division-of-polynomials-in-haskell/&quot;&gt;https://www.philipzucker.com/division-of-polynomials-in-haskell/&lt;/a&gt;.
&lt;/div&gt;
&lt;/div&gt;</description>
	<pubDate>Tue, 28 Apr 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Dan Piponi (sigfpe): Some type constructors are tensor products</title>
	<guid isPermaLink="false">tag:blogger.com,1999:blog-11295132.post-5406444218917761776</guid>
	<link>http://blog.sigfpe.com/2026/04/introduction-i-want-to-return-to.html</link>
	<description>&lt;br /&gt;&lt;b&gt;Introduction&lt;/b&gt;&lt;p&gt;

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

&lt;p&gt;First some admin stuff:&lt;/p&gt;

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

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

&amp;gt; infixr 7 ⊗
&lt;/pre&gt;

&lt;p&gt;Suppose you define a type like so:&lt;/p&gt;

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

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

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

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

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

&amp;gt;     abs    = error &quot;abs doesn't make sense here&quot;
&amp;gt;     signum = error &quot;signum makes no sense here&quot;
&lt;/pre&gt;

&lt;p&gt;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 &lt;tt&gt;Complex Float&lt;/tt&gt; or &lt;tt&gt;Complex Double&lt;/tt&gt; as representations of \(\mathbb{C}\).&lt;/p&gt;

&lt;p&gt;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 &lt;tt&gt;A&lt;/tt&gt; is a suitable algebraic structure then, if you allow me to mix code and mathematics notation,&lt;/p&gt;

&lt;div class=&quot;legacy-equation-display&quot;&gt;\[
\mathtt{Complex\ A} = \mathbb{C}\otimes\mathtt{A}
\]&lt;/div&gt;

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

&lt;br /&gt;&lt;b&gt;Tensor Products&lt;/b&gt;&lt;p&gt;

&lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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?&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;So, for example, the dot product can be written as&lt;/p&gt;

&lt;div class=&quot;legacy-equation-display&quot;&gt;\[
x\cdot y = \phi(x\otimes y)
\]&lt;/div&gt;

&lt;p&gt;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\).&lt;/p&gt;

&lt;p&gt;Similarly&lt;/p&gt;

&lt;div class=&quot;legacy-equation-display&quot;&gt;\[
x\times y = \psi(x\otimes y)
\]&lt;/div&gt;

&lt;p&gt;where \(\psi(x_0, x_1, \ldots, x_8)=(x_5 - x_7, x_6 - x_2, x_1 - x_3)\)&lt;/p&gt;

&lt;br /&gt;&lt;b&gt;Algebras&lt;/b&gt;&lt;p&gt;

&lt;/p&gt;&lt;p&gt;It's a confusing use of terminology, but the term &quot;algebra (over \(k\))&quot; 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 &quot;unital algebra&quot;. I'll use the word &quot;unital&quot; when I want to stress that there is a unit.&lt;/p&gt;

&lt;p&gt;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 &lt;a href=&quot;https://en.wikipedia.org/wiki/Algebra_over_a_field&quot;&gt;Wikipedia&lt;/a&gt; for all the properties an algebra must satisfy.&lt;/p&gt;

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

&lt;pre&gt;&amp;gt; class VectorSpace k v where
&amp;gt;     scale :: k -&amp;gt; v -&amp;gt; v

&amp;gt; instance VectorSpace Double Double where
&amp;gt;     scale = (*)
&lt;/pre&gt;

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

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

&lt;p&gt;Because fmap composes through nested functors, scale descends recursively through arbitrarily nested structures like &lt;tt&gt;Complex (Complex Double)&lt;/tt&gt;.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

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

&lt;p&gt;We're literally just recursively building a table of all products of coordinates of &lt;tt&gt;c k&lt;/tt&gt; and coordinates of &lt;tt&gt;a&lt;/tt&gt;.&lt;/p&gt;

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

&lt;br /&gt;&lt;b&gt;Algebras too&lt;/b&gt;&lt;p&gt;

&lt;/p&gt;&lt;p&gt;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 &lt;tt&gt;Num&lt;/tt&gt; instance is already doing the work.&lt;/p&gt;

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

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

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

&lt;p&gt;Something like:&lt;/p&gt;

&lt;pre&gt;    (F ... a ...) * (F ... a' ...) = F ... (... + a * a' + ...) ...
&lt;/pre&gt;

&lt;p&gt;Note that I'm claiming&lt;/p&gt;

&lt;div class=&quot;legacy-equation-display&quot;&gt;\[
\mathtt{F\ A} = \mathtt{F\ Double}\otimes\mathtt{A}
\]&lt;/div&gt;

&lt;p&gt;so I can suppose that &lt;tt&gt;a&lt;/tt&gt; is in &lt;tt&gt;Double&lt;/tt&gt; (or whatever we use to represent the reals).&lt;/p&gt;

&lt;p&gt;Assuming &lt;tt&gt;*&lt;/tt&gt; is such a product:&lt;/p&gt;

&lt;pre&gt;   (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
&lt;/pre&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Also, I used Haskell above but it carries over straightforwardly to other languages, even &lt;tt&gt;C++&lt;/tt&gt;.&lt;/p&gt;

&lt;pre&gt;&amp;gt; main :: IO ()
&amp;gt; main = do
&amp;gt;   print &quot;Bye!&quot;
&lt;/pre&gt;</description>
	<pubDate>Mon, 27 Apr 2026 19:15:36 +0000</pubDate>
	<author>noreply@blogger.com (sigfpe)</author>
</item>
<item>
	<title>Haskell Interlude: 81: Torsten Grust</title>
	<guid isPermaLink="false">Buzzsprout-19077145</guid>
	<link></link>
	<description>&lt;p&gt;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. &lt;/p&gt;</description>
	<pubDate>Mon, 27 Apr 2026 07:00:00 +0000</pubDate>
        <enclosure url="https://www.buzzsprout.com/1817535/episodes/19077145-81-torsten-grust.mp3" length="50950616" type="audio/mpeg"/>
</item>
<item>
	<title>Dan Piponi (sigfpe): Constructing Clifford Algebras using the Super Tensor Product</title>
	<guid isPermaLink="false">tag:blogger.com,1999:blog-11295132.post-4271990394665143853</guid>
	<link>http://blog.sigfpe.com/2023/03/constructing-clifford-algebras-using.html</link>
	<description>&lt;div style=&quot;border: 1px solid #ccc; padding: 10px; background-color: #f9e9e9; margin: 10px 0;&quot;&gt;
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 &lt;a href=&quot;https://github.com/dpiponi/StableBlog/blob/main/ConstructingClifford/ConstructingClifford.pdf&quot;&gt;GitHub&lt;/a&gt;.
&lt;/div&gt;
&lt;p&gt;
Some literate Haskell but little about this code is specific to Haskell...
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;pre&gt;&amp;gt; {-# LANGUAGE DataKinds #-}
&amp;gt; {-# LANGUAGE TypeFamilies #-}
&amp;gt; {-# LANGUAGE TypeOperators #-}
&amp;gt; {-# LANGUAGE UndecidableInstances #-}
&amp;gt; 
&amp;gt; import GHC.TypeLits
&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;b&gt;Introduction&lt;/b&gt;&lt;p&gt;
This is a followup to &lt;a href=&quot;http://blog.sigfpe.com/2006/08/geometric-algebra-for-free_30.html&quot;&gt;Geometric Algebra for Free&lt;/a&gt; and &lt;a href=&quot;http://blog.sigfpe.com/2006/09/more-low-cost-geometric-algebra.html&quot;&gt;More Low Cost Geometric Algebra&lt;/a&gt;.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
In those articles I showed how you could build up the Clifford algebras like so:
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;pre&gt;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'
...
&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;/pre&gt;
I used &lt;tt&gt;CliffN&lt;/tt&gt; as the Clifford algebra for a negative definite inner product and
&lt;tt&gt;CliffN'&lt;/tt&gt; for the positive definite case.
It's not a completely uniform sequence in the sense that &lt;tt&gt;CliffN&lt;/tt&gt; is built from &lt;tt&gt;CliffN'&lt;/tt&gt; for dimension two lower and you use a mix of &lt;tt&gt;Matrix&lt;/tt&gt; and &lt;tt&gt;Quaternion&lt;/tt&gt;.
&lt;p&gt;&lt;br /&gt;
The core principle making this work is that for type constructors &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=T&quot; style=&quot;vertical-align: middle;&quot; /&gt; implemented like &lt;tt&gt;Matrix&lt;/tt&gt;, &lt;tt&gt;Quaternion&lt;/tt&gt; etc. we have the property that
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=TU%5Cmathbb%7BR%7D%20%3D%20T%5Cmathbb%7BR%7D%5Cotimes%20U%5Cmathbb%7BR%7D&quot; style=&quot;vertical-align: middle;&quot; /&gt;
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
eg. &lt;tt&gt;Matrix (Quaternion Float)&lt;/tt&gt; is effectively the same thing as &lt;tt&gt;Matrix Float&lt;/tt&gt; &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=%5Cotimes&quot; style=&quot;vertical-align: middle;&quot; /&gt; &lt;tt&gt;Quaternion Float&lt;/tt&gt;.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
But John Baez pointed out to me that you can build up the &lt;tt&gt;CliffN&lt;/tt&gt; algebras much more simply enabling us to use these definitions:
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;pre&gt;&amp;gt; type Cliff1 = Complex Float
&amp;gt; type Cliff2 = Complex Cliff1
&amp;gt; type Cliff3 = Complex Cliff2
&amp;gt; type Cliff4 = Complex Cliff3
&amp;gt; type Cliff5 = Complex Cliff4
&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;/pre&gt;
&lt;pre&gt;...
&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;/pre&gt;
Or even better:
&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;pre&gt;&amp;gt; type family Cliff (n :: Nat) :: * where
&amp;gt;   Cliff 0 = Float
&amp;gt;   Cliff n = Complex (Cliff (n - 1))
&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;/pre&gt;
But there's one little catch.
We have to work, not with the tensor product, but the &lt;b&gt;super tensor&lt;/b&gt; product.
&lt;p&gt;&lt;br /&gt;
We define &lt;tt&gt;Complex&lt;/tt&gt; the same way as before:
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;pre&gt;&amp;gt; data Complex a = C a a deriving (Eq, Show)
&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;/pre&gt;
Previously we used a definition of multiplication like this:
&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;pre&gt;instance Num a =&amp;gt; Num (Complex a) where
  C a b * C c d = C (a * c - b * d) (a * d + b * c) 
&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;/pre&gt;
We can think of &lt;tt&gt;C a b&lt;/tt&gt; in &lt;tt&gt;Complex R&lt;/tt&gt; as representing the element \(1\otimes a+i\otimes b\). The definition of multiplication in a tensor product of algebras is
&lt;div class=&quot;legacy-equation-display&quot;&gt;\[(a\otimes b)(c\otimes d)=(ac)\otimes(bd).\]&lt;/div&gt;
So we have
&lt;div class=&quot;legacy-equation-display&quot;&gt;\[(1\otimes a+i\otimes b)(1\otimes c+i\otimes d)\]&lt;/div&gt;
&lt;div class=&quot;legacy-equation-display&quot;&gt;\[=1\otimes ac+i\otimes ad+i\otimes bc+i^2\otimes bd\]&lt;/div&gt;
&lt;div class=&quot;legacy-equation-display&quot;&gt;\[=1\otimes(ac-bd)+i\otimes(ad+bc).\]&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;
This means that line of code we wrote above defining &lt;tt&gt;*&lt;/tt&gt; for &lt;tt&gt;Complex&lt;/tt&gt; isn't simply a definition of multiplication of complex numbers, it says how to multiply in an algebra tensored with the complex numbers.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;b&gt;Let's go Super!&lt;/b&gt;&lt;/p&gt;&lt;p&gt;
A &lt;a href=&quot;https://en.wikipedia.org/wiki/Superalgebra&quot;&gt;superalgebra&lt;/a&gt; is an algebra graded by &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=%5Cmathbb%7BZ%7D_2&quot; style=&quot;vertical-align: middle;&quot; /&gt; where &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=%5Cmathbb%7BZ%7D_2&quot; style=&quot;vertical-align: middle;&quot; /&gt; is the ring of integers modulo 2.
What that means is that we have some algebra &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=A&quot; style=&quot;vertical-align: middle;&quot; /&gt; that can be broken down as a direct sum &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=A_0%5Coplus%20A_1&quot; style=&quot;vertical-align: middle;&quot; /&gt; (the subscripts live in &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=%5Cmathbb%7BZ%7D_2&quot; style=&quot;vertical-align: middle;&quot; /&gt;) with the property that multiplication respects the grading, ie. if &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=x&quot; style=&quot;vertical-align: middle;&quot; /&gt; is in &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=A_i&quot; style=&quot;vertical-align: middle;&quot; /&gt; and &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=y&quot; style=&quot;vertical-align: middle;&quot; /&gt; is in &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=A_j&quot; style=&quot;vertical-align: middle;&quot; /&gt; then &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=xy&quot; style=&quot;vertical-align: middle;&quot; /&gt; is in &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=A_%7Bi%2Bj%7D&quot; style=&quot;vertical-align: middle;&quot; /&gt;.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
The elements of &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=A_0&quot; style=&quot;vertical-align: middle;&quot; /&gt; are called &quot;even&quot; (or bosonic) and those in &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=A_1&quot; style=&quot;vertical-align: middle;&quot; /&gt; &quot;odd&quot; (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.)
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
The super tensor product is much like the tensor product but it respects the grading.
This means that if &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=x&quot; style=&quot;vertical-align: middle;&quot; /&gt; is in &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=A_i&quot; style=&quot;vertical-align: middle;&quot; /&gt; and &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=y&quot; style=&quot;vertical-align: middle;&quot; /&gt; is in &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=B_j&quot; style=&quot;vertical-align: middle;&quot; /&gt; then &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=x%5Cotimes%20y&quot; style=&quot;vertical-align: middle;&quot; /&gt; is in &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=%28A%5Cotimes%20B%29_%7Bi%2Bj%7D&quot; style=&quot;vertical-align: middle;&quot; /&gt;.
From now on I'm using &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=%5Cotimes&quot; style=&quot;vertical-align: middle;&quot; /&gt; to mean super tensor product.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
Multiplication in the super tensor product of two superalgebras &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=A&quot; style=&quot;vertical-align: middle;&quot; /&gt; and &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=B&quot; style=&quot;vertical-align: middle;&quot; /&gt; is now defined by the following modified rule:
if &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=b&quot; style=&quot;vertical-align: middle;&quot; /&gt; is in &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=B_i&quot; style=&quot;vertical-align: middle;&quot; /&gt; and &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=c&quot; style=&quot;vertical-align: middle;&quot; /&gt; is in &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=A_j&quot; style=&quot;vertical-align: middle;&quot; /&gt; then &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=%28a%5Cotimes%20b%29%28c%5Cotimes%20d%29%20%3D%20%28-1%29%5E%7Bij%7D%28ac%29%5Cotimes%28bd%29&quot; style=&quot;vertical-align: middle;&quot; /&gt;.
Note that the sign flip arises when we shuffle an odd &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=c&quot; style=&quot;vertical-align: middle;&quot; /&gt; left past an odd &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=b&quot; style=&quot;vertical-align: middle;&quot; /&gt;.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
The neat fact that John pointed out to me is that
&lt;/p&gt;&lt;div class=&quot;legacy-equation-display&quot;&gt;\[Cliff_n=\mathbb{C}\otimes\mathbb{C}\otimes\ldots\text{ n times }\ldots\otimes\mathbb{C}.\]&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;
We have to modify our definition of &lt;tt&gt;*&lt;/tt&gt; to take into account that sign flip.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
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.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
So I could define &lt;tt&gt;SuperAlgebra&lt;/tt&gt; like so:
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;pre&gt;class SuperAlgebra a where
  conjugation :: a -&amp;gt; a
&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;/pre&gt;
where &lt;tt&gt;conjugation&lt;/tt&gt; is the negation of the odd part.
&lt;p&gt;&lt;br /&gt;
(I'm not sure if this operation corresponds to what is usually called conjugation in this branch of mathematics.)
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
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 &lt;tt&gt;negate&lt;/tt&gt;s in a row.
This means applying &lt;tt&gt;negate&lt;/tt&gt; 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 &lt;tt&gt;negate&lt;/tt&gt; and we can
accumulate flips of a flag rather than flips of lots of elements.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;pre&gt;&amp;gt; class SuperAlgebra a where
&amp;gt;   conjugation :: Bool -&amp;gt; a -&amp;gt; a
&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;/pre&gt;
Here's our first instance:
&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;pre&gt;&amp;gt; instance SuperAlgebra Float where
&amp;gt;   conjugation False x = x
&amp;gt;   conjugation True x = negate x
&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;/pre&gt;
This is saying that the conjugation is the identity on &lt;tt&gt;Float&lt;/tt&gt; but if we
want to perform an extra flip we can set the flag to &lt;tt&gt;True&lt;/tt&gt;.
Maybe I should call it &lt;tt&gt;conjugationWithOptionalExtraNegation&lt;/tt&gt;.
&lt;p&gt;&lt;br /&gt;
And now comes the first bit of non-trivial superalgebra:
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;pre&gt;&amp;gt; instance (Num a, SuperAlgebra a) =&amp;gt; SuperAlgebra (Complex a) where
&amp;gt;   conjugation e (C a b) = C (conjugation e a) (conjugation (not e) b)
&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;/pre&gt;
We consider &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=1&quot; style=&quot;vertical-align: middle;&quot; /&gt; to be even and &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=i&quot; style=&quot;vertical-align: middle;&quot; /&gt; to be odd. When we apply the conjugation to &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=1%5Cotimes%20a%2Bi%5Cotimes%20b&quot; style=&quot;vertical-align: middle;&quot; /&gt; then we can just apply it directly to &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=a&quot; style=&quot;vertical-align: middle;&quot; /&gt;.
But that &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=i%5Cotimes&quot; style=&quot;vertical-align: middle;&quot; /&gt; flips the &quot;parity&quot; of &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=b&quot; style=&quot;vertical-align: middle;&quot; /&gt; (because tensor product respects the grading) so we need to swap when we use the conjugation.
And that should explain why &lt;tt&gt;conjugation&lt;/tt&gt; is defined the way it is.
&lt;p&gt;&lt;br /&gt;
Now we can use the modified rule for &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=%5Cmathbb%7BC%7D%5Cotimes&quot; style=&quot;vertical-align: middle;&quot; /&gt; defined above:
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;pre&gt;&amp;gt; instance (Num a, SuperAlgebra a) =&amp;gt; Num (Complex a) where
&amp;gt;   fromInteger n = C (fromInteger n) 0
&amp;gt;   C a b + C a' b' = C (a + a') (b + b')
&amp;gt;   C a b * C c d = C (a * c - conjugation False b * d)
&amp;gt;                     (conjugation False a * d + b * c) 
&amp;gt;   negate (C a b) = C (negate a) (negate b)
&amp;gt;   abs = undefined
&amp;gt;   signum = undefined
&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;/pre&gt;
For example, &lt;tt&gt;conjugation False&lt;/tt&gt; is applied to the first &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=b&quot; style=&quot;vertical-align: middle;&quot; /&gt; on the RHS because &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=d&quot; style=&quot;vertical-align: middle;&quot; /&gt; implicitly represents an &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=id&quot; style=&quot;vertical-align: middle;&quot; /&gt; term and when expanding out the product we shuffle the (odd) &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=i&quot; style=&quot;vertical-align: middle;&quot; /&gt; in &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=id&quot; style=&quot;vertical-align: middle;&quot; /&gt; left of &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=b&quot; style=&quot;vertical-align: middle;&quot; /&gt;. It doesn't get applied to the second &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=ib&quot; style=&quot;vertical-align: middle;&quot; /&gt; because &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=ib&quot; style=&quot;vertical-align: middle;&quot; /&gt; and &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=c&quot; style=&quot;vertical-align: middle;&quot; /&gt; remain in the same order.
&lt;p&gt;&lt;br /&gt;
That's it!
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;b&gt;Tests&lt;/b&gt;&lt;/p&gt;&lt;p&gt;
I'll test it with some examples from &lt;tt&gt;Cliff3&lt;/tt&gt;:
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;pre&gt;&amp;gt; class HasBasis a where
&amp;gt;   e :: Integer -&amp;gt; a
&lt;p&gt;&lt;br /&gt;
&amp;gt; instance HasBasis Float where
&amp;gt;   e = undefined
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&amp;gt; instance (Num a, HasBasis a) =&amp;gt; HasBasis (Complex a) where
&amp;gt;   e 0 = C 0 1
&amp;gt;   e n = C (e (n - 1)) 0
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&amp;gt; make a b c d e f g h =
&amp;gt;   C (C (C a b) (C c d))
&amp;gt;     (C (C e f) (C g h))
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&amp;gt; e1, e2, e3, e21, e31, e32, e321 :: Cliff 3
&amp;gt; e1 = e 0
&amp;gt; e2 = e 1
&amp;gt; e21 = e2 * e1
&amp;gt; e3 = e 2
&amp;gt; e31 = e3 * e1
&amp;gt; e32 = e3 * e2
&amp;gt; e321 = e3 * e2 * e1
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&amp;gt; main = do
&amp;gt;     print (e1 * e1 + 1 == 0)
&amp;gt;     print (e31 * e31 + 1 == 0)
&amp;gt;     print (e3 * e3 + 1 == 0)
&amp;gt;     print (e21 * e21 + 1 == 0)
&amp;gt;     print (e2 * e2 + 1 == 0)
&amp;gt;     print (e32 * e32 + 1 == 0)
&amp;gt;     print (e321 * e321 - 1 == 0)
&amp;gt;     print (e3 * e2 * e1 - e321 == 0)
&amp;gt;     print (e2 * e1 - e21 == 0)
&amp;gt;     print (e3 * e1 - e31 == 0)
&amp;gt;     print (e3 * e2 - e32 == 0)
&amp;gt;     print (e21 * e32 - e31 == 0)
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;b&gt;Observation&lt;/b&gt;&lt;p&gt;
The implementation of multiplication looks remarkably like it's the &lt;a href=&quot;https://en.wikipedia.org/wiki/Cayleyâ€“Dickson_construction&quot;&gt;Cayley-Dickson&lt;/a&gt; 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.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;b&gt;Efficiency&lt;/b&gt;&lt;/p&gt;&lt;p&gt;
As mentioned above, before I realised I just needed the &lt;tt&gt;conjugation&lt;/tt&gt; 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 &quot;speed-up&quot; of complex multiplication that uses three real multiplications instead of four.
This should lead to a fast implementation of Clifford algebras.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
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 &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=n&quot; style=&quot;vertical-align: middle;&quot; /&gt;.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
Note also that this code translates directly into many languages.&lt;/p&gt;</description>
	<pubDate>Thu, 23 Apr 2026 00:28:40 +0000</pubDate>
	<author>noreply@blogger.com (sigfpe)</author>
</item>
<item>
	<title>Dan Piponi (sigfpe): Self-referential logic via self-referential circuits</title>
	<guid isPermaLink="false">tag:blogger.com,1999:blog-11295132.post-1013073177509119669</guid>
	<link>http://blog.sigfpe.com/2017/07/self-referential-logic-via-self.html</link>
	<description>&lt;br /&gt;&lt;b&gt;Introduction&lt;/b&gt;&lt;p&gt;
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&lt;b&gt;TL;DR&lt;/b&gt; 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.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
Here's a &lt;a href=&quot;https://en.wikipedia.org/wiki/Liar_paradox&quot;&gt;famous&lt;/a&gt; paradoxical sentence:
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;blockquote&gt;
&lt;i&gt;This sentence is false&lt;/i&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;br /&gt;
If it's false then it's true and if it's true then it's false.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
Here's a paradoxical electronic circuit:

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

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.
&lt;p&gt;&lt;br /&gt;
There's a similarity here.
But with a bit of tweaking you can turn the similarity into an isomorphism of sorts.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
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 &lt;i&gt;unprovability&lt;/i&gt; and then we get Gödel's incompleteness theorems and a statement that is apparently true and yet can't be proved.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
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 &lt;a href=&quot;https://electronics.stackexchange.com/questions/206907/how-to-delay-a-not-gate-oscillator-to-make-it-run-at-a-desired-frequency&quot;&gt;oscillator circuit&lt;/a&gt; that can be thought of as outputting a stream of bits.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
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 &lt;a href=&quot;https://intelligence.org/files/ProgramEquilibrium.pdf&quot;&gt;logicians or robots play games like Prisoner's Dilemma&lt;/a&gt;.
I'll be making use of results found in Boolos' book on &lt;a href=&quot;http://www.cambridge.org/catalogue/catalogue.asp?isbn=0521483255&quot;&gt;The Logic of Provability&lt;/a&gt; and some ideas I borrowed from Smoryński's &lt;a href=&quot;https://projecteuclid.org/euclid.bams/1183548781&quot;&gt;paper&lt;/a&gt; on Fixed Point Algebras.
I'll be assuming the reader has at least a slight acquaintance with ithe ideas behind provability logic.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;b&gt;Provability Logic&lt;/b&gt;&lt;/p&gt;&lt;p&gt;
There are many descriptions of &lt;a href=&quot;https://en.wikipedia.org/wiki/Provability_logic&quot;&gt;provability logic&lt;/a&gt; (aka GL) available online, so I'm not going to repeat it all here.
However, I've put some background material in the &lt;a href=&quot;http://blog.sigfpe.com/rss.xml#appendix&quot;&gt;appendix&lt;/a&gt; below and I'm going to give a very brief reminder now.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
Start with (classical) propositional calculus which has a bunch of variables with names like &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(a, b, c, d, \ldots\)&lt;/span&gt; and connectives like &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\wedge\)&lt;/span&gt; for AND, &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\vee\)&lt;/span&gt; for OR, &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\neg\)&lt;/span&gt; for NOT and &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\rightarrow\)&lt;/span&gt; for implication. (Note that &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(a\rightarrow b = \neg a\vee b\)&lt;/span&gt;.)
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
Provability logic extends propositional calculus by adding a unary operator &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\Box\)&lt;/span&gt;.
(I apologise, that's meant to be a □ but it's coming out like &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\Box\)&lt;/span&gt; in LaTeX formulae.
I think it's a bug in Google's LaTeX renderer.)
The idea is that &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\Box p\)&lt;/span&gt; asserts that &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(p\)&lt;/span&gt; is provable in Peano Arithmetic, aka PA.
In addition to the axioms of propositional calculus we have
&lt;/p&gt;&lt;blockquote&gt;
&lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\Box(p\rightarrow q)\rightarrow\Box p\rightarrow\Box q\)&lt;/span&gt;
&lt;/blockquote&gt;
and
&lt;blockquote&gt;
&lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\Box p\rightarrow\Box\Box p\)&lt;/span&gt;
&lt;/blockquote&gt;
as well as a rule that allows us to deduce &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\Box p\)&lt;/span&gt; from &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(p\)&lt;/span&gt;.
&lt;p&gt;&lt;br /&gt;
We also have this fixed point property:
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;blockquote&gt;
Let &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(F(p)\)&lt;/span&gt; be any predicate we can write in the language of GL involving the variable &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(p\)&lt;/span&gt;, and suppose that every appearance of &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(p\)&lt;/span&gt; in &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(F(p)\)&lt;/span&gt; is inside a &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\Box\)&lt;/span&gt;, e.g. &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(F(p)=\Box p\vee\Box(\neg p)\)&lt;/span&gt;. Then there is a fixed point, i.e. a proposition &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(q\)&lt;/span&gt; that makes no mention of &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(p\)&lt;/span&gt; such that &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(q\leftrightarrow F(q)\)&lt;/span&gt; is a theorem.
In effect, for any such &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(F\)&lt;/span&gt;, &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(q\)&lt;/span&gt; is a proposition that asserts &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(F(q)\)&lt;/span&gt;.
&lt;/blockquote&gt;
&lt;p&gt;&lt;br /&gt;
See the &lt;a href=&quot;http://blog.sigfpe.com/rss.xml#appendix&quot;&gt;appendix&lt;/a&gt; for a brief mention of why we should expect this to be true.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
From the fixed point property we can deduce Löb's theorem: &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\Box(\Box p\rightarrow p)\rightarrow\Box p\)&lt;/span&gt;.
There is a &lt;a href=&quot;https://en.wikipedia.org/wiki/Löb%27s_theorem&quot;&gt;proof&lt;/a&gt; at wikipedia that starts from the fixed point property.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
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 &lt;a href=&quot;http://semantic-domain.blogspot.com/2016/05/lobs-theorem-is-almost-y-combinator.html&quot;&gt;you can argue&lt;/a&gt; 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 &lt;tt&gt;loeb&lt;/tt&gt; function I defined &lt;a href=&quot;http://blog.sigfpe.com/2006/11/from-l-theorem-to-spreadsheet.html&quot;&gt;way back&lt;/a&gt;.
But note that &lt;tt&gt;loeb&lt;/tt&gt; isn't really a proof of Löb's theorem, it just has formal similarities.)
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;b&gt;Back to electronic circuits&lt;/b&gt;&lt;/p&gt;&lt;p&gt;
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:

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

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.
&lt;p&gt;&lt;br /&gt;
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 &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\{0,1\}\)&lt;/span&gt; to &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\{0,1\}\)&lt;/span&gt;.
Instead let's think of electronic components as binary operators on bitstreams, i.e. infinite streams of binary digits like &lt;tt&gt;...00111010&lt;/tt&gt; 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,
&lt;/p&gt;&lt;blockquote&gt;
&lt;tt&gt;...001110 &amp;amp; ...101010 = ...001010&lt;/tt&gt;
&lt;/blockquote&gt;
and
&lt;blockquote&gt;&lt;tt&gt;~...101 = ...010&lt;/tt&gt;
&lt;/blockquote&gt;
and so on.
Let's use □ to represent the effect of latch-delay on a bitstream.
We have, for example,
&lt;blockquote&gt;
&lt;tt&gt;□...000 = ...001&lt;/tt&gt;
&lt;/blockquote&gt;
and
&lt;blockquote&gt;
&lt;tt&gt;□...11101111 = ...00011111&lt;/tt&gt;.
&lt;/blockquote&gt;
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 &lt;tt&gt;...111111&lt;/tt&gt;, 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 &lt;tt&gt;□p=p^(p+1)&lt;/tt&gt; where &lt;tt&gt;^&lt;/tt&gt; is the C XOR operator.
The operator □ outputs the bits that get flipped when you add one.
&lt;p&gt;&lt;br /&gt;
Let's use the symbol &lt;tt&gt;→&lt;/tt&gt; so that &lt;tt&gt;a → b&lt;/tt&gt; is shorthand for &lt;tt&gt;~a|b&lt;/tt&gt;.
Here are some properties of □:
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
1. &lt;tt&gt;□(-1) = -1&lt;/tt&gt;
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
2. &lt;tt&gt;□p → □□p = -1&lt;/tt&gt;
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
3. &lt;tt&gt;□(p → q) → □p → □q = -1&lt;/tt&gt;
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
In addition we have the fixed point property:
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;blockquote&gt;
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).
&lt;/blockquote&gt;
&lt;p&gt;&lt;br /&gt;
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.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
We also have the Löb property:
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
4. □(□p → p) → □p = -1
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
We can see this by examining the definition of □.
Intuitively it says something like &quot;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&quot;.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
I hope you've noticed something curious.
These properties are extremely close to the properties of &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\Box\)&lt;/span&gt; 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:
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
1. Map &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\bot\)&lt;/span&gt; to a wire set to 0, which outputs &lt;tt&gt;...000 = 0&lt;/tt&gt;.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
2. Map &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\top\)&lt;/span&gt; to a wire set to 1, which outputs &lt;tt&gt;...111 = -1&lt;/tt&gt;.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
3. Map &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(p \circ q\)&lt;/span&gt;, where &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\circ\)&lt;/span&gt; is a binary connective, by creating a circuit that takes the outputs from the circuits for &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(p\)&lt;/span&gt; and &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(q\)&lt;/span&gt; and passes them into the corresponding boolean logic gate.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
4. Map &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\Box p\)&lt;/span&gt; to the circuit for &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(p\)&lt;/span&gt; piped through a delay-latch.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
For example, let's convert &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\Box(\Box\bot\rightarrow\bot)\rightarrow\Box\bot\)&lt;/span&gt; into a circuit. I'm translating &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(a\rightarrow b\)&lt;/span&gt; to the circuit for &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\neg a\vee b\)&lt;/span&gt;.

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

&lt;p&gt;&lt;br /&gt;
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.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
We have this neat result:
&lt;/p&gt;&lt;blockquote&gt;
Because delay-latch satisfies the same equations as &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\Box\)&lt;/span&gt; in provability logic, any theorem, translated into a circuit, will produce a bistream of just 1s, i.e. -1.
&lt;/blockquote&gt;
&lt;p&gt;&lt;br /&gt;
But here's a more surprising result: the converse is true.
&lt;/p&gt;&lt;blockquote&gt;
If the circuit corresponding to a letterless GL proposition produces a bistream of just 1s then the proposition is actually a theorem of GL.
&lt;/blockquote&gt;
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 &lt;tt&gt;...1111&lt;/tt&gt;, so the circuit represents a theorem.
As it represents Löb's theorem for the special case &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(p=\bot\)&lt;/span&gt; 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 &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\psi(p)\)&lt;/span&gt; to represent the translation from propositions to bitstreams via circuits that I described above.
Use &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\phi(b)\)&lt;/span&gt; to represent the translation of bitstream &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(b\)&lt;/span&gt; back into propositions.
We have &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(p\leftrightarrow\phi(\psi(p))\)&lt;/span&gt;.
But I haven't given a full description of &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\phi\)&lt;/span&gt; and I haven't proved here that it has this property.
&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;b&gt;Circuits with feedback&lt;/b&gt;&lt;/p&gt;&lt;p&gt;
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
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 &quot;solve equations&quot; in GL using circuits &lt;i&gt;with&lt;/i&gt; feedback.
The GL fixed point theorem above says that we can &quot;solve&quot; the equation &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(p\leftrightarrow F(p)\)&lt;/span&gt;, with one letter &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(p\)&lt;/span&gt;, to produce a letterless proposition &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(q\)&lt;/span&gt; such that &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(q\leftrightarrow F(q)\)&lt;/span&gt;.
Note here that &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(p\)&lt;/span&gt; is a letter in the language of GL.
But I'm using &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(q\)&lt;/span&gt; to represent a proposition in letterless GL.
If we build a circuit to represent &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(F\)&lt;/span&gt;, and feed its output back into where &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(p\)&lt;/span&gt; appears, then the output bitstream represents the fixed point.
Here's a translation of the equation &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(p \leftrightarrow \neg(\Box p \vee \Box\Box\Box p)\)&lt;/span&gt;:

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

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

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

It starts by outputting 1's and doesn't stop.
In other words, the fixed point is a theorem.
And that tells us &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(p\)&lt;/span&gt; is a theorem.
And hence that the program terminates.
&lt;p&gt;&lt;br /&gt;
&lt;i&gt;2. Robots who reason about each others play in Prisoner's Dilemma&lt;/i&gt;
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
For the background to this problem see &lt;a href=&quot;http://lesswrong.com/lw/hmw/robust_cooperation_in_the_prisoners_dilemma/&quot;&gt;Robust Cooperation in the Prisoner's Dilemma&lt;/a&gt; at LessWrong.
We have two robot participants &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(A\)&lt;/span&gt; and &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(B\)&lt;/span&gt; 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 &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(p =\)&lt;/span&gt; &quot;A will cooperate&quot; and &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(q =\)&lt;/span&gt; &quot;B will cooperate&quot;.
Our assumptions about the behaviour of the robots are &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(p \leftrightarrow \Box q\)&lt;/span&gt; and &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(q \leftrightarrow \Box p\)&lt;/span&gt;, and hence that &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(p \leftrightarrow \Box\Box p\)&lt;/span&gt;.
This corresponds to the circuit:

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

This outputs &lt;tt&gt;...1111 = -1&lt;/tt&gt; so we can conclude &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(p\)&lt;/span&gt; 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 &lt;a href=&quot;https://arxiv.org/abs/1401.5577&quot;&gt;paper&lt;/a&gt; for more on this.)
&lt;p&gt;&lt;br /&gt;
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 :-)
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;b&gt;Things I didn't say above&lt;/b&gt;&lt;/p&gt;&lt;p&gt;
1. I described the translation from propositions to circuits that I called &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\psi\)&lt;/span&gt; above.
But I didn't tell you what &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\phi\)&lt;/span&gt; looks like.
I'll leave this as an exercise.
(Hint: consider the output from the translation of &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\Box^n\bot\)&lt;/span&gt; into a circuit.)
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
2. The integers, considered as bistreams, with the bitwise operators, and the unary operator &lt;tt&gt;□p=p^(p+1)&lt;/tt&gt;, form an algebraic structure.
For example, if we define &lt;tt&gt;⋄p=~□~p&lt;/tt&gt; we have a &lt;a href=&quot;https://ncatlab.org/nlab/show/Magari+algebra&quot;&gt;Magari algebra&lt;/a&gt;.
Structures like these are intended to capture the essential parts of self-referential arguments in an algebraic way.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
3. Because of the interpretation of □ as a delayed latch in a circuit you could view it as saying &quot;my input was always true until a moment ago&quot;.
This surely embeds provability logic in a &lt;a href=&quot;https://en.wikipedia.org/wiki/Temporal_logic&quot;&gt;temporal logic&lt;/a&gt; of some sort.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
4. (Deleted speculations about tit-for-tat that need rethinking.)
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
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 &lt;a href=&quot;https://en.wikipedia.org/wiki/Pneumatic_circuit&quot;&gt;pneumatic circuit&lt;/a&gt;.
I had to say that to fulfil a prophecy and maintain the integrity of the timeline.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;

&lt;a id=&quot;appendix&quot;&gt;&lt;/a&gt;

&lt;br /&gt;&lt;b&gt;Appendix on provability&lt;/b&gt;&lt;/p&gt;&lt;p&gt;
The modern notion of a proof is that it is a string of symbols generated from some initial strings called &quot;axioms&quot; and some derivation rules that make new strings from both axioms and strings you've derived previously.
Usually we pick axioms that represent &quot;self-evident&quot; truths and we pick derivation rules that are &quot;truth-preserving&quot; so that every proof ends at a true proposition of which it is a proof.
The derivation rules are mechanical in nature: things like &quot;if you have this symbol here and that symbol there then you can replace this symbol with that string you derived earlier&quot; etc.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
You can represent strings of symbols using numbers, so-called Gödel numbers.
Let's pick a minimal mathematical framework for working with numbers: &lt;a href=&quot;https://en.wikipedia.org/wiki/Peano_axioms#First-order_theory_of_arithmetic&quot;&gt;Peano Arithmetic&lt;/a&gt;, aka PA.
Let's assume we've made some choice of Gödel numbering scheme and when &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(p\)&lt;/span&gt; is a proposition, write &lt;span class=&quot;legacy-equation-inline&quot;&gt;\([p]\)&lt;/span&gt; for the number representing &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(p\)&lt;/span&gt;.
You can represent the mechanical derivation rules as operations on numbers.
And that makes it possible to define a mathematical predicate &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(Prov\)&lt;/span&gt; that is true if and only if its argument represents a provable proposition.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
In other words, we can prove &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(Prov([p])\)&lt;/span&gt; using PA if and only if &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(p\)&lt;/span&gt; is a proposition provable in PA.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
The predicate &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(Prov\)&lt;/span&gt; has some useful properties:
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
1.&lt;i&gt;If we can prove &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(p\)&lt;/span&gt;, then we can prove &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(Prov([p])\)&lt;/span&gt;.&lt;/i&gt;
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
We take the steps we used to prove &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(p\)&lt;/span&gt;, and convert everything to propositions about numbers.
If &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(Prov\)&lt;/span&gt; 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 &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(Prov(p)\)&lt;/span&gt;.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
2.&lt;i&gt;&lt;span class=&quot;legacy-equation-inline&quot;&gt;\(Prov([p\rightarrow q])\)&lt;/span&gt; and &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(Prov([p])\)&lt;/span&gt; imply &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(Prov([q])\)&lt;/span&gt;&lt;/i&gt;
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
A fundamental step in any proof is &lt;i&gt;modus ponens&lt;/i&gt;, i.e. that &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(p\rightarrow q\)&lt;/span&gt; and &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(q\)&lt;/span&gt; implies &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(p\)&lt;/span&gt;.
If &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(Prov\)&lt;/span&gt; does its job correctly then it had better know about this.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
3.&lt;i&gt;&lt;span class=&quot;legacy-equation-inline&quot;&gt;\(Prov([p])\)&lt;/span&gt; implies &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(Prov([Prov([p])])\)&lt;/span&gt;&lt;/i&gt;
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
One way is to prove this is to use Löb's theorem.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
4. &lt;i&gt;&lt;span class=&quot;legacy-equation-inline&quot;&gt;\(Prov([\top])\)&lt;/span&gt;&lt;/i&gt;
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
The trivially true statement had better be provable or &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(Prov\)&lt;/span&gt; is broken.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
Constructing &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(Prov\)&lt;/span&gt; is conceptually straightforward but hard work.
I'm definitely not going to do it here.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
And there's one last thing we need: self-reference.
If &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(p\)&lt;/span&gt; is a proposition, how can we possibly assert &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(Prov([p])\)&lt;/span&gt; without squeezing a copy of &lt;span class=&quot;legacy-equation-inline&quot;&gt;\([p]\)&lt;/span&gt; inside &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(p\)&lt;/span&gt;?
I'm not going to do that here either - just mention that we can use a variation of &lt;a href=&quot;https://en.wikipedia.org/wiki/Quine_%28computing%29&quot;&gt;quining&lt;/a&gt; to achieve this.
That allows us to form a proposition &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(p\)&lt;/span&gt; for which we can prove &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(p\leftrightarrow Prov([p])\)&lt;/span&gt;.
In fact, we can go further.
We can find propositions that solve &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(p\leftrightarrow F(p)\)&lt;/span&gt; for any predicate &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(F(p)\)&lt;/span&gt; built from the usual boolean operations and &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(p\)&lt;/span&gt; as long as all of the occurrences of &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(p\)&lt;/span&gt; are inside the appearances of &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(Prov\)&lt;/span&gt;.
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.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
Anyway, all that &lt;span class=&quot;legacy-equation-inline&quot;&gt;\([]\)&lt;/span&gt; and &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(Prov\)&lt;/span&gt; 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 &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\Box\)&lt;/span&gt;.
The intention is that if &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(p\)&lt;/span&gt; is a proposition, &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\Box p\)&lt;/span&gt; is a proposition in GL that represents &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(Prov([p])\)&lt;/span&gt; in PA.
The properties of &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(Prov\)&lt;/span&gt; above become the axioms and derivation rules of GL in the main text.&lt;/p&gt;</description>
	<pubDate>Wed, 22 Apr 2026 23:29:47 +0000</pubDate>
	<author>noreply@blogger.com (sigfpe)</author>
</item>
<item>
	<title>Dan Piponi (sigfpe): Expectation-Maximization with Less Arbitrariness</title>
	<guid isPermaLink="false">tag:blogger.com,1999:blog-11295132.post-751712815454057762</guid>
	<link>http://blog.sigfpe.com/2016/10/expectation-maximization-with-less.html</link>
	<description>&lt;b&gt;Introduction&lt;/b&gt;&lt;p&gt;

&lt;/p&gt;&lt;div style=&quot;border: 1px solid #ccc; padding: 10px; background-color: #f9e9e9; margin: 10px 0;&quot;&gt;
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 &lt;a href=&quot;https://github.com/dpiponi/em/blob/master/em.pdf&quot;&gt;GitHub&lt;/a&gt;.
&lt;/div&gt;

&lt;p&gt;
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:
&lt;/p&gt;&lt;ol&gt;&lt;li&gt;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 &lt;i&gt;this&lt;/i&gt; way of writing this expression and not that one which is equal?&lt;/li&gt;
&lt;li&gt;Substituting &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(1=A/A\)&lt;/span&gt; in the middle of an expression.  Again, you can use &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(1=A/A\)&lt;/span&gt; just about anywhere.  Why choose this &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(A\)&lt;/span&gt; at this time? Similarly I found derivations that insert a &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(B-B\)&lt;/span&gt; into an expression.&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;/ol&gt;
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 &lt;a href=&quot;http://stats.stackexchange.com/questions/44513/the-relationship-between-expectation-maximization-and-majorization-minimization/59470#59470&quot;&gt;stackexchange answer&lt;/a&gt;.
&lt;p&gt;&lt;br /&gt;
&lt;b&gt;Generalities about EM&lt;/b&gt;&lt;/p&gt;&lt;p&gt;
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.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
First assume no hidden variables.
We assume there is a vector of parameters &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\theta=(\theta_i)\)&lt;/span&gt; that defines some model.
We make some observations &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(x=(x_j)\)&lt;/span&gt;.
We have a probability density &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(P(x|\theta)\)&lt;/span&gt; that depends on &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\theta\)&lt;/span&gt;.
The likelihood of &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\theta\)&lt;/span&gt; given the observations &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(x\)&lt;/span&gt; is &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(l(\theta|x)=P(x|\theta)\)&lt;/span&gt;.
The maximum likelhood estimator for &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\theta\)&lt;/span&gt; is the choice of &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\theta\)&lt;/span&gt; that maximises &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(l(\theta|x)\)&lt;/span&gt; for the &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(x\)&lt;/span&gt; we have observed.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
Now suppose there are also some variables &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(z=(z_k)\)&lt;/span&gt; that we didn't get to observe.
We assume a density &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(P(x,z|\theta)\)&lt;/span&gt;.
We now have
&lt;/p&gt;&lt;blockquote&gt;
&lt;span class=&quot;legacy-equation-inline&quot;&gt;\(P(x|\theta)=\sum_z P(x,z|\theta)\)&lt;/span&gt;
&lt;/blockquote&gt;
where we sum over all possible values of &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(z\)&lt;/span&gt;.
The MLE approach says we now need to maximise
&lt;blockquote&gt;
&lt;span class=&quot;legacy-equation-inline&quot;&gt;\(l(\theta|x)=\sum_z P(x,z|\theta).\)&lt;/span&gt;
&lt;/blockquote&gt;
One of the things that is a challenge here is that the components of &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\theta\)&lt;/span&gt; might be mixed up among the terms in the sum.
If, instead, each term only referred to its own unique block of &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\theta_i\)&lt;/span&gt;, 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
&lt;blockquote&gt;
&lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\log l(\theta|x)=\log\sum_z P(x,z|\theta).\)&lt;/span&gt;
&lt;/blockquote&gt;
Now imagine that by magic we could commute the logarithm with the sum.
We'd need to maximise
&lt;blockquote&gt;
&lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\sum_z \log P(x,z|\theta).\)&lt;/span&gt;
&lt;/blockquote&gt;
One reason this would be to our advantage is that &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(P(x,z|\theta)\)&lt;/span&gt; often takes the form &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\exp(f(x,z,\theta))\)&lt;/span&gt; where &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(f\)&lt;/span&gt; is a simple function to optimise.
In addition, &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(f\)&lt;/span&gt; may break up as a sum of terms, each with its own block of &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\theta_i\)&lt;/span&gt;'s.
Moving the logarithm inside the sum would give us something we could easily maximise term by term.
What's more, the &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(P(x,z|\theta)\)&lt;/span&gt; for each &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(z\)&lt;/span&gt; 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.
&lt;p&gt;&lt;br /&gt;
&lt;b&gt;Maximisation by proxy&lt;/b&gt;&lt;/p&gt;&lt;p&gt;
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 &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(f\)&lt;/span&gt; is a differentiable function in a neighbourhood of &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(x_0\)&lt;/span&gt;.
Then around &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(x_0\)&lt;/span&gt; we have
&lt;/p&gt;&lt;blockquote&gt;
&lt;span class=&quot;legacy-equation-inline&quot;&gt;\(f(x) \approx f(x_0) f'(x_0)\cdot (x-x_0).\)&lt;/span&gt;
&lt;/blockquote&gt;
We can try optimising &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(f(x_0) f'(x_0)\cdot (x-x_0)\)&lt;/span&gt; with respect to &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(x\)&lt;/span&gt; within a neighbourhood of &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(x_0\)&lt;/span&gt;.
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 &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(f(x_0) f'(x_0)\cdot (x-x_0)\)&lt;/span&gt; because it matches both the value and derivatives of &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(f\)&lt;/span&gt; at &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(x_0\)&lt;/span&gt;.
We could go further and optimise a proxy that shares second derivatives too, and that leads to methods based on Newton-Raphson iteration.
&lt;p&gt;&lt;br /&gt;
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.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
Write
&lt;/p&gt;&lt;blockquote&gt;
&lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\log l(\theta|x)
= \log\sum_z P(x,z|\theta)
\approx \sum_z\beta_z\log P(x,z|\theta) \text{constant}.\)&lt;/span&gt;
&lt;/blockquote&gt;
The &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\beta_z\)&lt;/span&gt; are constants we'll determine.
We want to match the derivatives on either side of the &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\approx\)&lt;/span&gt;
at &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\theta=\theta_0\)&lt;/span&gt;:
&lt;blockquote&gt;
&lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\frac{\partial \log l(\theta_0|x)}{\partial\theta_0}\)&lt;/span&gt; &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(=\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}.\)&lt;/span&gt;
&lt;/blockquote&gt;
On the other hand we have
&lt;blockquote&gt;
&lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\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}\)&lt;/span&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;br /&gt;
To achieve equality we want to make these expressions match.
We choose
&lt;/p&gt;&lt;blockquote&gt;
&lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\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).\)&lt;/span&gt;
&lt;/blockquote&gt;
Our desired proxy function is:
&lt;blockquote&gt;
&lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\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.}\)&lt;/span&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;br /&gt;
So the procedure is to take an estimated &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\theta_0\)&lt;/span&gt; and obtain a new estimate
by optimising this proxy function with respect to &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\theta\)&lt;/span&gt;.
This is the standard EM algorithm.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
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.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&lt;b&gt;Afterword&lt;/b&gt;&lt;/p&gt;&lt;p&gt;
As a side effect we have a general purpose optimisation algorithm that has nothing to do with statistics. If your goal is to compute
&lt;/p&gt;&lt;blockquote&gt;
&lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\operatorname{argmax}_x\sum_i\exp(f_i(x))\)&lt;/span&gt;
&lt;/blockquote&gt;
you can iterate, at each step computing
&lt;blockquote&gt;
&lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\operatorname{argmax}_x\sum_i\exp(f_i(x_0))f_i(x)\)&lt;/span&gt;
&lt;/blockquote&gt;
where &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(x_0\)&lt;/span&gt; is the previous iteration.
If the &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(f_i\)&lt;/span&gt; take a convenient form then this may turn out to be much easier.
&lt;p&gt;&lt;br /&gt;
&lt;b&gt;Note&lt;/b&gt;&lt;/p&gt;&lt;p&gt;
This was originally written as a PDF using LaTeX. It'll be available &lt;a href=&quot;https://t.co/hyZrCiAh6h&quot;&gt;here&lt;/a&gt; for a while. Some fidelity was lost when converting it to HTML.&lt;/p&gt;</description>
	<pubDate>Wed, 22 Apr 2026 23:23:39 +0000</pubDate>
	<author>noreply@blogger.com (sigfpe)</author>
</item>
<item>
	<title>Dan Piponi (sigfpe): Logarithms and exponentials of functions</title>
	<guid isPermaLink="false">tag:blogger.com,1999:blog-11295132.post-8266076036196212490</guid>
	<link>http://blog.sigfpe.com/2017/02/logarithms-and-exponentials-of-functions.html</link>
	<description>&lt;br /&gt;&lt;b&gt;Introduction&lt;/b&gt;&lt;p&gt;
A popular question in mathematics is this: given a function &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(f\)&lt;/span&gt;, what is its &quot;square root&quot; &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(g\)&lt;/span&gt; in the sense that &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(g(g(x)) = f(x)\)&lt;/span&gt;.
There are many questions about this on &lt;a href=&quot;http://mathoverflow.net/questions/tagged/fractional-iteration&quot;&gt;mathoverflow&lt;/a&gt; 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 &lt;a href=&quot;http://blog.sigfpe.com/2007/11/small-combinatorial-library.html&quot;&gt;here&lt;/a&gt;.
There are some methods for directly finding &quot;functional square roots&quot; for formal power series that start as &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(z a_2z^2 a_3z^3 \ldots\)&lt;/span&gt;, but I want to approach the problem indirectly.
When working with real numbers we can find square roots, say, by using &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\sqrt{x}=\exp(\frac{1}{2}\log{x})\)&lt;/span&gt;.
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.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;b&gt;Notation&lt;/b&gt;&lt;/p&gt;&lt;p&gt;
There's potential for a lot of ambiguous notation here, especially as the usual mathematical notation for &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(n\)&lt;/span&gt;th powers of trig functions is so misleading.
I'm going to use &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\circ\)&lt;/span&gt; for composition of functions and power series, and I'm going to use the notation &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(f^{\circ n}\)&lt;/span&gt; to mean the &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(n\)&lt;/span&gt;th iterate of &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(f\)&lt;/span&gt;.
So &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(f^{n 1}(x) = f(x)f^n(x)\)&lt;/span&gt; and &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(f^{\circ n 1}(x) = f(f^{\circ n}(x))\)&lt;/span&gt;.
As I'll be working mostly in the ring of formal power series &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(R[\![z]\!]\)&lt;/span&gt; for some ring &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(R\)&lt;/span&gt;, I'll reserve the variable &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(z\)&lt;/span&gt; to refer only to the corresponding element in this ring.
I'll also use formal power series somewhat interchangeably with functions. So &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(z\)&lt;/span&gt; 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:
&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;span class=&quot;legacy-equation-inline&quot;&gt;\(z^mz^n = z^{m n}\)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;legacy-equation-inline&quot;&gt;\(f^{\circ m}\circ f^{\circ n} = f^{\circ m n}\)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;legacy-equation-inline&quot;&gt;\((1 z)^n = \sum_{i=0}^n{n\choose i}z^n\)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;legacy-equation-inline&quot;&gt;\((1 z)^{\circ n}=n z\)&lt;/span&gt;.&lt;/li&gt;
&lt;/ol&gt;
That last one simply says that adding one &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(n\)&lt;/span&gt; times is the same as adding &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(n\)&lt;/span&gt;.
&lt;p&gt;&lt;br /&gt;
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 &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\operatorname{LOG}\)&lt;/span&gt; for functional logarithm and &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\operatorname{EXP}\)&lt;/span&gt; for functional exponentiation.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;b&gt;Preliminaries&lt;/b&gt;&lt;/p&gt;&lt;p&gt;
The first goal is to define a non-trivial function &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\operatorname{LOG}\)&lt;/span&gt; with the fundamental property that &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\operatorname{LOG}(f^{\circ n})=n\operatorname{LOG}(f)\)&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
First, let's note some basic algebraic facts.
The formal power series form a commutative ring with operations &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=%2B&quot; style=&quot;vertical-align: middle;&quot; /&gt; and &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\cdot\)&lt;/span&gt; (ordinary multiplication) and with additive identity &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(0\)&lt;/span&gt; and multiplicative identity &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(1\)&lt;/span&gt;.
The formal power series form a ring-like algebraic structure with operation &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=%2B&quot; style=&quot;vertical-align: middle;&quot; /&gt; and partial operation &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\circ\)&lt;/span&gt; with additive identity &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(0\)&lt;/span&gt; and multiplicative identity &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(z\)&lt;/span&gt;.
But it's not actually ring or even a &lt;a href=&quot;https://en.wikipedia.org/wiki/Near-ring&quot;&gt;near-ring&lt;/a&gt;.
Composition isn't defined for all formal power series and even when it's defined, we don't have distributivity.
For example, in general &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(f\circ(g h)\ne f\circ g f\circ h\)&lt;/span&gt;, after all there's no reason to expect &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(f(g(x) h(x))\)&lt;/span&gt; to equal &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(f(g(x)) f(h(x))\)&lt;/span&gt;.
We do have right-distributivity however, i.e.
&lt;/p&gt;&lt;blockquote&gt;
&lt;span class=&quot;legacy-equation-inline&quot;&gt;\((f g)\circ h = f\circ g f\circ h\)&lt;/span&gt;,
&lt;/blockquote&gt;
because
&lt;blockquote&gt;
&lt;span class=&quot;legacy-equation-inline&quot;&gt;\((f g)(h(x))=f(h(x)) g(h(x))\)&lt;/span&gt;,
&lt;/blockquote&gt;
more or less by definition of &lt;img src=&quot;https://chart.googleapis.com/chart?cht=tx&amp;amp;chl=%2B&quot; style=&quot;vertical-align: middle;&quot; /&gt;.
&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;b&gt;We can't use power series on our power series&lt;/b&gt;&lt;/p&gt;&lt;p&gt;
There's an obvious approach, just use power series of power series.
So we might tentatively suggest that
&lt;/p&gt;&lt;blockquote&gt;
&lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\operatorname{LOG}(z f) = f-\frac{1}{2}f^{\circ 2} \frac{1}{3}f^{\circ 3} \ldots\)&lt;/span&gt;.
&lt;/blockquote&gt;
Note that I consider &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\operatorname{LOG}(z f)\)&lt;/span&gt; rather than &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\operatorname{LOG}(1 f)\)&lt;/span&gt; because &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(z\)&lt;/span&gt; is the multiplicative identity in our ring-like structure.
&lt;p&gt;&lt;br /&gt;
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.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;b&gt;Sleight of hand&lt;/b&gt;&lt;/p&gt;&lt;p&gt;
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 &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(R(g)\)&lt;/span&gt; defined by &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(R(g)(f) = f\circ g\)&lt;/span&gt;.
In other words &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(R(g)\)&lt;/span&gt; is right-composition by &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(g\)&lt;/span&gt;.
(Ambiguity alert, I'm using &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(R\)&lt;/span&gt; here to mean &lt;i&gt;right&lt;/i&gt;.
It has nothing to do with the ring underlying our formal power series.)
Because we have right-distributivity, &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(R(g)\)&lt;/span&gt; is a &lt;i&gt;bona fide&lt;/i&gt; linear operator on the space of formal power series.
If you think of formal power series as being infinitely long vectors of coefficients then &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(R(g)\)&lt;/span&gt; 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 &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\log R(g)\)&lt;/span&gt; with the property that &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\log(R(g)^n) = n\log R(g)\)&lt;/span&gt;.
Define:
&lt;/p&gt;&lt;blockquote&gt;
&lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\operator{LOG}(f) = \log(R(f))z\)&lt;/span&gt;.
&lt;/blockquote&gt;
We have:
&lt;blockquote&gt;
&lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\operator{LOG}(f) = \log(R(f))z = \log(1 (R(f)-1))z\)&lt;/span&gt;
&lt;/blockquote&gt;
where I'm using &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(1\)&lt;/span&gt; to mean the identity linear operator.
And now have:
&lt;blockquote&gt;
&lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\operator{LOG}(f) = (R(f)-1)z-\frac{1}{2}(R(f)-1)^2z \frac{1}{3}(R(f)-1)^3z \ldots\)&lt;/span&gt;.
&lt;/blockquote&gt;
But does it converge?
Suppose &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(f\)&lt;/span&gt; is of the form &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(x a_2x^2 a_3x^3 \ldots\)&lt;/span&gt;.
Then &lt;span class=&quot;legacy-equation-inline&quot;&gt;\((R(f)-1)g = g\circ f-g\)&lt;/span&gt;.
The leading term in &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(g\circ f\)&lt;/span&gt; is the same as the leading term in &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(g\)&lt;/span&gt;.
So &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(R(f)-1\)&lt;/span&gt; kills the first term of whatever it is applied to, which means that when we sum the terms in &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\operatorname{LOG}(f)\)&lt;/span&gt;, we only need &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(n\)&lt;/span&gt; to get a power series correct to &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(n\)&lt;/span&gt; coefficients.
Reusing my code from &lt;a href=&quot;http://blog.sigfpe.com/2007/11/small-combinatorial-library.html&quot;&gt;here&lt;/a&gt;, I call &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\operatorname{LOG}\)&lt;/span&gt; by the name &lt;tt&gt;flog&lt;/tt&gt;.
Here is its implementation:
&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;pre&gt;&amp;gt; import Data.Ratio
&lt;p&gt;&lt;br /&gt;
&amp;gt; flog :: (Eq a, Fractional a) =&amp;gt; [a] -&amp;gt; [a]
&amp;gt; flog f@(0 : 1 : _) =
&amp;gt;   flog' 1 (repeat 0) (0 : 1 : repeat 0)
&amp;gt;      where flog' n total term = take (n+1) total ++ (
&amp;gt;              drop (n+1) $
&amp;gt;                 let pz = p term
&amp;gt;                 in flog' (n+1) (total-map (((-1)^n / fromIntegral n) *) pz) pz)
&amp;gt;            p total = (total ○ f) - total
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;/pre&gt;
The &lt;tt&gt;take&lt;/tt&gt; and &lt;tt&gt;drop&lt;/tt&gt; are how I tell Haskell when the first &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(n 1\)&lt;/span&gt; coefficients have been exactly computed and so no more terms are necessary.
&lt;p&gt;&lt;br /&gt;
Does it work?
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
Here's an example using the twice iterated sin function:
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;pre&gt;&amp;gt; ex1 = do
&amp;gt;   let lhs = flog (sin (sin z))
&amp;gt;   let rhs = 2*flog (sin z)
&amp;gt;   mapM_ print $ take 20 (lhs-rhs)
&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;/pre&gt;
Works to 20 coefficients. Dare we try an inverse function?
&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;pre&gt;&amp;gt; ex2 = do
&amp;gt;   let lhs = flog (sin z)
&amp;gt;   let rhs = flog (asin z)
&amp;gt;   mapM_ print $ take 20 (lhs+rhs)
&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;/pre&gt;
Seems to work!
&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;b&gt;Exponentials&lt;/b&gt;&lt;/p&gt;&lt;p&gt;
It's no good having logarithms if we can't invert them.
One way to think about the exponential function is that
&lt;/p&gt;&lt;blockquote&gt;
&lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\exp(x) = \lim_{n\rightarrow \infty}(1 \frac{x}{n})^n\)&lt;/span&gt;
&lt;/blockquote&gt;
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 &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\exp\)&lt;/span&gt; from this, but only if right-distributivity holds.
So let's try to use the above expression directly:
&lt;blockquote&gt;
&lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\operatorname{EXP}(f) = \lim_{n\rightarrow \infty}(z \frac{f}{n})^{\circ n}\)&lt;/span&gt;
&lt;/blockquote&gt;
and get
&lt;blockquote&gt;
&lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\operatorname{EXP}(f) = \lim_{n\rightarrow \infty}R(z \frac{f}{n})^nz\)&lt;/span&gt;.
&lt;/blockquote&gt;
Unfortunately, even though &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(R(g)\)&lt;/span&gt; is linear, &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(R\)&lt;/span&gt; itself isn't.
So it's going to take some extra work to raise &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(R(z f/n)\)&lt;/span&gt; to the power of &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(n\)&lt;/span&gt;.
&lt;p&gt;&lt;br /&gt;
The good news is that we're dealing with the special case &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(R(z \epsilon)\)&lt;/span&gt; where &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\epsilon\)&lt;/span&gt; is something small.
We have
&lt;/p&gt;&lt;blockquote&gt;
&lt;span class=&quot;legacy-equation-inline&quot;&gt;\(R(z \epsilon)f=f(z \epsilon)=f(z) \epsilon\frac{df}{dz} O(\epsilon^2)\)&lt;/span&gt;.
&lt;/blockquote&gt;
So &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(R(z f/n)\)&lt;/span&gt; is actually &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(1 \frac{1}{n}f\frac{d}{dz}\)&lt;/span&gt; modulo higher order terms.
This gives us
&lt;blockquote&gt;
&lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\operatorname{EXP}(f) = \lim_{n\rightarrow \infty}(1 \frac{1}{n}f\frac{d}{dz})^nz=\exp(f\frac{d}{dz})z\)&lt;/span&gt;.
&lt;/blockquote&gt;
This is something we can implement using the power series for ordinary &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\exp\)&lt;/span&gt;:
&lt;blockquote&gt;
&lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\operatorname{EXP}(f) = z f \frac{1}{2!}f\frac{df}{dz} \frac{1}{3!}f\frac{d}{dz}(f\frac{df}{dz}) \ldots\)&lt;/span&gt;.
&lt;/blockquote&gt;
In code that becomes:
&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;pre&gt;&amp;gt; fexp f@(0 : 0 : _) = fexp' f 0 z 1
&amp;gt; fexp' f total term n = take (n-1) total ++ drop (n-1)
&amp;gt;           (fexp' f (total+term) (map (/fromIntegral n) (f*d term)) (n+1))
&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;/pre&gt;
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 &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(f\)&lt;/span&gt; to look like &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(a_2z^2 a_3a^3 \ldots\)&lt;/span&gt;.
Luckily this is exactly the kind of series &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\operatorname{LOG}\)&lt;/span&gt; gives us.
&lt;p&gt;&lt;br /&gt;
But does it successfully invert &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\operatorname{LOG}\)&lt;/span&gt;?
Let's try:
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;pre&gt;&amp;gt; ex3 = do
&amp;gt;   let lhs = sin z
&amp;gt;   let rhs = fexp (flog (sin z))
&amp;gt;   mapM_ print $ take 20 (lhs-rhs)
&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;/pre&gt;
Now we can start computing fractional iterates.
Square root first:
&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;pre&gt;&amp;gt; ex4 = do
&amp;gt;   mapM_ print $ take 20 $ fexp (flog (sin z)/2)
&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;/pre&gt;
That matches the results at &lt;a href=&quot;http://oeis.org/A048602&quot;&gt;A048602&lt;/a&gt; and &lt;a href=&quot;http://oeis.org/A048603&quot;&gt;A048603&lt;/a&gt;.
&lt;p&gt;&lt;br /&gt;
Cube root:
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;pre&gt;&amp;gt; ex5 = do
&amp;gt;   mapM_ print $ take 20 $ fexp (flog (sin z)/3)
&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;/pre&gt;
Matches &lt;a href=&quot;http://oeis.org/A052132&quot;&gt;A052132&lt;/a&gt; and &lt;a href=&quot;http://oeis.org/A052135&quot;&gt;A052135&lt;/a&gt;.
&lt;p&gt;&lt;br /&gt;
And this gives an alternative to Lagrange inversion for computing power series for inverse functions:
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;pre&gt;&amp;gt; ex6 = do
&amp;gt;   let lhs = fexp (-flog (sin z))
&amp;gt;   let rhs = asin z
&amp;gt;   mapM_ print $ take 20 (lhs-rhs)
&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;b&gt;What's really going on with &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\operatorname{EXP}\)&lt;/span&gt;?&lt;/b&gt;&lt;p&gt;
Let's approach &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\operatorname{EXP}\)&lt;/span&gt; in a slightly different way.
In effect, &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\operatorname{EXP}\)&lt;/span&gt; is the composition of &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(n\)&lt;/span&gt; lots of &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(z \frac{f}{n}\)&lt;/span&gt; with &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(z\)&lt;/span&gt;.
So let's try composing these one at a time, with one composition every &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\frac{1}{n}\)&lt;/span&gt; seconds.
After one second we should have our final result.
We can write this as:
&lt;/p&gt;&lt;blockquote&gt;
&lt;span class=&quot;legacy-equation-inline&quot;&gt;\(g(0) = z\)&lt;/span&gt; and &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(g(t \frac{1}{n}) = g(t) \frac{1}{n}f(g(t))\)&lt;/span&gt; to first order.
&lt;/blockquote&gt;
So we're solving the differential equation:
&lt;blockquote&gt;
&lt;span class=&quot;legacy-equation-inline&quot;&gt;\(g(0) = z\)&lt;/span&gt; and &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\frac{dg}{dt} = f(g(t))\)&lt;/span&gt;
&lt;/blockquote&gt;
with &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\operatorname{EXP}(g) = g(1)\)&lt;/span&gt;.
&lt;p&gt;&lt;br /&gt;
So &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\operatorname{EXP}\)&lt;/span&gt; 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
&lt;/p&gt;&lt;blockquote&gt;
&lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\frac{dg}{dt}=sin(g(t))^2\)&lt;/span&gt; and &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(g(0)=x\)&lt;/span&gt;
&lt;/blockquote&gt;
at &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(t=1\)&lt;/span&gt; is
&lt;blockquote&gt;
&lt;span class=&quot;legacy-equation-inline&quot;&gt;\(g(1) = \frac{\tan z}{1-\tan z}\)&lt;/span&gt;
&lt;/blockquote&gt;
so let's check:
&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;pre&gt;&amp;gt; ex7 = do
&amp;gt;   let lhs = fexp ((sin z)^2)
&amp;gt;   let rhs = atan (tan z/(1-tan z))
&amp;gt;   mapM_ print $ take 20 (lhs-rhs)
&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;/pre&gt;
I like this example because it leads to the generalized Catalan numbers &lt;a href=&quot;http://oeis.org/A004148&quot;&gt;A004148&lt;/a&gt;:
&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;pre&gt;&amp;gt; ex8 = do
&amp;gt;     mapM_ print $ take 20 $ fexp (z^2/(1-z^2))
&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;/pre&gt;
That suggests this question: what does &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\operatorname{EXP}\)&lt;/span&gt; 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 &lt;a href=&quot;https://arxiv.org/abs/1512.00906&quot;&gt;here&lt;/a&gt;.
&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;b&gt;What is going on geometrically?&lt;/b&gt;&lt;/p&gt;&lt;p&gt;
For those who know some differential geometry,
The differential equation
&lt;/p&gt;&lt;blockquote&gt;
&lt;span class=&quot;legacy-equation-inline&quot;&gt;\(g(0) = z\)&lt;/span&gt; and &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\frac{dg}{dt} = f(g(t))\)&lt;/span&gt;
&lt;/blockquote&gt;
describes a flow on the real line (or complex plane).
You can think of &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(f\)&lt;/span&gt; as being a one-dimensional vector field describing how points move from time &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(t\)&lt;/span&gt; to &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(t dt\)&lt;/span&gt;.
When we solve the differential equation we get &lt;a href=&quot;https://en.wikipedia.org/wiki/Integral_curve&quot;&gt;integral curves&lt;/a&gt; that these points follow and &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\operatorname{EXP}\)&lt;/span&gt; tells us where the points end up after one unit of time.
So &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\operatorname{EXP}\)&lt;/span&gt; is the &lt;a href=&quot;https://en.wikipedia.org/wiki/Exponential_map_%28Riemannian_geometry%29&quot;&gt;exponential map&lt;/a&gt;.
In fact, &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\operatorname{EXP}(f)=\exp(f\frac{d}{dz})z\)&lt;/span&gt; is essentially the exponential of the vector field &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(f\frac{d}{dz}\)&lt;/span&gt; where we're now using the differential geometer's notion of a vector field as a differential operator.
&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;b&gt;Final word&lt;/b&gt;&lt;/p&gt;&lt;p&gt;
Unfortunately the power series you get from using &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\operator{LOG}\)&lt;/span&gt; and &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\operator{EXP}\)&lt;/span&gt; don't always have good convergence properties.
For example, I'm not sure but I think the series for &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\sin^{\circ 1/2} z\)&lt;/span&gt; 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.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;b&gt;And the rest of the code&lt;/b&gt;&lt;/p&gt;&lt;p&gt;
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;pre&gt;&amp;gt; (*!) _ 0 = 0
&amp;gt; (*!) a b = a*b
&amp;gt; (!*) 0 _ = 0
&amp;gt; (!*) a b = a*b
&amp;gt; (^+) a b = zipWith (+) a b
&amp;gt; (^-) a b = zipWith (-) a b
&lt;p&gt;&lt;br /&gt;
&amp;gt; ~(a:as) ⊗ (b:bs) = (a *! b):
&amp;gt;     ((map (a !*) bs) ^+ (as ⊗ (b:bs)))
&amp;gt; (○) (f:fs) (0:gs) = f:(gs ⊗ (fs ○ (0:gs)))
&amp;gt; inverse (0:f:fs) = x where x     = map (recip f *) (0:1:g)
&amp;gt;                            _:_:g    = map negate ((0:0:fs) ○ x)
&amp;gt; invert x = r where r = map (/x0)  ((1:repeat 0) ^- (r ⊗ (0:xs)))
&amp;gt;                    x0:xs = x 
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&amp;gt; (^/) (0:a) (0:b) = a ^/ b
&amp;gt; (^/) a b = a ⊗ (invert b)
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&amp;gt; z :: [Rational]
&amp;gt; z = 0:1:repeat 0
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&amp;gt; d (_:x) = zipWith (*) (map fromInteger [1..]) x
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&amp;gt; integrate x = 0 : zipWith (/) x (map fromInteger [1..])
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&amp;gt; instance (Eq r, Num r) =&amp;gt; Num [r] where
&amp;gt;     x+y  = zipWith (+) x y
&amp;gt;     x-y  = zipWith (-) x y
&amp;gt;     ~x*y = x ⊗ y
&amp;gt;     fromInteger x      = fromInteger x:repeat 0
&amp;gt;     negate x     = map negate x
&amp;gt;     signum (x:_) = signum x : repeat 0
&amp;gt;     abs (x:xs)   = error &quot;Can't form abs of a power series&quot;
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&amp;gt; instance (Eq r, Fractional r) =&amp;gt; Fractional [r] where
&amp;gt;     x/y = x ^/ y
&amp;gt;     fromRational x    = fromRational x:repeat 0
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&amp;gt; sqrt' x = 1 : rs where rs = map (/2) (xs ^- (rs ⊗ (0:rs)))
&amp;gt;                        _ : xs = x
&amp;gt; instance (Eq r, Fractional r) =&amp;gt; Floating [r] where
&amp;gt;     sqrt (1 : x) = sqrt' (1 : x)
&amp;gt;     sqrt _  = error &quot;Can only find sqrt when leading term is 1&quot;
&amp;gt;     exp x   = e where e = 1+integrate (e * d x)
&amp;gt;     log x   = integrate (d x/x)
&amp;gt;     sin x   = integrate ((cos x)*(d x))
&amp;gt;     cos x   = [1] ... negate (integrate ((sin x)*(d x)))
&amp;gt;     asin x  = integrate (d x/sqrt(1-x*x))
&amp;gt;     atan x  = integrate (d x/(1+x*x))
&amp;gt;     acos x  = error &quot;Unable to form power series for acos&quot;
&amp;gt;     sinh x  = integrate ((cosh x)*(d x))
&amp;gt;     cosh x  = [1] ... integrate ((sinh x)*(d x))
&amp;gt;     asinh x = integrate (d x/sqrt(1+x*x))
&amp;gt;     atanh x = integrate (d x/(1-x*x))
&amp;gt;     acosh x = error &quot;Unable to form power series for acosh&quot;
&amp;gt;     pi      = error &quot;There is no formal power series for pi&quot;
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&amp;gt; lead [] x = x
&amp;gt; lead (a:as) x = a : (lead as (tail x))
&amp;gt; a ... x = lead a x
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&amp;gt; (//) :: Fractional a =&amp;gt; [a] -&amp;gt; (Integer -&amp;gt; Bool) -&amp;gt; [a]
&amp;gt; (//) a c = zipWith (\a-&amp;gt; \b-&amp;gt;(if (c a :: Bool) then b else 0)) [(0::Integer)..] a
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;/pre&gt;
A direct functional square root that doesn't use &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\operatorname{LOG}\)&lt;/span&gt; and &lt;span class=&quot;legacy-equation-inline&quot;&gt;\(\operatorname{EXP}\)&lt;/span&gt;:
&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;pre&gt;&amp;gt; fsqrt (0 : 1 : fs) =
&amp;gt;     let gs = (fs-(0 : gs*((0 : delta gs gs)+((2 : gs)*(gs*g)))))/2
&amp;gt;         g = 0 : 1 : gs
&amp;gt;         delta (g : gs) h = let g' = delta gs h
&amp;gt;                    in (0 : ((1 : h) * g')) + gs
&amp;gt;     in g
&lt;/pre&gt;</description>
	<pubDate>Wed, 22 Apr 2026 23:16:27 +0000</pubDate>
	<author>noreply@blogger.com (sigfpe)</author>
</item>
<item>
	<title>Tweag I/O: ð�•¯ð�–”ð�–ˆ ð�–Žð�–™ ð�–‘ð�–Žð�–�ð�–Š ð�–Žð�–™'ð�–˜ ð�–�ð�–”ð�–™</title>
	<guid isPermaLink="true">https://tweag.io/blog/2026-04-16-doc-it-like-its-hot/</guid>
	<link>https://tweag.io/blog/2026-04-16-doc-it-like-its-hot/</link>
	<description>&lt;div class=&quot;lyrics&quot;&gt;
&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://www.tweag.io/static/762ffa5f48916f2ae5059d549abae602/5ff7e/pharrell-1.png&quot; rel=&quot;noopener&quot; style=&quot;display: block;&quot; target=&quot;_blank&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 100%; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img alt=&quot;Pharrell&quot; class=&quot;gatsby-resp-image-image&quot; src=&quot;https://www.tweag.io/static/762ffa5f48916f2ae5059d549abae602/5ff7e/pharrell-1.png&quot; style=&quot;width: 100%; height: 100%; margin: 0; vertical-align: middle;&quot; title=&quot;Pharrell&quot; /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You’ve got some nice code. That’s a nice trie. &lt;br /&gt;
I see those PRs. But no &lt;code class=&quot;language-text&quot;&gt;README&lt;/code&gt;?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;p&gt;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 &lt;em&gt;should&lt;/em&gt; be thinking is, “I &lt;em&gt;get&lt;/em&gt; 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.&lt;/p&gt;
&lt;p&gt;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 &lt;i&gt;pro&lt;/i&gt;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.&lt;/p&gt;
&lt;h2 id=&quot;when-your-readmes-a-monolith&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#when-your-readmes-a-monolith&quot;&gt;&lt;/a&gt;When your &lt;code class=&quot;language-text&quot;&gt;README&lt;/code&gt;’s a monolith&lt;/h2&gt;
&lt;div class=&quot;lyrics&quot;&gt;
&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://www.tweag.io/static/4c6ea454e851d06070b463adc975197b/e45a9/snoop-1.png&quot; rel=&quot;noopener&quot; style=&quot;display: block;&quot; target=&quot;_blank&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 100%; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img alt=&quot;Snoop Dogg&quot; class=&quot;gatsby-resp-image-image&quot; src=&quot;https://www.tweag.io/static/4c6ea454e851d06070b463adc975197b/e45a9/snoop-1.png&quot; style=&quot;width: 100%; height: 100%; margin: 0; vertical-align: middle;&quot; title=&quot;Snoop Dogg&quot; /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Doc it like it’s hot&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;p&gt;Sometimes the docs are already a mess and you gotta clean house. That’s
the reactive play.&lt;/p&gt;
&lt;p&gt;That was the case with &lt;a href=&quot;https://topiary.tweag.io&quot;&gt;Topiary&lt;/a&gt;, 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.&lt;/p&gt;
&lt;p&gt;Moreover, our documentation covered usage instructions, which were
checked against the &lt;code class=&quot;language-text&quot;&gt;--help&lt;/code&gt; output of each subcommand. Then there was
our project motivation and design philosophy, language support,
installation instructions, configuration details, usage guides…&lt;/p&gt;
&lt;p&gt;…All in a single &lt;code class=&quot;language-text&quot;&gt;README.md&lt;/code&gt; which had grown to over 7,000 words. Way
too big for the crib, homes. Ain’t nobody reading all that!&lt;/p&gt;
&lt;p&gt;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?&lt;/p&gt;
&lt;p&gt;Topiary OG Erin started work reconstructing the monolith into a book
format using — as it’s a Rust project — &lt;a href=&quot;https://rust-lang.github.io/mdBook&quot;&gt;mdBook&lt;/a&gt;. I picked up where he
left off and finished it for Topiary v0.6.1. Yo, the &lt;a href=&quot;https://topiary.tweag.io/book&quot;&gt;Topiary Book&lt;/a&gt; was
born!&lt;/p&gt;
&lt;p&gt;But the move here wasn’t just splitting up the &lt;code class=&quot;language-text&quot;&gt;README.md&lt;/code&gt; 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 &lt;a href=&quot;https://diataxis.fr&quot;&gt;Diátaxis&lt;/a&gt;, which identifies four distinct documentation
types based on what the reader actually needs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tutorials&lt;/strong&gt;, for learners. For example, &lt;a href=&quot;https://topiary.tweag.io/book/guides/yann-tutorial.html&quot;&gt;Yann’s step-by-step
guides&lt;/a&gt; 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.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How-to guides&lt;/strong&gt;, for readers who want to accomplish a specific goal.
&lt;a href=&quot;https://topiary.tweag.io/book/guides/adding-a-new-language.html&quot;&gt;“Adding a new language”&lt;/a&gt; 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.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Explanation&lt;/strong&gt;, for those who need a deeper understanding. For
example, &lt;a href=&quot;https://topiary.tweag.io/book/getting-started/on-tree-sitter.html&quot;&gt;“Tree-sitter and its queries”&lt;/a&gt; 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.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reference&lt;/strong&gt;, which describes what exists and how it behaves. Our
&lt;a href=&quot;https://topiary.tweag.io/book/reference/capture-names/index.html&quot;&gt;capture names chapter&lt;/a&gt; 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.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h2 id=&quot;when-you-have-varied-audiences&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#when-you-have-varied-audiences&quot;&gt;&lt;/a&gt;When you have varied audiences&lt;/h2&gt;
&lt;div class=&quot;lyrics&quot;&gt;
&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://www.tweag.io/static/7af1ae3c9dc85afd82ec8bc9200ce7de/50ac3/snoop-2.png&quot; rel=&quot;noopener&quot; style=&quot;display: block;&quot; target=&quot;_blank&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;display: block;&quot;&gt;&lt;/span&gt;
  &lt;img alt=&quot;Snoop Dogg&quot; class=&quot;gatsby-resp-image-image&quot; src=&quot;https://www.tweag.io/static/7af1ae3c9dc85afd82ec8bc9200ce7de/50ac3/snoop-2.png&quot; style=&quot;width: 100%; height: 100%; margin: 0; vertical-align: middle;&quot; title=&quot;Snoop Dogg&quot; /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Doc it like it’s hot&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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 &lt;a href=&quot;https://en.wikipedia.org/wiki/Omics&quot;&gt;omics&lt;/a&gt; data acquisition tool for a pharmaceutical
client’s computational biology needs.&lt;/p&gt;
&lt;p&gt;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!&lt;/p&gt;
&lt;p&gt;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:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;technical manual&lt;/strong&gt;, 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.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;developer manual&lt;/strong&gt;, 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!&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;user manual&lt;/strong&gt; sat between the two, covering key concepts, how-to
guides and troubleshooting. &lt;a href=&quot;https://diataxis.fr&quot;&gt;Diátaxis&lt;/a&gt; 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.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;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
&lt;a href=&quot;https://en.wikipedia.org/wiki/Strange_Case_of_Dr_Jekyll_and_Mr_Hyde&quot;&gt;Strange Case of Dr. Jekyll and Mr. Hyde&lt;/a&gt;: An external
collaborator’s data arrives from Dr. Jekyll’s lab, making oblique
references to the novella throughout, and ultimately identifying the
&lt;code class=&quot;language-text&quot;&gt;evil-transcriptome&lt;/code&gt; for downstream analysis.&lt;/p&gt;
&lt;p&gt;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
&lt;a href=&quot;https://en.wikipedia.org/wiki/Transportation_theory_(psychology)&quot;&gt;through narrative&lt;/a&gt; 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.&lt;/p&gt;
&lt;p&gt;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 &lt;abbr title=&quot;National Center for Biotechnology Information&quot;&gt;NCBI&lt;/abbr&gt; 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!&lt;/p&gt;
&lt;h2 id=&quot;when-you-need-to-have-clarity&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#when-you-need-to-have-clarity&quot;&gt;&lt;/a&gt;When you need to have clarity&lt;/h2&gt;
&lt;div class=&quot;lyrics&quot;&gt;
&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://www.tweag.io/static/77a4393a83eda677c52710aa429a9022/39e45/snoop-3.png&quot; rel=&quot;noopener&quot; style=&quot;display: block;&quot; target=&quot;_blank&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 100%; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img alt=&quot;Snoop Dogg&quot; class=&quot;gatsby-resp-image-image&quot; src=&quot;https://www.tweag.io/static/77a4393a83eda677c52710aa429a9022/39e45/snoop-3.png&quot; style=&quot;width: 100%; height: 100%; margin: 0; vertical-align: middle;&quot; title=&quot;Snoop Dogg&quot; /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Doc it like it’s hot&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;The previous case study included a developer manual, but my final
example? That’s &lt;em&gt;all&lt;/em&gt; developer; front to back. &lt;a href=&quot;https://crates.io/crates/cardano-scrawls&quot;&gt;Scrawls&lt;/a&gt; is a Rust
library implementing a verifiable file format for &lt;a href=&quot;https://cardano.org&quot;&gt;Cardano&lt;/a&gt; ledger
state, as an independent implementation alongside a &lt;a href=&quot;https://github.com/tweag/cardano-cls&quot;&gt;Haskell
reference&lt;/a&gt;. Its users are Rust developers pulling in the
crate as a dependency, so the documentation strategy needed to reflect
that.&lt;/p&gt;
&lt;p&gt;In Rust, the idiomatic answer to this is &lt;a href=&quot;https://doc.rust-lang.org/rustdoc&quot;&gt;rustdoc&lt;/a&gt;: in-band
documentation that lives alongside the types, functions and invariants
it describes. Then, while there is still a &lt;code class=&quot;language-text&quot;&gt;README.md&lt;/code&gt;, 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.&lt;/p&gt;
&lt;p&gt;Docstrings ain’t new, of course — &lt;a href=&quot;https://www.doxygen.nl&quot;&gt;Doxygen&lt;/a&gt; has been around since the
’90s — but Rust’s ecosystem raises the bar. Between &lt;a href=&quot;https://docs.rs&quot;&gt;docs.rs&lt;/a&gt;
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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h2 id=&quot;document-your-code-ma&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#document-your-code-ma&quot;&gt;&lt;/a&gt;Document your code, ma&lt;/h2&gt;
&lt;div class=&quot;lyrics&quot;&gt;
&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://www.tweag.io/static/d4779a85b30d02db57f93f6d6205dafb/5ff7e/pharrell-2.png&quot; rel=&quot;noopener&quot; style=&quot;display: block;&quot; target=&quot;_blank&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 100%; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img alt=&quot;Pharrell&quot; class=&quot;gatsby-resp-image-image&quot; src=&quot;https://www.tweag.io/static/d4779a85b30d02db57f93f6d6205dafb/5ff7e/pharrell-2.png&quot; style=&quot;width: 100%; height: 100%; margin: 0; vertical-align: middle;&quot; title=&quot;Pharrell&quot; /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;That’s how you get ahizzead&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;That’s the shift I want to put you on to. Documentation ain’t a tax you
pay for writing code; it &lt;em&gt;is&lt;/em&gt; 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.&lt;/p&gt;
&lt;p&gt;Now if documentation alongside code is good, then documentation &lt;em&gt;before&lt;/em&gt;
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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;So now, just like my man S-to the N-to the double O-P, you too can
say…&lt;/p&gt;
&lt;div class=&quot;lyrics&quot;&gt;
&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://www.tweag.io/static/f0d351ee79b57822b54a1ff8abcdc0d0/d4635/snoop-4.png&quot; rel=&quot;noopener&quot; style=&quot;display: block;&quot; target=&quot;_blank&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;display: block;&quot;&gt;&lt;/span&gt;
  &lt;img alt=&quot;Snoop Dogg&quot; class=&quot;gatsby-resp-image-image&quot; src=&quot;https://www.tweag.io/static/f0d351ee79b57822b54a1ff8abcdc0d0/d4635/snoop-4.png&quot; style=&quot;width: 100%; height: 100%; margin: 0; vertical-align: middle;&quot; title=&quot;Snoop Dogg&quot; /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I got a Rollie on my arm and I’m pourin’ Chandon &lt;br /&gt;
And I write the best docs, ‘cause I got it goin’ on.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/div&gt;

&lt;section class=&quot;acknowledgements&quot;&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;/section&gt;</description>
	<pubDate>Thu, 16 Apr 2026 00:00:00 +0000</pubDate>
</item>

</channel>
</rss>
