<?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>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;0&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;http://www.cs.ox.ac.uk/people/jeremy.gibbons/publications/linear.ps.gz&quot;&gt;http://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>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 April 2026 for PenroseKiteDart version 1.8)&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; using a two dimensional vector to indicate the length and direction of the join edge of the half-tile (from the &lt;code&gt;originV&lt;/code&gt; to the &lt;code&gt;oppV&lt;/code&gt;), thus 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 derive vectors for other edges of a half-tile piece from its join edge vector. 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;darawjPiece&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 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.&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 and rotated.&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, rotated but without the labels themselves being rotated. We can simply convert the &lt;code&gt;Tgraph&lt;/code&gt; to a &lt;code&gt;VPatch&lt;/code&gt;, and rotate 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 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 string&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-complete 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>Sun, 26 Apr 2026 16:11:03 +0000</pubDate>
</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>
<item>
	<title>Haskell Interlude: 80: POPL 2026 - Part 1</title>
	<guid isPermaLink="false">Buzzsprout-18995056</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: undergrad funding and participation, the behind the scenes of AV, choreographic programming, quantum languages, conference catering, and the joy of theory. And at one point, you’ll even hear us get kicked out the venue mid interview. Enjoy!&lt;/p&gt;</description>
	<pubDate>Mon, 13 Apr 2026 05:00:00 +0000</pubDate>
        <enclosure url="https://www.buzzsprout.com/1817535/episodes/18995056-80-popl-2026-part-1.mp3" length="30930364" type="audio/mpeg"/>
</item>
<item>
	<title>Philip Wadler: Wet Sidewalks and Odd Numbers</title>
	<guid isPermaLink="false">tag:blogger.com,1999:blog-9757377.post-3700094658306171494</guid>
	<link>https://wadler.blogspot.com/2026/04/wet-sidewalks-and-odd-numbers.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/AVvXsEij_CIKOMnrRH3Aa4_K7emngkVT1D39qIa_4v8foa-HMuWLPQMR8BL7kHbLbO1luZz7XK_8WKvHatJctvdSqo6LBXgKtENq55oDuLCgCBD8HdFXlup_VPR66psESR0Kjh9YQh6R0FXNPfRmBqWg5K33tmPdM28ArIxzvbEtC2VWHMpyFV2OsUwR&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; height=&quot;334&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEij_CIKOMnrRH3Aa4_K7emngkVT1D39qIa_4v8foa-HMuWLPQMR8BL7kHbLbO1luZz7XK_8WKvHatJctvdSqo6LBXgKtENq55oDuLCgCBD8HdFXlup_VPR66psESR0Kjh9YQh6R0FXNPfRmBqWg5K33tmPdM28ArIxzvbEtC2VWHMpyFV2OsUwR=w640-h334&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Phil Crissman &lt;a href=&quot;https://philcrissman.net/posts/wet-sidewalks-and-odd-numbers/&quot;&gt;explains&lt;/a&gt; Propositions as Types with a dialogue between Achilles and the Tortoise, in the style of Douglas Hofstadter (who in turn was inspired by Lewis Carrol). Lambda Man makes an appearance.&lt;p&gt;&lt;/p&gt;</description>
	<pubDate>Thu, 09 Apr 2026 15:22:05 +0000</pubDate>
	<author>noreply@blogger.com (Philip Wadler)</author>
</item>
<item>
	<title>Russell O'Connor: Nash Equilibrium for Terminal Maneuvers</title>
	<guid isPermaLink="true">https://r6.ca/blog/20260402T135216Z.html</guid>
	<link>https://r6.ca/blog/20260402T135216Z.html</link>
	<description>&lt;p&gt;Last year Ethan Heilman wrote about a simple game he calls &lt;a href=&quot;https://www.ethanheilman.com/x/31/index.html&quot; title=&quot;Missile vs. Laser: The Game of Terminal Maneuvers&quot;&gt;Terminal Maneuvers&lt;/a&gt;.
This game simulates a missile attacking an interstellar ship.
The ship has a laser defence system.
One player controls the missile, and the other player controls the laser.
If the missile hits the ship, Missile wins.
If the laser hits the missile, the missile is destroyed and Laser wins.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

&lt;/p&gt;&lt;p&gt;Continuing with linear programming, we can fill out the  table for the probability of winning for Round 4.

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

&lt;/p&gt;&lt;p&gt;Continuing this way, we can work backwards and compute probability tables for all the rounds until we reach round 1.

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

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

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

# if you still have to rely on dynamically generated archives instead of releases
rewrite github.com/([^/]+)/([^/]+)/archive/(.+).(tar.gz|zip) artifacts.my-company.com/artifactory/github-releases-mirror/$1/$2/archive/$3.$4&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;However, support for using Bazel’s downloader needs to be enabled in Bazel rulesets by their authors.
For instance, in &lt;code class=&quot;language-text&quot;&gt;rules_python&lt;/code&gt;, the &lt;a href=&quot;https://github.com/bazel-contrib/rules_python/blob/main/docs/pypi/download.md#bazel-downloader-and-multi-platform-wheel-hub-repository&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;pip&lt;/code&gt; extension&lt;/a&gt;
now supports pulling information from a PyPI compatible mirror
which means that the Bazel downloader can be used for downloading Python wheels.&lt;/p&gt;
&lt;p&gt;Take a look at some downloader configurations used in other projects
(e.g., &lt;a href=&quot;https://github.com/monogon/monogon/blob/main/build/bazel/bazel_downloader.cfg&quot;&gt;1&lt;/a&gt;, &lt;a href=&quot;https://github.com/bazelbuild/bazel/blob/master/bazel_downloader.cfg&quot;&gt;2&lt;/a&gt;, &lt;a href=&quot;https://github.com/google/tensorstore/blob/master/bazel/rewrite.config&quot;&gt;3&lt;/a&gt;)
to explore how others set up access to external resources
and learn the nuances of the configuration declaration syntax.&lt;/p&gt;
&lt;h3 id=&quot;blocking-network-requests&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#blocking-network-requests&quot;&gt;&lt;/a&gt;Blocking network requests&lt;/h3&gt;
&lt;p&gt;Additional control of network access can be achieved by blocking some network requests in CI agents
using custom firewall rules or other tools of that nature.
However, as mentioned earlier, Bazel’s downloader configuration can only rewrite or block requests that Bazel
is aware of.
This means that not all network traffic in a Bazel build is Bazel-managed traffic.&lt;/p&gt;
&lt;p&gt;To illustrate this, let’s declare a dependency on the &lt;a href=&quot;https://github.com/bazelbuild/bazel-central-registry/tree/5978cdffb9fdb566dc0eca759f1aa57cb3604914/modules/gawk/5.3.2&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;gawk&lt;/code&gt; binary&lt;/a&gt;.
When running &lt;code class=&quot;language-text&quot;&gt;gawk&lt;/code&gt;, its &lt;a href=&quot;https://github.com/bazelbuild/bazel-central-registry/blob/5978cdffb9fdb566dc0eca759f1aa57cb3604914/modules/gawk/5.3.2/source.json#L2&quot;&gt;sources&lt;/a&gt; are going to be fetched from the &lt;a href=&quot;https://ftp.gnu.org/gnu/gawk/gawk-5.3.2.tar.xz&quot;&gt;GNU FTP server&lt;/a&gt;.
Let’s also add a &lt;code class=&quot;language-text&quot;&gt;genrule&lt;/code&gt; that will download an archive from the same FTP server:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# MODULE.bazel&lt;/span&gt;
bazel_dep&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;gawk&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; version &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;5.3.2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

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

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

# use the original location if the mirror is down
rewrite (.*) $1&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For a completely custom solution, take a look at the &lt;a href=&quot;https://github.com/monogon/monogon/tree/main/build/mirror_proxy&quot;&gt;Bazel downloader mirror from Monogon&lt;/a&gt;
which can be used to mirror Bazel dependencies to a cloud bucket storage such as S3 or GCS.
Bazel’s &lt;a href=&quot;https://github.com/bazelbuild/remote-apis&quot;&gt;remote asset API&lt;/a&gt; lets you use an existing remote cache
(content-addressable storage: CAS) as a downloader cache as well.
The cache provider service needs to support it, but many existing solutions, both commercial and open-source ones, are compatible.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://bazel.build/reference/command-line-reference#common_options-flag--experimental_remote_downloader&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;--experimental_remote_downloader&lt;/code&gt; flag&lt;/a&gt;
can be specified to provide a Remote Asset API endpoint URI to be used as a remote download proxy.
To get started, consider using &lt;a href=&quot;https://github.com/buchgr/bazel-remote&quot;&gt;bazel-remote&lt;/a&gt;, which has out-of-the-box support for this use case.
Make sure to provide the &lt;a href=&quot;https://bazel.build/rules/lib/repo/http#http_archive-sha256&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;sha256&lt;/code&gt;&lt;/a&gt; for the assets to fetch
so that they can be cached just like any other CAS object.
A remote caching service will automatically download the assets from the URL if they are found in the CAS and cache it thereafter.&lt;/p&gt;
&lt;p&gt;Bazel 9 adds support for &lt;a href=&quot;https://github.com/bazelbuild/bazel/discussions/27509&quot;&gt;remote repository caches&lt;/a&gt;
which make Bazel builds (at least those requiring previously cached assets) extra resilient to external access issues.
During outages of external hosting services, those organizations that didn’t have a central repository manager
where repository rules artifacts could be stored had to extract files from cache directories on local developer machines
and save them to an accessible location within the internal network.&lt;/p&gt;
&lt;p&gt;Now these artifacts will be saved into a remote cache similarly to build output results.
To confirm that your remote repository cache works as expected,
you can use the &lt;a href=&quot;https://bazel.build/reference/command-line-reference#common_options-flag--repository_disable_download&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;--repository_disable_download&lt;/code&gt; flag&lt;/a&gt;
after doing a clean build (which should succeed as it will reuse the remote cache entries uploaded in the previous build).&lt;/p&gt;
&lt;h3 id=&quot;chaos-testing&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#chaos-testing&quot;&gt;&lt;/a&gt;Chaos testing&lt;/h3&gt;
&lt;p&gt;Finally, instead of waiting for the next GitHub outage, you can test your resilience
by intentionally breaking access to certain external hosts.
In a staging CI environment, temporarily block access to key external systems with firewall rules and verify
that your mirrors and caches are used as expected, builds either still succeed,
or fail fast with clear error messages, and your runbooks are correct and sufficient.&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;Bazel projects often depend on external services in subtle ways,
and any instability or change in those services can break otherwise healthy builds.
You can significantly improve build reliability by making all downloads explicit and verifiable,
routing them through managed infrastructure,
and tightening how and when network access is allowed.
Resilient Bazel builds come from treating external dependencies as first‑class operational risks
and turning unpredictable third‑party failures into controlled, recoverable events.&lt;/p&gt;</description>
	<pubDate>Thu, 02 Apr 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Well-Typed.Com: Second pre-release of hs-bindgen</title>
	<guid isPermaLink="false">http://www.well-typed.com/blog/2026/03/hs-bindgen-alpha2</guid>
	<link>https://well-typed.com/blog/2026/03/hs-bindgen-alpha2</link>
	<description>&lt;p&gt;With heartfelt thanks to the many people who have already tried &lt;code&gt;hs-bindgen&lt;/code&gt; and
given us feedback, we have steadily been working towards the first official
release (see &lt;a href=&quot;https://github.com/well-typed/hs-bindgen/tree/release-0.1-alpha2?tab=readme-ov-file#contributors&quot;&gt;Contributors&lt;/a&gt; for the full list). In case you missed
the &lt;a href=&quot;https://well-typed.com/blog/2026/02/hs-bindgen-alpha/&quot;&gt;announcement of the first alpha&lt;/a&gt;, &lt;code&gt;hs-bindgen&lt;/code&gt; is a
tool for automatic construction of Haskell bindings for C libraries: just point
it at a C header and let it handle the rest. Because we have fixed some critical
bugs in this alpha release, but we’re not quite ready yet for the first full
official release, we have &lt;a href=&quot;https://github.com/well-typed/hs-bindgen/releases/tag/release-0.1-alpha2&quot;&gt;tagged a second alpha release&lt;/a&gt;. In the
remainder of this blog post we will briefly highlight the most important
changes; please refer to the &lt;code&gt;CHANGELOG.md&lt;/code&gt; of
&lt;a href=&quot;https://github.com/well-typed/hs-bindgen/blob/release-0.1-alpha2/hs-bindgen/CHANGELOG.md&quot;&gt;hs-bindgen&lt;/a&gt; and of
&lt;a href=&quot;https://github.com/well-typed/hs-bindgen/blob/release-0.1-alpha2/hs-bindgen-runtime/CHANGELOG.md&quot;&gt;hs-bindgen-runtime&lt;/a&gt; for the full list of changes, as well as
for migration hints where we have introduced some minor backwards incompatible
changes.&lt;/p&gt;

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

&lt;p&gt;The GHC developers are very pleased to announce the release of GHC 9.12.4.
Binary distributions, source distributions, and documentation are available at
&lt;a href=&quot;https://downloads.haskell.org/ghc/9.12.4&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.4 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;&lt;p&gt;Fixed a critical code generation regression where sub-word division produced
incorrect results (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26711&quot;&gt;#26711&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26668&quot;&gt;#26668&lt;/a&gt;), similar to the bug fixed in 9.12.2&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Numerous fixes for register allocation bugs, preventing data corruption
when spilling and reloading registers
(&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;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fixes for several compiler crashes, including issues with CSE (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/25468&quot;&gt;#25468&lt;/a&gt;),
and the simplifier(&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26681&quot;&gt;#26681&lt;/a&gt;), implicit parameters (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26451&quot;&gt;#26451&lt;/a&gt;), and the type-class
specialiser (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26682&quot;&gt;#26682&lt;/a&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&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;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fixed LLVM backend miscompilation of bit manipulation operations
(&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/20645&quot;&gt;#20645&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26065&quot;&gt;#26065&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26109&quot;&gt;#26109&lt;/a&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&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;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&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;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Improvements to determinism of compiler output (&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;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fixes for eventlog shutdown deadlocks (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26573&quot;&gt;#26573&lt;/a&gt;)
and lost wakeups in the RTS (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26324&quot;&gt;#26324&lt;/a&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&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;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fixes for the bytecode compiler, PPC native code generator, and Wasm backend&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The runtime linker now supports COMMON symbols (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/6107&quot;&gt;#6107&lt;/a&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Improved backtrace support: backtraces for &lt;code&gt;error&lt;/code&gt; exceptions are now
evaluated at throw time&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;NamedDefaults&lt;/code&gt; now correctly requires the class to be standard or have an
in-scope default declaration, and handles poly-kinded classes (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/25775&quot;&gt;#25775&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/25778&quot;&gt;#25778&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/25882&quot;&gt;#25882&lt;/a&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;… and many more&lt;/p&gt;&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.12/docs/users_guide/9.12.4-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;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>Fri, 27 Mar 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Chris Smith 2: Athena Loses a Bet</title>
	<guid isPermaLink="false">https://medium.com/p/539cb2f40215</guid>
	<link>https://cdsmithus.medium.com/athena-loses-a-bet-539cb2f40215?source=rss-18bd5acaea78------2</link>
	<description>&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;https://cdn-images-1.medium.com/max/1024/1*weyULcS-xuFt4Akf6f4vpA.png&quot; /&gt;&lt;/figure&gt;&lt;p&gt;Athena and Ares argue over human nature, and agree to test three great minds of the age.&lt;/p&gt;&lt;p&gt;First, they approach Aristotle in the Lyceum and propose a bargain. “If you ask it of us, the one you love most in the world will perish, but you will be made rich beyond imagining.” Aristotle barely hesitates. “No,” he says. “To destroy the very purpose of living for the sake of the mere means is the mark of a man who lacks wisdom.”&lt;/p&gt;&lt;p&gt;Next, they approach Plato, finding him pacing in an olive grove of his Academy. They offer the same proposal. “I decline,” he says. “Love allows us to glimpse the ideal of pure beauty, but wealth is an anchor to the material world.”&lt;/p&gt;&lt;p&gt;Finally, they approach Socrates, wandering barefoot in the crowded dusty stalls of the Agora. The gods approach him with the same bargain: “If you ask it of us, Xanthippe, whom you love most in the world, will perish — ”&lt;/p&gt;&lt;p&gt;“I ask it!” he blurts out.&lt;/p&gt;&lt;p&gt;Athena blinks. “You did not even hear the rest. We were going to say you would be given wealth beyond measure.”&lt;/p&gt;&lt;p&gt;Socrates shrugs. “Keep it. This was never about money.”&lt;/p&gt;&lt;p&gt;Millenia later, Athena is still smarting from losing the bet, and she demands a rematch. Searching for another Greek philosopher, they instead find a middle aged woman writing a novel called &lt;em&gt;Atlas Shrugged&lt;/em&gt;. She’s a philosopher, and Atlas was Greek, so that’s close enough.&lt;/p&gt;&lt;p&gt;“If you ask it,” Athena says to her, “we will make you wealthy beyond measure, but then in return, your true love will be taken from you.”&lt;/p&gt;&lt;p&gt;The woman looks up, bored, and asks “Why give me the money if you’re just going to take it right back?”&lt;/p&gt;&lt;img alt=&quot;&quot; height=&quot;1&quot; src=&quot;https://medium.com/_/stat?event=post.clientViewed&amp;amp;referrerSource=full_rss&amp;amp;postId=539cb2f40215&quot; width=&quot;1&quot; /&gt;</description>
	<pubDate>Wed, 25 Mar 2026 18:58:04 +0000</pubDate>
</item>
<item>
	<title>Haskell Interlude: 79: Peter Thiemann</title>
	<guid isPermaLink="false">Buzzsprout-18853260</guid>
	<link></link>
	<description>&lt;p&gt;Peter is a professor at the University of Freiburg, and he was doing functional programming right when Haskell got started. So naturally we asked him about the early days of Haskell, and how from the start Peter pushed the envelope on what you could do with the type system and specifically with the type classes, from early web programming to program generation to session types. Come with us on a trip down memory lane!&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
	<pubDate>Sun, 22 Mar 2026 12:00:00 +0000</pubDate>
        <enclosure url="https://www.buzzsprout.com/1817535/episodes/18853260-79-peter-thiemann.mp3" length="47963255" type="audio/mpeg"/>
</item>
<item>
	<title>Well-Typed.Com: Haskell ecosystem activities report: December 2025â€“February 2026</title>
	<guid isPermaLink="false">http://www.well-typed.com/blog/2026/03/haskell-ecosystem-report-q1-2026</guid>
	<link>https://well-typed.com/blog/2026/03/haskell-ecosystem-report-q1-2026</link>
	<description>&lt;p&gt;This is the thirtieth edition of our Haskell ecosystem activities report,
which describes the work Well-Typed are doing on GHC, Cabal, HLS and other parts
of the core Haskell toolchain. The current edition covers roughly the months of
December 2025 to February 2026.&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;team&quot;&gt;Team&lt;/h2&gt;

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

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

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

&lt;p&gt;It turns out, yes!  Or rather, maybe!&lt;/p&gt;

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

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

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

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

&lt;p&gt;The GHC developers are very pleased to announce the availability
of the release candidate for GHC 9.12.4. Binary distributions, source
distributions, and documentation are available at &lt;a href=&quot;https://downloads.haskell.org/ghc/9.12.4-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.12.4 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 critical code generation regression where sub-word division produced
incorrect results (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26711&quot;&gt;#26711&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26668&quot;&gt;#26668&lt;/a&gt;), similar to the bug fixed in 9.12.2&lt;/li&gt;
&lt;li&gt;Numerous fixes for register allocation bugs, preventing data corruption
when spilling and reloading registers
(&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;/li&gt;
&lt;li&gt;Fixes for several compiler crashes, including issues with
CSE (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/25468&quot;&gt;#25468&lt;/a&gt;), SetLevels (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26681&quot;&gt;#26681&lt;/a&gt;),
implicit parameters (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26451&quot;&gt;#26451&lt;/a&gt;), and the type-class specialiser (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26682&quot;&gt;#26682&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 LLVM backend miscompilation of bit manipulation operations
(&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/20645&quot;&gt;#20645&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26065&quot;&gt;#26065&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26109&quot;&gt;#26109&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;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;Improvements to determinism of compiler output (&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;/li&gt;
&lt;li&gt;Fixes for eventlog shutdown deadlocks (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26573&quot;&gt;#26573&lt;/a&gt;)
and lost wakeups in the RTS (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26324&quot;&gt;#26324&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;Fixes for the bytecode compiler, PPC native code generator, and Wasm backend&lt;/li&gt;
&lt;li&gt;The runtime linker now supports COMMON symbols (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/6107&quot;&gt;#6107&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Improved backtrace support: backtraces for &lt;code&gt;error&lt;/code&gt; exceptions are now
evaluated at throw time&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NamedDefaults&lt;/code&gt; now correctly requires the class to be standard or have an
in-scope default declaration, and handles poly-kinded classes (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/25775&quot;&gt;#25775&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/25778&quot;&gt;#25778&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/25882&quot;&gt;#25882&lt;/a&gt;)&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;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/-/blob/ghc-9.12/docs/users_guide/9.12.4-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 26 March 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>Fri, 13 Mar 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Christoph Breitkopf: Functional Valhalla?</title>
	<guid isPermaLink="false">tag:blogger.com,1999:blog-8897180777295067814.post-6620848665537137843</guid>
	<link>http://bokesan.blogspot.com/2026/03/functional-valhalla.html</link>
	<description>&lt;p&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #1a1a1a;&quot;&gt;Pointer-rich data layouts lead to suboptimal performance on modern hardware. For an excellent introduction to this, see the article&lt;/span&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #1a1a1a;&quot;&gt; &lt;/span&gt;&lt;a href=&quot;https://openjdk.org/projects/valhalla/design-notes/state-of-valhalla/01-background&quot; style=&quot;color: #1a1a1a;&quot;&gt;The Road to Valhalla&lt;/a&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #1a1a1a;&quot;&gt;. While it is specifically about Java, many parts of the article also apply to other languages. To summarize some of the key points of the article:&lt;/span&gt;&lt;/p&gt;&lt;ul style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin-top: 1em; padding-left: 1.7em;&quot;&gt;&lt;li&gt;In 1990, a main memory fetch was about as expensive as an arithmetic operation. Now, it might be a hundred times slower.&lt;/li&gt;&lt;li&gt;A pointer-rich data layout involving indirections between data at different locations is not ideal for today’s hardware.&lt;/li&gt;&lt;li&gt;A language should make flat (cache-efficient) and dense (memory-efficient) memory layouts possible without compromising abstraction or type safety.&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;&quot;&gt;Consider a vector of records (or tuples, structures, product types - I’ll stay with “record” in this article). A pointer-rich layout has each record allocated separately in the heap, with a vector containing pointers to the records. For example, given a “Point” record of two numbers:&lt;/p&gt;&lt;p style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;&quot;&gt;&lt;img alt=&quot;pikchr diagram&quot; height=&quot;336&quot; width=&quot;491&quot; /&gt;&lt;/p&gt;&lt;p style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;&quot;&gt;The flat and dense layout has the records directly in the array:&lt;/p&gt;&lt;p style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;&quot;&gt;&lt;img alt=&quot;pikchr diagram&quot; height=&quot;88&quot; width=&quot;647&quot; /&gt;&lt;/p&gt;&lt;p style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;&quot;&gt;(Note that there is another flat layout, namely, using one vector per field of the record. This is better suited to instruction-level parallelism or specialized hardware (e.g., GPUs), especially when the record fields have different sizes. But it is less suited for general-purpose computing, as reading a single vector element requires one memory access per field, whereas the “vector of records” layout above requires only one access per record. Such a layout can be easily implemented in any language that has arrays of native types, whether in the language itself or in a library (e.g., OCaml’s Owl library). Thus, in this article, I will only consider the “array of records” layout above.)&lt;/p&gt;&lt;h2 id=&quot;functional-language-considerations&quot; style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin-top: 1.4em;&quot;&gt;Functional language considerations&lt;/h2&gt;&lt;p style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;&quot;&gt;Things should be much easier in functional languages than in Java: we have purity, referential transparency, and everything is a value. So it should be simple enough to store these values in memory in their native representation. But there are reasons that that is often not the case in practice:&lt;/p&gt;&lt;ul style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin-top: 1em; padding-left: 1.7em;&quot;&gt;&lt;li&gt;Lazyness: a value can be a computation that produces a value only when needed.&lt;/li&gt;&lt;li&gt;Layout polymorphism: unless we replicate the code for every type (as, for example, Rust does), we need to be able to store every possible value in the same kind of slot.&lt;/li&gt;&lt;li&gt;Dynamically typed languages require type information at runtime.&lt;/li&gt;&lt;li&gt;Functional languages often have automatic memory management, which may require runtime type information.&lt;/li&gt;&lt;li&gt;Many of our languages are not purely functional, but contain impure features.&lt;/li&gt;&lt;li&gt;Pure languages often lack traditional vectors or arrays, since making them perform well in immutable code is not easy.&lt;/li&gt;&lt;li&gt;Historical reasons: Graph reduction was a common implementation technique for lazy languages, and graphs involve pointers.&lt;/li&gt;&lt;li&gt;Implementation restrictions: not being mainstream, fewer resources are devoted to implementation and optimization.&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;&quot;&gt;Many implementations can not even lay out native types flat in records, so a Point record of IEEE 754 double-precision numbers may actually look like this in memory:&lt;/p&gt;&lt;p style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;&quot;&gt;&lt;img alt=&quot;pikchr diagram&quot; height=&quot;232&quot; width=&quot;330&quot; /&gt;&lt;/p&gt;&lt;h2 id=&quot;the-very-short-list&quot; style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin-top: 1.4em;&quot;&gt;The (very short) List&lt;/h2&gt;&lt;p style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;&quot;&gt;So, given a record type, which functional languages allow a collection of values of that type to have a flat, linear memory layout? The number of programming languages that claim to be “functional” is huge, so the ones listed here are just a selection based on my preferences - mainly languages that allow that layout, and some I have some experience with and can speculate on how easy or hard it would be to add that as a library or extension.&lt;/p&gt;&lt;p style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;&quot;&gt;Since the Point record can be misleading in its simplicity when it comes to the question of whether the functionality could be implemented as a library, I’ll point out that there are records where the layout is a bit more interesting:&lt;/p&gt;&lt;ul style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin-top: 1em; padding-left: 1.7em;&quot;&gt;&lt;li&gt;Records containing different types with different storage sizes, for example, one 64-bit float and one 32-bit integer. On most architectures, this will require 4 bytes of padding between elements.&lt;/li&gt;&lt;li&gt;Records containing native values along with something that has to be represented as a pointer, for example, a reference-type or a lazy value. In a flat layout, this means that every nth element will be a pointer, requiring special support from the memory management system, either by providing layout information or by using a conservative GC that treats everything as a potential pointer.&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;pure-languages&quot; style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin-top: 1.4em;&quot;&gt;Pure languages:&lt;/h3&gt;&lt;h4 id=&quot;clean&quot; style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin-top: 1.4em;&quot;&gt;Clean&lt;/h4&gt;&lt;p style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;&quot;&gt;Yes: Clean has unboxed arrays of records in the base language.&lt;/p&gt;&lt;p style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;&quot;&gt;Caveat: it does not have integer types of specific sizes and only one floating-point type, making it harder to reduce memory usage by using the smallest type just large enough to support the required value range. It seems possible to implement such types in a library (the &lt;a href=&quot;http://bokesan.blogspot.de/feeds/posts/default/-/gitlab.com/mtask/&quot; style=&quot;color: #1a1a1a;&quot;&gt;mTask system&lt;/a&gt; does that).&lt;/p&gt;&lt;h4 id=&quot;futhark&quot; style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin-top: 1.4em;&quot;&gt;Futhark&lt;/h4&gt;&lt;p style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;&quot;&gt;No. Futhark does not intend to be a general-purpose language, so this is not surprising.&lt;/p&gt;&lt;p style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;&quot;&gt;I mention it here because it &lt;em&gt;does have arrays of records,&lt;/em&gt; but, since it targets GPUs and related hardware, it uses the “record of arrays” layout mentioned above.&lt;/p&gt;&lt;h4 id=&quot;haskell&quot; style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin-top: 1.4em;&quot;&gt;Haskell&lt;/h4&gt;&lt;p style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;&quot;&gt;Yes. Not in the base language, but there is library support via &lt;a href=&quot;https://hackage-content.haskell.org/package/vector-0.13.2.0/docs/Data-Vector-Unboxed.html&quot; style=&quot;color: #1a1a1a;&quot;&gt;Data.Vector.Unboxed&lt;/a&gt;. Types that implement the &lt;code&gt;Unbox&lt;/code&gt; type class can be used in these vectors. Many basic types and tuples have an &lt;code&gt;Unbox&lt;/code&gt; instance. However, when you care about efficiency, you probably do not want to use tuples but rather a data type with strict fields, i.e., not:&lt;/p&gt;&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot; style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px; overflow: auto;&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot; style=&quot;background-color: transparent; margin: 0px; overflow: visible;&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb1-1&quot; style=&quot;color: inherit; display: inline-block; line-height: 1.25; text-decoration: inherit;&quot;&gt;&lt;a href=&quot;http://bokesan.blogspot.de/feeds/posts/default/-/Haskell#cb1-1&quot; style=&quot;color: #1a1a1a;&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot; style=&quot;color: #007020; font-weight: bold;&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot; style=&quot;color: #902000;&quot;&gt;Point&lt;/span&gt; &lt;span class=&quot;ot&quot; style=&quot;color: #007020;&quot;&gt;=&lt;/span&gt; (&lt;span class=&quot;dt&quot; style=&quot;color: #902000;&quot;&gt;Double&lt;/span&gt;, &lt;span class=&quot;dt&quot; style=&quot;color: #902000;&quot;&gt;Double&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;&quot;&gt;but:&lt;/p&gt;&lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot; style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px; overflow: auto;&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot; style=&quot;background-color: transparent; margin: 0px; overflow: visible;&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb2-1&quot; style=&quot;color: inherit; display: inline-block; line-height: 1.25; text-decoration: inherit;&quot;&gt;&lt;a href=&quot;http://bokesan.blogspot.de/feeds/posts/default/-/Haskell#cb2-1&quot; style=&quot;color: #1a1a1a;&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot; style=&quot;color: #007020; font-weight: bold;&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot; style=&quot;color: #902000;&quot;&gt;Point&lt;/span&gt; &lt;span class=&quot;ot&quot; style=&quot;color: #007020;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot; style=&quot;color: #902000;&quot;&gt;Point&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;color: #666666;&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;dt&quot; style=&quot;color: #902000;&quot;&gt;Double&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;color: #666666;&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;dt&quot; style=&quot;color: #902000;&quot;&gt;Double&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;&quot;&gt;Writing an &lt;code&gt;Unbox&lt;/code&gt; instance for such a type is not trivial. The &lt;a href=&quot;https://hackage.haskell.org/package/vector-th-unbox-0.2.2/docs/Data-Vector-Unboxed-Deriving.html&quot; style=&quot;color: #1a1a1a;&quot;&gt;vector-th-unbox library&lt;/a&gt; makes it easier, but requires Template Haskell. Unboxed vectors are implemented by marshalling the values to byte arrays, so records with pointer fields are not supported.&lt;/p&gt;&lt;h3 id=&quot;impure-languages&quot; style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin-top: 1.4em;&quot;&gt;Impure Languages&lt;/h3&gt;&lt;h4 id=&quot;f&quot; style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin-top: 1.4em;&quot;&gt;F#&lt;/h4&gt;&lt;p style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;&quot;&gt;Yes, even records with pointer fields. Records have structural equality, and you can use structs or the &lt;code&gt;[&amp;lt;Struct&amp;gt;]&lt;/code&gt; attribute to get a flat layout.&lt;/p&gt;&lt;hr style=&quot;background-color: #fdfdfd; border-bottom: none; border-left: none; border-right: none; border-top-color: rgb(26, 26, 26); border-top-style: solid; height: 1px; margin: 1em 0px;&quot; /&gt;&lt;p style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;&quot;&gt;And that’s all I could find. Unless I follow &lt;a href=&quot;https://en.wikipedia.org/wiki/List_of_programming_languages_by_type#Functional_languages&quot; style=&quot;color: #1a1a1a;&quot;&gt;Wikipedia's list of functional programming languages&lt;/a&gt;, which contains languages such as C++, C#, Rust, or Swift, that allow the flat layout, but don’t really fit my idea of a functional language. But SML, OCaml, Erlang (Elixir, Gleam), Scala? Not that I could see (but please correct me if I’m wrong).&lt;/p&gt;&lt;h3 id=&quot;rolling-your-own&quot; style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin-top: 1.4em;&quot;&gt;Rolling your own&lt;/h3&gt;&lt;p style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;&quot;&gt;Since there is a library implementation for Haskell, maybe that’s a possibility for other languages?&lt;/p&gt;&lt;p style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;&quot;&gt;You should be able to implement flat layouts in any language that supports byte vectors. More interesting is how well such a library fits into the language, and whether a user of the library has to write code or annotations for user-defined record types, or whether the library can handle part or all of that automagically.&lt;/p&gt;&lt;p style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;&quot;&gt;I’ll only mention my beloved Lisp/Scheme here. Lisp’s uniform syntax and macro system are a bonus here, but the lack of static typing makes things harder.&lt;/p&gt;&lt;p style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;&quot;&gt;In Scheme, R6RS (and R7RS with the help of some SRFIs) has byte-vectors and marshalling to/from them in the standard library. But Scheme does not have type annotations, so you either need to offer a macro to define records with typed fields or to define how to marshal the fields of a regular (sealed) record. Since you can shadow standard procedures in a library, you can write code that looks like regular Scheme code, but, perhaps surprisingly, loses identity when storing/retrieving values from records:&lt;/p&gt;&lt;div class=&quot;sourceCode&quot; id=&quot;cb3&quot; style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px; overflow: auto;&quot;&gt;&lt;pre class=&quot;sourceCode scheme&quot; style=&quot;background-color: transparent; margin: 0px; overflow: visible;&quot;&gt;&lt;code class=&quot;sourceCode scheme&quot;&gt;&lt;span id=&quot;cb3-1&quot; style=&quot;color: inherit; display: inline-block; line-height: 1.25; text-decoration: inherit;&quot;&gt;&lt;a href=&quot;http://bokesan.blogspot.de/feeds/posts/default/-/Haskell#cb3-1&quot; style=&quot;color: #1a1a1a;&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;(&lt;span class=&quot;kw&quot; style=&quot;color: #007020; font-weight: bold;&quot;&gt;let&lt;/span&gt; ((vec (make-typed-vector 'point &lt;span class=&quot;dv&quot; style=&quot;color: #40a070;&quot;&gt;1000&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb3-2&quot; style=&quot;color: inherit; display: inline-block; line-height: 1.25; text-decoration: inherit;&quot;&gt;&lt;a href=&quot;http://bokesan.blogspot.de/feeds/posts/default/-/Haskell#cb3-2&quot; style=&quot;color: #1a1a1a;&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      (pt (make-point x y)))&lt;/span&gt;
&lt;span id=&quot;cb3-3&quot; style=&quot;color: inherit; display: inline-block; line-height: 1.25; text-decoration: inherit;&quot;&gt;&lt;a href=&quot;http://bokesan.blogspot.de/feeds/posts/default/-/Haskell#cb3-3&quot; style=&quot;color: #1a1a1a;&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  (&lt;span class=&quot;kw&quot; style=&quot;color: #007020; font-weight: bold;&quot;&gt;vector-set!&lt;/span&gt; vec &lt;span class=&quot;dv&quot; style=&quot;color: #40a070;&quot;&gt;0&lt;/span&gt; pt)&lt;/span&gt;
&lt;span id=&quot;cb3-4&quot; style=&quot;color: inherit; display: inline-block; line-height: 1.25; text-decoration: inherit;&quot;&gt;&lt;a href=&quot;http://bokesan.blogspot.de/feeds/posts/default/-/Haskell#cb3-4&quot; style=&quot;color: #1a1a1a;&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  (&lt;span class=&quot;kw&quot; style=&quot;color: #007020; font-weight: bold;&quot;&gt;eq?&lt;/span&gt; (&lt;span class=&quot;kw&quot; style=&quot;color: #007020; font-weight: bold;&quot;&gt;vector-ref&lt;/span&gt; vec &lt;span class=&quot;dv&quot; style=&quot;color: #40a070;&quot;&gt;0&lt;/span&gt;) pt))&lt;/span&gt;
&lt;span id=&quot;cb3-5&quot; style=&quot;color: inherit; display: inline-block; line-height: 1.25; text-decoration: inherit;&quot;&gt;&lt;a href=&quot;http://bokesan.blogspot.de/feeds/posts/default/-/Haskell#cb3-5&quot; style=&quot;color: #1a1a1a;&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; ⇒ &lt;span class=&quot;dv&quot; style=&quot;color: #40a070;&quot;&gt;#f&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;&quot;&gt;(But then, you probably shouldn’t be using &lt;code&gt;eq?&lt;/code&gt; when doing functional programming in Scheme).&lt;/p&gt;&lt;p style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;&quot;&gt;The same approach is possible in Common Lisp. In contrast to Scheme, it does have optional type annotations, and, together with a helper library for accessing the innards of floats and either the meta-object protocol to get type information or (probably better) a macro to define typed records, an implementation should be reasonably straightforward. Making it play nice with inheritance and the dynamic nature of Common Lisp (e.g., adding slots to classes or even changing an object's class at runtime) would be a much harder undertaking.&lt;/p&gt;&lt;h2 id=&quot;conclusion&quot; style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin-top: 1.4em;&quot;&gt;Conclusion&lt;/h2&gt;&lt;p style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;&quot;&gt;Of the functional languages I looked at, only F# fully supports flat and dense memory layouts. Among the pure languages, Haskell and Clean come close.&lt;/p&gt;&lt;p style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;&quot;&gt;The question is how important this really is. There’s a good argument to be made for turning to more specialized languages like Futhark if you mainly care about performance. On the other hand, having a uniform codebase in one language also has advantages.&lt;/p&gt;&lt;p style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;&quot;&gt;Then, the performance story has changed, too. While the points Project Valhalla raises remain true in principle, processor designers are aware of this as well. They are doing their best to hide memory latency with techniques such as out-of-order execution or humongous caches. Thus, on a modern CPU, the effects of a pointer-rich layout are often only observable with large working set sizes.&lt;/p&gt;&lt;p style=&quot;background-color: #fdfdfd; color: #1a1a1a; margin: 1em 0px;&quot;&gt;Still, given the plethora of imperative language that can get you to Valhalla, support for this in the functional landscape seems lacking. In the future, I hope to see more languages or libraries that will make this possible.&lt;/p&gt;</description>
	<pubDate>Thu, 12 Mar 2026 11:17:02 +0000</pubDate>
	<author>noreply@blogger.com (bokesan)</author>
</item>
<item>
	<title>Matt Parsons: Teaching Claude to Be Lazy</title>
	<guid isPermaLink="true">https://www.parsonsmatt.org/2026/03/10/teaching_claude_to_be_lazy.html</guid>
	<link>https://www.parsonsmatt.org/2026/03/10/teaching_claude_to_be_lazy.html</link>
	<description>&lt;p&gt;I’ve been watching AI development for a long time.
I found LessWrong around 2012-2013, and managed to get myself worked up about the oncoming singularity.
I managed to chill out about it, but interest and excitement for AI remained.
The initial Deep Dream image generation, Alpha Go, etc, were all so exciting.
And then GPT-2 came out.&lt;/p&gt;

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

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

&lt;p&gt;This is pretty incredible, because my productivity has always been limited by two things:&lt;/p&gt;

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

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

&lt;h1 id=&quot;using-claude-code-effectively&quot;&gt;Using Claude Code Effectively&lt;/h1&gt;

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

&lt;p&gt;The brief tl;dr:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;It’s the same shit that makes humans good at software development&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;haskell-is-awesome-for-llms&quot;&gt;Haskell is Awesome for LLMs&lt;/h2&gt;

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

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

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

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

&lt;h2 id=&quot;software-engineering-matters&quot;&gt;Software Engineering Matters&lt;/h2&gt;

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

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

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

&lt;h2 id=&quot;build-workflows-iteratively&quot;&gt;Build Workflows Iteratively&lt;/h2&gt;

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

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

&lt;p&gt;So each work session with Claude produces:&lt;/p&gt;

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

&lt;p&gt;This process ends up reducing the highly non-deterministic LLM tool with a much more deterministic tool.&lt;/p&gt;

&lt;h2 id=&quot;mock-reviews-and-refactoring&quot;&gt;Mock Reviews and Refactoring&lt;/h2&gt;

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

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

&lt;h1 id=&quot;what-doesnt-work-well&quot;&gt;What Doesn’t Work Well&lt;/h1&gt;

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

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

&lt;h2 id=&quot;defined-by-our-vice&quot;&gt;Defined by our Vice&lt;/h2&gt;

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

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

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

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

&lt;h1 id=&quot;am-i-still-a-skeptic&quot;&gt;Am I still a skeptic?&lt;/h1&gt;

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

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

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

&lt;p&gt;I’m excited to wait and find out.&lt;/p&gt;</description>
	<pubDate>Tue, 10 Mar 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Mark Jason Dominus: Programmers will document for Claude, but not for each other</title>
	<guid isPermaLink="false">tag:,2026:/tech/gpt/documentation-wins-2</guid>
	<link>https://blog.plover.com/tech/gpt/documentation-wins-2.html</link>
	<description>&lt;p&gt;&lt;a href=&quot;https://blog.plover.com/tech/gpt/documentation-wins.html&quot;&gt;A couple of days ago I recounted a common complaint&lt;/a&gt;:&lt;/p&gt;

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

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

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

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

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

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

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

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

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

&lt;p&gt;My advice for the day:&lt;/p&gt;

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

&lt;p&gt;Maybe this is obvious?  But it wasn't obvious to me.  I'm still
getting used to this new world.&lt;/p&gt;</description>
	<pubDate>Mon, 09 Mar 2026 08:04:00 +0000</pubDate>
	<author>mjd@plover.com (Mark Dominus)</author>
</item>
<item>
	<title>Haskell Interlude: 78: Jamie Willis</title>
	<guid isPermaLink="false">Buzzsprout-18809011</guid>
	<link></link>
	<description>&lt;p&gt;&lt;b&gt;In this episode, we focus on a particular part of Haskell: teaching it. To help us, we are joined by Jamie Willis who is a Teaching Fellow at Imperial College London. The episode explores the benefits of live coding, and why Haskell is the best language for teaching programming.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
	<pubDate>Sun, 08 Mar 2026 11:00:00 +0000</pubDate>
        <enclosure url="https://www.buzzsprout.com/1817535/episodes/18809011-78-jamie-willis.mp3" length="31284259" type="audio/mpeg"/>
</item>
<item>
	<title>Mark Jason Dominus: How are John Waters movies like James Bond movies?</title>
	<guid isPermaLink="false">tag:,2026:/movie/john_waters</guid>
	<link>https://blog.plover.com/movie/john_waters.html</link>
	<description>&lt;p&gt;A number of years ago I wondered how many movies I had seen. The only
way I could think of finding out was just to make a list.  This I did
as best I could.  (It turned out to be around 700.)&lt;/p&gt;

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

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

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

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

&lt;p&gt;Looking into it further I discovered that I also wasn't sure if I had
seen &lt;em&gt;Multiple Maniacs&lt;/em&gt;.  In it, Divine's character is raped by a
giant lobster.  On the one hand, that seems like the sort of thing I
would remember.  And I think maybe I do?  But again I'm not sure I'm
not just imagining what it would be like!&lt;/p&gt;</description>
	<pubDate>Sun, 08 Mar 2026 09:50:00 +0000</pubDate>
	<author>mjd@plover.com (Mark Dominus)</author>
</item>
<item>
	<title>Mark Jason Dominus: Documentation is a message in a bottle</title>
	<guid isPermaLink="false">tag:,2026:/tech/gpt/documentation-wins</guid>
	<link>https://blog.plover.com/tech/gpt/documentation-wins.html</link>
	<description>&lt;p&gt;Our company is
going to a convention later this month, and they will have a booth with
big TV screens showing statistics that update in real time.  My job is
to write the backend server that delivers the statistics.&lt;/p&gt;

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

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

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

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

&lt;p&gt;Amanda shared some screencaps of her chats with Claude about the
project, and I suggested:&lt;/p&gt;

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

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

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

&lt;blockquote&gt;
  &lt;p&gt;It looks like maybe you started it off by feeding it my ticket
  description.  Is that right? &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;She said yes, she had.  She had also fed it the original product
documents I had read.&lt;/p&gt;

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

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

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

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

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

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

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

&lt;p&gt;Not everything is going to get worse.  Some things will get better.&lt;/p&gt;

&lt;h3&gt;Addendum 20260208&lt;/h3&gt;

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

&lt;p&gt;If you're good at editing, anyway.  I wonder if part of the reason
Claude is working so well for me is that I'm really good at editing
and at code review?&lt;/p&gt;</description>
	<pubDate>Thu, 05 Mar 2026 16:07:00 +0000</pubDate>
	<author>mjd@plover.com (Mark Dominus)</author>
</item>
<item>
	<title>Mark Jason Dominus: Bo Diddley</title>
	<guid isPermaLink="false">tag:,2026:/lang/etym/Bo-Diddley</guid>
	<link>https://blog.plover.com/lang/etym/Bo-Diddley.html</link>
	<description>&lt;p&gt;Bo Diddley's cover of &quot;Sixteen Tons&quot; sounds very much like one of my
favorites, &quot;Can't Judge A Book By Its Cover&quot;.  It's interesting to
compare.&lt;/p&gt;

&lt;p&gt;Thinking on that it suddenly occured to me that his name might have
been a play on “diddley bow”, which is a sort of homemade one-stringed
zither.  The player uses a bottle as a bridge for the string, and
changes the pitch by sliding the bottle up and down.  When you hear
about blues artists whose first guitars were homemade, this is often
what was meant: it wasn't a six-string guitar, it was a diddley bow.&lt;/p&gt;

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

Trace

&lt;pre class=&quot;text&quot;&gt;&lt;code&gt;Input           Heap:
list:

[3,4,2,5,1]


[4,2,5,1]       3


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


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


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


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


Output          Heap:
list:

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


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


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


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


[1,2,3,4]       5


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

&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;Max&lt;/span&gt;&lt;/code&gt; and
&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;Last&lt;/span&gt;&lt;/code&gt;
Monus laws

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


&lt;h3 id=&quot;what-was-that&quot;&gt;What was that?&lt;/h3&gt;
&lt;p&gt;So what did you just see (or skipped watching)? You could see Emilio’s screen, running VSCode and editing a Lean file. He designed a small programming language that he embedded into Lean, including an evaluator. So far, so standard, but a few things stick out already:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Using Lean’s very extensible syntax this embedding is rather elegant and pretty.&lt;/li&gt;
&lt;li&gt;Furthermore, he can run this DSL code right there, in the source code, using commands like &lt;a href=&quot;https://lean-lang.org/doc/reference/latest/find/?domain=Verso.Genre.Manual.section&amp;amp;name=hash-eval&quot;&gt;&lt;code&gt;#eval&lt;/code&gt;&lt;/a&gt;. This is a bit like the interpreter found in Haskell or Python, but without needing a separate process, or like using a Jupyter notebook, but without the stateful cell management.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is already a nice demonstration of Lean’s abilities and strength, as we know them. But what blew my mind the first time was what happened next: He had a visual debugger that allowed him to &lt;em&gt;debug his DSL program&lt;/em&gt;. It appeared on the right, in Lean’s “Info View”, where various Lean tools can hook into, show information and allow the user to interact.&lt;/p&gt;
&lt;p&gt;But it did not stop there, and my mind was blown a second time: Emilio opened VSCode’s „Debugger“ pane on the left, and was able to properly use VSCode’s full-fledged debugger frontend for his own little embedded programming language! Complete with highlighting the executed line, with the ability to set breakpoints there, and showing the state of local variables in the debugger.&lt;/p&gt;
&lt;p&gt;Having a good debugger is not to be taken for granted even for serious, practical programming languages. Having it for a small embedded language that you just built yourself? I wouldn’t have even considered that.&lt;/p&gt;
&lt;h3 id=&quot;did-it-take-long&quot;&gt;Did it take long?&lt;/h3&gt;
&lt;p&gt;If I were Emilio’s manager I would applaud the demo and then would have to ask how many weeks he spent on that. Coming up with the language, getting the syntax extension right, writing the evaluator and especially learning how the debugger integration into VSCode (using the &lt;a href=&quot;https://microsoft.github.io/debug-adapter-protocol/&quot;&gt;DAP protocol&lt;/a&gt;) works, and then instrumenting his evaluator to speak that protocol – that is a sizeable project!&lt;/p&gt;
&lt;p&gt;It turns out the answer isn’t measured in weeks: it took just one day of coding together with GPT-Codex 5.3. My mind was blown a third time.&lt;/p&gt;
&lt;h3 id=&quot;why-does-lean-make-a-difference&quot;&gt;Why does Lean make a difference?&lt;/h3&gt;
&lt;p&gt;I am sure this post is just one of many stories you have read in recent weeks about how new models like Claude Opus 4.6 and GPT-Codex 5.3 built impressive things in hours that would have taken days or more before. But have you seen something like this? Agentic coding is powerful, but limited by what the underlying platform exposes. I claim that Lean is a particularly well-suited platform to unleash the agents’ versatility.&lt;/p&gt;
&lt;p&gt;Here we are using Lean as a programming language, not as a theorem prover (which brings other immediate benefits when using agents, e.g. the produced code can be verified rather than merely plausible, but that’s a story to be told elsewhere.)&lt;/p&gt;
&lt;p&gt;But arguably because Lean is &lt;em&gt;also&lt;/em&gt; a theorem prover, and because of the requirements that stem from that, its architecture is different from that of a conventional programming language implementation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;As a theorem prover, it needs extensible syntax to allow formalizing mathematics in an ergonomic way, but it can also be used for embedding syntax.&lt;/li&gt;
&lt;li&gt;As a theorem prover, it needs the ability to run “tactics” written by the user, hence the ability to evaluate the code right there in the editor.&lt;/li&gt;
&lt;li&gt;As a theorem prover, it needs to give access to information such as tactic state, and such introspection abilities unlock many other features – such as a debugger for an embedded language.&lt;/li&gt;
&lt;li&gt;As a theorem prover, it has to allow tools to present information like the tactic state, so it has the concept of &lt;a href=&quot;https://lean-lang.org/examples/1900-1-1-widgets/&quot;&gt;interactive “Widgets”&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So Lean’s design has always made such a feat &lt;em&gt;possible&lt;/em&gt;. But it was no easy feat. The Lean API is large, and documentation never ceases to be improvable. In the past, it would take an expert (or someone willing to become one) to pull off that stunt. These days, coding assistants have no issue digesting, understanding and using the API, as Emilio’s demo shows.&lt;/p&gt;
&lt;p&gt;The combination of Lean’s extensibility and the ability of coding agents to make use of that is a game changer to how we can develop software, with rich, deep, flexible and bespoke ways to interact with our code, created on demand.&lt;/p&gt;
&lt;h3 id=&quot;where-does-that-lead-us&quot;&gt;Where does that lead us?&lt;/h3&gt;
&lt;p&gt;Emilio actually shared more such demos (&lt;a href=&quot;https://github.com/ejgallego/imp-lab&quot;&gt;Github repository&lt;/a&gt;). A visual explorer for the compiler output (&lt;a href=&quot;https://www.joachim-breitner.de/various/lean-compiler-explorer.png&quot;&gt;have a look at the screenshot&lt;/a&gt;. A browser-devtool-like inspection tool for Lean’s “InfoTree”. Any of these provide a significant productivity boost. Any of these would have been a sizeable project half a year ago. Now it’s just a few hours of chatting with the agent.&lt;/p&gt;
&lt;p&gt;So allow me to try and extrapolate into a future where coding agents have continued to advance at the current pace, and are used ubiquitously. Is there then even a point in polishing these tools, shipping them to our users, documenting them? Why build a compiler explorer for our users, if our users can just ask their agent to build one for them, right then when they need it, tailored to precisely the use case they have, with no unnecessary or confusing feature. The code would be single use, as the next time the user needs something like that the agent can just re-create it, maybe slightly different because every use case is different.&lt;/p&gt;
&lt;p&gt;If that comes to pass then Lean may no longer get praise for its nice out-of-the-box user experience, but instead because it is such a powerful framework for ad-hoc UX improvements.&lt;/p&gt;
&lt;p&gt;And Emilio wouldn’t post demos about his debugger. He’d just use it.&lt;/p&gt;</description>
	<pubDate>Wed, 25 Feb 2026 10:53:30 +0000</pubDate>
	<author>mail@joachim-breitner.de (Joachim Breitner)</author>
</item>
<item>
	<title>Haskell Interlude: 77: Franz Thoma</title>
	<guid isPermaLink="false">Buzzsprout-18725311</guid>
	<link></link>
	<description>&lt;p&gt;Franz Thoma is Principal Consultant at TNG Technology Consulting, and an organizer of MuniHac. Franz sees functional programming and Haskell as a tool for thinking about software, even if the project is not written in Haskell. We had a far-reaching conversation about the differences between functional and object-oriented programming and their languages, software architecture, and Haskell adoption in industry. &lt;/p&gt;</description>
	<pubDate>Sun, 22 Feb 2026 12:00:00 +0000</pubDate>
        <enclosure url="https://www.buzzsprout.com/1817535/episodes/18725311-77-franz-thoma.mp3" length="41677874" type="audio/mpeg"/>
</item>
<item>
	<title>Tweag I/O: Nickel since 1.0</title>
	<guid isPermaLink="true">https://tweag.io/blog/2026-02-19-nickel-since-1-0/</guid>
	<link>https://tweag.io/blog/2026-02-19-nickel-since-1-0/</link>
	<description>&lt;p&gt;We released Nickel 1.0 in May 2023. Since then, we’ve been working so hard
on new features, bug fixes, and performance improvements that we haven’t had
the opportunity to write about them as much as we would’ve liked. This post
rounds up some of the big changes that we’ve landed over the past few years.&lt;/p&gt;
&lt;h2 id=&quot;new-language-features&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#new-language-features&quot;&gt;&lt;/a&gt;New language features&lt;/h2&gt;
&lt;h3 id=&quot;algebraic-data-types&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#algebraic-data-types&quot;&gt;&lt;/a&gt;Algebraic data types&lt;/h3&gt;
&lt;p&gt;The biggest new language feature is one that we have actually &lt;a href=&quot;https://www.tweag.io/blog/2024-09-05-algebraic-data-types-nickel/&quot;&gt;written
about&lt;/a&gt;
before: algebraic data types — or &lt;em&gt;enum variants&lt;/em&gt; in Nickel terminology —
first landed in &lt;a href=&quot;https://github.com/tweag/nickel/releases/tag/1.5.0&quot;&gt;Nickel 1.5&lt;/a&gt;. Nickel has supported plain enums
for a long time: &lt;code class=&quot;language-text&quot;&gt;[| 'Carnitas, 'Fish |]&lt;/code&gt; is the type of something that
can take two possible values: &lt;code class=&quot;language-text&quot;&gt;'Carnitas&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;'Fish&lt;/code&gt;. Enum variants extend
these by allowing the enum types to specify payloads, like
&lt;code class=&quot;language-text&quot;&gt;[| 'Carnitas { pineapple : Number }, 'Fish { avocado : Number, cheese : Number } |]&lt;/code&gt;.
Types like this are supported by many modern programming languages, as
they are useful for encoding important invariants like the fact that carnitas
tacos can be topped with pineapple but not avocado. For more on the design
and motivation for algebraic data types in Nickel, see
&lt;a href=&quot;https://www.tweag.io/blog/2024-09-05-algebraic-data-types-nickel/&quot;&gt;our other post&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;pattern-matching&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#pattern-matching&quot;&gt;&lt;/a&gt;Pattern matching&lt;/h3&gt;
&lt;p&gt;Nickel has had a &lt;code class=&quot;language-text&quot;&gt;match&lt;/code&gt; statement for a while, but it used to be quite limited.
&lt;a href=&quot;https://github.com/tweag/nickel/releases/tag/1.5.0&quot;&gt;Nickel 1.5&lt;/a&gt; and
&lt;a href=&quot;https://github.com/tweag/nickel/releases/tag/1.7.0&quot;&gt;Nickel 1.7&lt;/a&gt; extended it significantly: not only can you now match
the enum variants we mentioned above, you can also match arrays, records, and constants.
You can also match the “or” of two patterns, and you can guard matches with predicates.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-nickel&quot;&gt;&lt;code class=&quot;language-nickel&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;match&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 operator&quot;&gt; &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 operator&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;s&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;e&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token operator&quot;&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&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 operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;too much pineapple&quot;&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 operator&quot;&gt; &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 operator&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;s&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 operator&quot;&gt; &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 operator&quot;&gt; &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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;h&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 operator&quot;&gt; &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 operator&quot;&gt; &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 operator&quot;&gt;]&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 operator&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;r&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;h&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 operator&quot;&gt; &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 operator&quot;&gt; &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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;s&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 operator&quot;&gt; &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 operator&quot;&gt; &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 operator&quot;&gt;]&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 operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;one of each&quot;&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Basically, if you’ve used pattern matching in another language then
Nickel’s match blocks probably have the features you’re used to.
And they’re adapted to Nickel’s gradual typing: the example match block
above will work in dynamically typed code, but in a statically typed block
it will fail to typecheck, because there’s no static type that can be
either an enum or an array.&lt;/p&gt;
&lt;h3 id=&quot;field-punning&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#field-punning&quot;&gt;&lt;/a&gt;Field punning&lt;/h3&gt;
&lt;p&gt;Records in Nickel are recursive by default, meaning that in the record&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-nickel&quot;&gt;&lt;code class=&quot;language-nickel&quot;&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;tacos&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 operator&quot;&gt; &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 operator&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;s&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;pineapple&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 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 operator&quot;&gt;}&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;price&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;o&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;s&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;price_per_taco&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;the name &lt;code class=&quot;language-text&quot;&gt;price_per_taco&lt;/code&gt; in the definition of &lt;code class=&quot;language-text&quot;&gt;price&lt;/code&gt; refers to the field
&lt;code class=&quot;language-text&quot;&gt;price_per_taco&lt;/code&gt; defined within the record. This is behavior is &lt;em&gt;usually&lt;/em&gt; very handy,
but it can be annoying when you’re trying to define a field whose name shadows
something in an outer scope. For example, suppose you want to move the definition
of &lt;code class=&quot;language-text&quot;&gt;tacos&lt;/code&gt; outside the record:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-nickel&quot;&gt;&lt;code class=&quot;language-nickel&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;tacos&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 operator&quot;&gt; &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 operator&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;s&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;pineapple&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 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 operator&quot;&gt;}&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 keyword&quot;&gt;in&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;tacos&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;s&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;price&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;o&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;s&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;price_per_taco&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This probably doesn’t do what you want: it recurses infinitely, because
in the &lt;code class=&quot;language-text&quot;&gt;tacos = tacos&lt;/code&gt; line, the &lt;code class=&quot;language-text&quot;&gt;tacos&lt;/code&gt; on the right side of the equals
sign refers to the name &lt;code class=&quot;language-text&quot;&gt;tacos&lt;/code&gt; that’s being defined on the left hand side
(and not, as you might expect, the &lt;code class=&quot;language-text&quot;&gt;tacos&lt;/code&gt; in &lt;code class=&quot;language-text&quot;&gt;let tacos = ... in&lt;/code&gt;).
There are workarounds (like calling the outer variable &lt;code class=&quot;language-text&quot;&gt;tacos_&lt;/code&gt; instead),
but they’re annoying. &lt;a href=&quot;https://github.com/tweag/nickel/releases/tag/1.12.0&quot;&gt;Nickel 1.12&lt;/a&gt; added the &lt;code class=&quot;language-text&quot;&gt;include&lt;/code&gt; keyword,
where &lt;code class=&quot;language-text&quot;&gt;{ include tacos }&lt;/code&gt; means &lt;code class=&quot;language-text&quot;&gt;{ tacos = &amp;lt;tacos-from-the-outer-scope&amp;gt; }&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;let-blocks&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#let-blocks&quot;&gt;&lt;/a&gt;Let blocks&lt;/h3&gt;
&lt;p&gt;Nickel binds local variables using a &lt;code class=&quot;language-text&quot;&gt;let&lt;/code&gt; statement, as in &lt;code class=&quot;language-text&quot;&gt;let x = 1 in x + x&lt;/code&gt;. Before &lt;a href=&quot;https://github.com/tweag/nickel/releases/tag/1.9.0&quot;&gt;Nickel 1.9&lt;/a&gt; you could only bind one variable at a time — as
in &lt;code class=&quot;language-text&quot;&gt;let x = 1 in let y = 2 in x + y&lt;/code&gt; — but now you can bind multiple variables
in a single block, as in &lt;code class=&quot;language-text&quot;&gt;let x = 1, y = 2 in x + y&lt;/code&gt;. In most situations this is
just a small syntactic convenience,&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; but with &lt;em&gt;recursive&lt;/em&gt; let
blocks you actually gain some expressive power. For example, they allow you to write
mutually recursive functions without putting them in a record (which used to be the
only way to create a recursive environment in Nickel):&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-nickel&quot;&gt;&lt;code class=&quot;language-nickel&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;rec&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 property&quot;&gt;is_even&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;x&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 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;if&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;x&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 operator&quot;&gt;=&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;then&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;d&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 operator&quot;&gt;x&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;is_odd&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;x&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 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;if&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;x&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 operator&quot;&gt;=&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;n&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 operator&quot;&gt;x&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&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 operator&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;in&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 operator&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;42&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;better-contract-constructors&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#better-contract-constructors&quot;&gt;&lt;/a&gt;Better contract constructors&lt;/h3&gt;
&lt;p&gt;Custom contracts were reworked in &lt;a href=&quot;https://github.com/tweag/nickel/releases/tag/1.8.0&quot;&gt;Nickel 1.8&lt;/a&gt;, allowing for better control of a
contract’s eagerness, more precise error locations, and better composability.
Nickel’s standard library now offers three contract constructors. The
simplest is &lt;code class=&quot;language-text&quot;&gt;std.contract.from_predicate&lt;/code&gt;, which turns a predicate (of type &lt;code class=&quot;language-text&quot;&gt;Dyn -&amp;gt; Bool&lt;/code&gt;)
into a contract. &lt;code class=&quot;language-text&quot;&gt;std.contract.from_validator&lt;/code&gt; is slightly more complicated but offers
better control over error messages, while &lt;code class=&quot;language-text&quot;&gt;std.contract.custom&lt;/code&gt; offers the most control.&lt;/p&gt;
&lt;p&gt;A full description of the contract changes is out of scope for this blog post — there’s
a whole &lt;a href=&quot;https://nickel-lang.org/user-manual/contracts/#user-defined-contracts&quot;&gt;section&lt;/a&gt; of the manual devoted to it. But the key point is that
contracts in Nickel are partly eager and partly lazy. For example, the contract in&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-nickel&quot;&gt;&lt;code class=&quot;language-nickel&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;Taco&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 operator&quot;&gt; &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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;s&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 operator&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;h&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 operator&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;s&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;Taco&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 operator&quot;&gt; &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 operator&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;s&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 operator&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;e&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 keyword&quot;&gt;in&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;gets applied in two stages. When &lt;code class=&quot;language-text&quot;&gt;tacos&lt;/code&gt; first gets evaluated, the contract checks that
&lt;code class=&quot;language-text&quot;&gt;tacos&lt;/code&gt; is an array. But rather than validating the array elements immediately,
it propagates the element contracts inside the array and leaves them
unevaluated; essentially, &lt;code class=&quot;language-text&quot;&gt;tacos&lt;/code&gt; gets evaluated to
&lt;code class=&quot;language-text&quot;&gt;['Carnitas | Taco, 'CrunchyTacoSupreme | Taco]&lt;/code&gt;. Only when the &lt;em&gt;elements&lt;/em&gt; of the array get
evaluated are their contracts checked. In particular, if the array elements are
never actually evaluated (for example, if &lt;code class=&quot;language-text&quot;&gt;&amp;lt;something&amp;gt;&lt;/code&gt; is &lt;code class=&quot;language-text&quot;&gt;std.array.length tacos&lt;/code&gt;, which doesn’t evaluate the individual elements) then we’ll never find
out that &lt;code class=&quot;language-text&quot;&gt;'CrunchyTacoSupreme&lt;/code&gt; isn’t actually a &lt;code class=&quot;language-text&quot;&gt;Taco&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The lazy/eager distinction has been part of Nickel’s built-in record and array
contracts since the beginning, but never fully exploitable by custom contracts.
The new &lt;code class=&quot;language-text&quot;&gt;std.contract.custom&lt;/code&gt; constructor creates a contract with explicit lazy
and eager parts, and the &lt;code class=&quot;language-text&quot;&gt;std.contract.check&lt;/code&gt; function allows for speculatively
checking the eager part of a contract without bailing out if it fails. Together,
these ingredients allowed us to create useful &lt;a href=&quot;https://www.tweag.io/blog/2022-04-28-union-intersection-contracts/&quot;&gt;union contracts&lt;/a&gt; (&lt;code class=&quot;language-text&quot;&gt;std.contract.any_of&lt;/code&gt;)
and improve the error reporting of the eager contracts in &lt;a href=&quot;https://github.com/nickel-lang/json-schema-to-nickel/&quot;&gt;json-schema-to-nickel&lt;/a&gt;,
our tool for converting JSON schemas to Nickel contracts.&lt;/p&gt;
&lt;h2 id=&quot;performance-improvements&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#performance-improvements&quot;&gt;&lt;/a&gt;Performance improvements&lt;/h2&gt;
&lt;p&gt;For Nickel 1.0, we were focused on getting the basic language right. Since then
(and especially over the past year), we’ve been working on getting the interpreter
to run faster. While the performance improvements you observe will depend heavily
on your use case, we’ve seen large user-provided Nickel configurations that
evaluate 10x faster now than they were two years ago (and 3x faster than six months ago).
The most recent performance improvements are part of our progress towards
a &lt;a href=&quot;https://github.com/tweag/nickel/blob/c483fe2811fa6b271d96cf87b8b3d3872fe03d8f/rfcs/007-bytecode-interpreter.md&quot;&gt;bytecode interpreter&lt;/a&gt;. We’ve been landing these improvements gradually over the
past year or so, but most of that preparation only had a performance impact
starting in &lt;a href=&quot;https://github.com/tweag/nickel/releases/tag/1.15.1&quot;&gt;Nickel 1.15&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;standard-library-improvements&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#standard-library-improvements&quot;&gt;&lt;/a&gt;Standard library improvements&lt;/h3&gt;
&lt;p&gt;Nickel’s &lt;a href=&quot;https://nickel-lang.org/stdlib/std/&quot;&gt;standard library&lt;/a&gt; has roughly doubled in size since Nickel 1.0, offering many useful
utility functions (like &lt;code class=&quot;language-text&quot;&gt;std.record.get_or&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;std.string.find_all&lt;/code&gt;) and contract combinators
(like &lt;code class=&quot;language-text&quot;&gt;std.contract.Sequence&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;std.contract.any_of&lt;/code&gt;). The standard library now also
contains a useful set of trigonometric and other numeric functions,
&lt;a href=&quot;https://github.com/nickel-lang/nickel/issues/2005&quot;&gt;contributed&lt;/a&gt; by a community member who was
using Nickel to configure a robot.&lt;/p&gt;
&lt;h2 id=&quot;tooling-and-distribution-improvements&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#tooling-and-distribution-improvements&quot;&gt;&lt;/a&gt;Tooling and distribution improvements&lt;/h2&gt;
&lt;p&gt;Nickel has seen many improvements that are not directly tied to the Nickel
language itself.&lt;/p&gt;
&lt;h3 id=&quot;language-server-improvements&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#language-server-improvements&quot;&gt;&lt;/a&gt;Language server improvements&lt;/h3&gt;
&lt;p&gt;Nickel’s language server (NLS) has seen many improvements, especially
in &lt;a href=&quot;https://github.com/tweag/nickel/releases/tag/1.2.0&quot;&gt;Nickel 1.2&lt;/a&gt; and &lt;a href=&quot;https://github.com/tweag/nickel/releases/tag/1.3.0&quot;&gt;1.3&lt;/a&gt;. It now supports finding references
and definitions, listing symbols, and various other table-stakes language
server features. Completions have also been improved substantially since
version 1.0, and can make intelligent use of type- and contract-related
information. For example, in&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-nickel&quot;&gt;&lt;code class=&quot;language-nickel&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;s&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 operator&quot;&gt; &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 operator&quot;&gt;}&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 operator&quot;&gt; &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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;s&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;e&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Number&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 operator&quot;&gt;,&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 operator&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;h&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;o&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Number&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 operator&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;e&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Number&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 operator&quot;&gt; &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 operator&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;#           └── cursor is here&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;NLS knows to offer “pineapple” as a completion, but not “avocado”.&lt;/p&gt;
&lt;p&gt;NLS has also gained the ability to offer diagnostics for &lt;em&gt;evaluation&lt;/em&gt;
errors. This is very useful in Nickel because contract errors are detected
during evaluation instead of during typechecking. In-editor detection of
contract violations is part of the vision
articulated in a &lt;a href=&quot;https://www.tweag.io/blog/2024-05-16-nickel-programmable-lsp/&quot;&gt;previous blog post&lt;/a&gt;, where configuration
errors are &lt;a href=&quot;https://en.wikipedia.org/wiki/Shift-left_testing&quot;&gt;left-shifted&lt;/a&gt;
(because you get them as you type) and infinitely customizable (because
contracts are arbitrary code). Since the previous post was written, the
diagnostics have been further improved thanks to the contract
improvements mentioned above: the problematic field now gets
highlighted directly.&lt;/p&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/de296f77c52d37c3a7c3d77ab91aee42/949b7/kubernetes.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;png&quot; class=&quot;gatsby-resp-image-image&quot; src=&quot;https://www.tweag.io/static/de296f77c52d37c3a7c3d77ab91aee42/fcda8/kubernetes.png&quot; style=&quot;width: 100%; height: 100%; margin: 0; vertical-align: middle;&quot; title=&quot;png&quot; /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;unit-tests&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#unit-tests&quot;&gt;&lt;/a&gt;Unit tests&lt;/h3&gt;
&lt;p&gt;Since &lt;a href=&quot;https://github.com/tweag/nickel/releases/tag/1.9.0&quot;&gt;Nickel 1.9&lt;/a&gt;, there is a &lt;code class=&quot;language-text&quot;&gt;nickel test&lt;/code&gt; command that executes
unit tests contained in documentation comments.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-nickel&quot;&gt;&lt;code class=&quot;language-nickel&quot;&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;o&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 operator&quot;&gt; &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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;m%&quot;
      Double the avocado!

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

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

Overridable fields &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;require &lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token parameter variable&quot;&gt;--override&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;:
- price
- tacos

Use the &lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;query&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;&lt;/span&gt; subcommand to print a detailed description of a specific field. See &lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;nickel &lt;span class=&quot;token builtin class-name&quot;&gt;help&lt;/span&gt; query&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Since &lt;a href=&quot;https://github.com/tweag/nickel/releases/tag/1.11.0&quot;&gt;Nickel 1.11&lt;/a&gt;, customize mode has had support for environment variables:
&lt;code class=&quot;language-text&quot;&gt;nickel export tacos.ncl -- taco_description=@env:DESC&lt;/code&gt; will expand the &lt;code class=&quot;language-text&quot;&gt;DESC&lt;/code&gt;
environment variable and substitute it into the &lt;code class=&quot;language-text&quot;&gt;tacos.ncl&lt;/code&gt; configuration.
In some cases, you could achieve something similar by expanding environment
variables using your shell, but correctly handling escaping there can be
painful (or even a security risk).&lt;/p&gt;
&lt;h3 id=&quot;nix-compatibility&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#nix-compatibility&quot;&gt;&lt;/a&gt;Nix compatibility&lt;/h3&gt;
&lt;p&gt;A lot of Nickel users are also Nix users, and so Nix interoperability is an
often-requested feature. Our current Nix interface is limited to plain data,
but you can import Nix from Nickel if you’ve built Nickel with the
“nix-experimental” feature:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-nickel&quot;&gt;&lt;code class=&quot;language-nickel&quot;&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;price&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;o&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;h&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 keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;tacos.nix&quot;&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;price_per_taco&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;package-management&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#package-management&quot;&gt;&lt;/a&gt;Package management&lt;/h3&gt;
&lt;p&gt;In Nickel 1.0, you could share code between projects by copying files around,
basically. &lt;a href=&quot;https://github.com/tweag/nickel/releases/tag/1.11.0&quot;&gt;Nickel 1.11&lt;/a&gt; introduced package management, allowing you
to import Nickel dependencies from other directories, Git repositories, or a
central package registry. You declare your dependencies in a &lt;code class=&quot;language-text&quot;&gt;Nickel-pkg.ncl&lt;/code&gt;
manifest file:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-nickel&quot;&gt;&lt;code class=&quot;language-nickel&quot;&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;name&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;tacos&quot;&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;authors&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Me&quot;&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;minimal_nickel_version&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;1.15.0&quot;&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;dependencies&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 operator&quot;&gt; &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 property&quot;&gt;salsa&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;G&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;t&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;package&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;github:example/salsa&quot;&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 property&quot;&gt;version&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;1.0&quot;&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 operator&quot;&gt; &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 operator&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then you can import those dependencies in your Nickel code:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-nickel&quot;&gt;&lt;code class=&quot;language-nickel&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;h&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;avocado&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&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 property&quot;&gt;salsa&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 operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;a&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 operator&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;e&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;thank-you&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#thank-you&quot;&gt;&lt;/a&gt;Thank you!&lt;/h2&gt;
&lt;p&gt;That sums up the biggest changes to Nickel over the past two and a half years or so.
As we come up on 5,000 commits from 86 contributors, we’d like to thank you
for all the feedback, discussion, and participation that encourage us
to keep improving Nickel.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn-1&quot;&gt;There are some situations where let blocks can improve
performance with Nickel’s current interpreter: &lt;code class=&quot;language-text&quot;&gt;let x = 1 in let y = 2 in x + y&lt;/code&gt; creates two nested environments while &lt;code class=&quot;language-text&quot;&gt;let x = 1, y = 2 in x + y&lt;/code&gt; creates a single environment. Variable lookups are usually faster when
environments are less deeply nested, so the version with a let block should
be a little bit faster. This performance distinction will probably go away
once we have a &lt;a href=&quot;https://github.com/tweag/nickel/blob/c483fe2811fa6b271d96cf87b8b3d3872fe03d8f/rfcs/007-bytecode-interpreter.md&quot;&gt;bytecode interpreter&lt;/a&gt;, though.&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, 19 Feb 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Magnus Therning: Switching to project.el</title>
	<guid isPermaLink="true">https://magnus.therning.org/2026-02-18-switching-to-project.el.html</guid>
	<link>https://magnus.therning.org/2026-02-18-switching-to-project.el.html</link>
	<description>&lt;p&gt;
I've used &lt;a href=&quot;https://github.com/bbatsov/projectile&quot;&gt;projectile&lt;/a&gt; ever since I created my own Emacs config. I have a vague
memory choosing it because some other package only supported it. (It might have
been &lt;a href=&quot;https://emacs-lsp.github.io/lsp-mode/&quot;&gt;lsp-mode&lt;/a&gt;, but I'm not sure.) Anyway, now that &lt;a href=&quot;https://magnus.therning.org/2026-01-19-trying-eglot,-again.html&quot;&gt;I'm trying out eglot&lt;/a&gt;, &lt;a href=&quot;https://magnus.therning.org/2026-01-25-more-on-the-switch-to-eglot.html&quot;&gt;again&lt;/a&gt;,
I thought I might as well see if I can switch to &lt;a href=&quot;https://www.gnu.org/software/emacs/manual/html_node/emacs/Projects.html&quot;&gt;project.el&lt;/a&gt;, which is included
in Emacs nowadays.
&lt;/p&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-org80f0ee9&quot;&gt;
&lt;h2 id=&quot;org80f0ee9&quot;&gt;A non-VC project marker&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-org80f0ee9&quot;&gt;
&lt;p&gt;
Projectile allows using a file, &lt;code&gt;.projectile&lt;/code&gt;, in the root of a project. This
makes it possible to turn a folder into a project without having to use version
control. It's possible to configure project.el to respect more VC markers than
what's built-in. This can be used to define a non-VC marker.
&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;setopt&lt;/span&gt; project-vc-extra-root-markers '&lt;span class=&quot;org-rainbow-delimiters-depth-2&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&quot;.projectile&quot;&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;.git&quot;&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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

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

&lt;dl class=&quot;org-dl&quot;&gt;
&lt;dt&gt;&lt;code&gt;xref-global-history&lt;/code&gt;&lt;/dt&gt;&lt;dd&gt;a single global history (the default)&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;xref-window-local-history&lt;/code&gt;&lt;/dt&gt;&lt;dd&gt;a history per window&lt;/dd&gt;
&lt;/dl&gt;

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

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

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

&lt;pre class=&quot;example&quot; id=&quot;org712aefd&quot;&gt;src
└── Sider
    └── Data
        ├── Command.hs
        ├── Pipeline.hs
        └── Resp.hs
test
└── Sider
    └── Data
        ├── CommandSpec.hs
        ├── PipelineSpec.hs
        └── RespSpec.hs

&lt;/pre&gt;

&lt;p&gt;
I'm not really sure how I'd configure &lt;code&gt;find-sibling-rules&lt;/code&gt;, which are regular
expressions, to deal with folder hierarchies like this. To be honest, I didn't
really see a way of configuring &lt;code&gt;ff-find-other-file&lt;/code&gt; at first either. Then I
happened on a post about &lt;a href=&quot;https://dev.to/fredericlepied/emacs-how-to-switch-from-modulepy-to-testmodulepy-67k&quot;&gt;switching between a module and its tests in Python&lt;/a&gt;.
With its help I came up with the following
&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;mes/setup-hs-ff&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;&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;&lt;span class=&quot;org-rainbow-delimiters-depth-4&quot;&gt;(&lt;/span&gt;proj-root &lt;span class=&quot;org-rainbow-delimiters-depth-5&quot;&gt;(&lt;/span&gt;project-root &lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;(&lt;/span&gt;project-current&lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;)&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;rel-proj-root &lt;span class=&quot;org-rainbow-delimiters-depth-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-keyword&quot;&gt;-some--&amp;gt;&lt;/span&gt; &lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;(&lt;/span&gt;buffer-file-name&lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;)&lt;/span&gt;
                               &lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;(&lt;/span&gt;file-name-directory it&lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;)&lt;/span&gt;
                               &lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;(&lt;/span&gt;f-relative proj-root it&lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;)&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;sub-tree &lt;span class=&quot;org-rainbow-delimiters-depth-5&quot;&gt;(&lt;/span&gt;car &lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;(&lt;/span&gt;f-split &lt;span class=&quot;org-rainbow-delimiters-depth-7&quot;&gt;(&lt;/span&gt;f-relative &lt;span class=&quot;org-rainbow-delimiters-depth-8&quot;&gt;(&lt;/span&gt;buffer-file-name&lt;span class=&quot;org-rainbow-delimiters-depth-8&quot;&gt;)&lt;/span&gt; proj-root&lt;span class=&quot;org-rainbow-delimiters-depth-7&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;)&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;search-dirs &lt;span class=&quot;org-rainbow-delimiters-depth-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-keyword&quot;&gt;--&amp;gt;&lt;/span&gt; '&lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&quot;src&quot;&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;test&quot;&lt;/span&gt;&lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;)&lt;/span&gt;
                                &lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;(&lt;/span&gt;remove sub-tree it&lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;)&lt;/span&gt;
                                &lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;(&lt;/span&gt;-map &lt;span class=&quot;org-rainbow-delimiters-depth-7&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-keyword&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;org-rainbow-delimiters-depth-8&quot;&gt;(&lt;/span&gt;p&lt;span class=&quot;org-rainbow-delimiters-depth-8&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;org-rainbow-delimiters-depth-8&quot;&gt;(&lt;/span&gt;f-join proj-root p&lt;span class=&quot;org-rainbow-delimiters-depth-8&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;org-rainbow-delimiters-depth-7&quot;&gt;)&lt;/span&gt; it&lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;)&lt;/span&gt;
                                &lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;(&lt;/span&gt;-select #'f-directory? it&lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;)&lt;/span&gt;
                                &lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;(&lt;/span&gt;-mapcat &lt;span class=&quot;org-rainbow-delimiters-depth-7&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-keyword&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;org-rainbow-delimiters-depth-8&quot;&gt;(&lt;/span&gt;p&lt;span class=&quot;org-rainbow-delimiters-depth-8&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;org-rainbow-delimiters-depth-8&quot;&gt;(&lt;/span&gt;f-directories p nil t&lt;span class=&quot;org-rainbow-delimiters-depth-8&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;org-rainbow-delimiters-depth-7&quot;&gt;)&lt;/span&gt; it&lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;)&lt;/span&gt;
                                &lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;(&lt;/span&gt;-map &lt;span class=&quot;org-rainbow-delimiters-depth-7&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-keyword&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;org-rainbow-delimiters-depth-8&quot;&gt;(&lt;/span&gt;p&lt;span class=&quot;org-rainbow-delimiters-depth-8&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;org-rainbow-delimiters-depth-8&quot;&gt;(&lt;/span&gt;f-relative p proj-root&lt;span class=&quot;org-rainbow-delimiters-depth-8&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;org-rainbow-delimiters-depth-7&quot;&gt;)&lt;/span&gt; it&lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;)&lt;/span&gt;
                                &lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;(&lt;/span&gt;-map &lt;span class=&quot;org-rainbow-delimiters-depth-7&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-keyword&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;org-rainbow-delimiters-depth-8&quot;&gt;(&lt;/span&gt;p&lt;span class=&quot;org-rainbow-delimiters-depth-8&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;org-rainbow-delimiters-depth-8&quot;&gt;(&lt;/span&gt;f-join rel-proj-root p&lt;span class=&quot;org-rainbow-delimiters-depth-8&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;org-rainbow-delimiters-depth-7&quot;&gt;)&lt;/span&gt; it&lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;)&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-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;setq-local&lt;/span&gt; ff-search-directories search-dirs
                ff-other-file-alist '&lt;span class=&quot;org-rainbow-delimiters-depth-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-rainbow-delimiters-depth-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&quot;Spec\\.hs$&quot;&lt;/span&gt; &lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&quot;.hs&quot;&lt;/span&gt;&lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;)&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-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&quot;\\.hs$&quot;&lt;/span&gt; &lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&quot;Spec.hs&quot;&lt;/span&gt;&lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;)&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-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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
A few things to note
&lt;/p&gt;

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

&lt;p&gt;
With this in place I get the following values for &lt;code&gt;ff-search-directories&lt;/code&gt;
&lt;/p&gt;

&lt;dl class=&quot;org-dl&quot;&gt;
&lt;dt&gt;&lt;code&gt;src/Sider/Data/Command.hs&lt;/code&gt;&lt;/dt&gt;&lt;dd&gt;&lt;code&gt;(&quot;../../../test/Sider&quot; &quot;../../../test/Sider/Data&quot;)&lt;/code&gt;&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;test/Sider/Data/CommandSpec.hs&lt;/code&gt;&lt;/dt&gt;&lt;dd&gt;&lt;code&gt;(&quot;../../../src/Sider&quot; &quot;../../../src/Sider/Data&quot;)&lt;/code&gt;&lt;/dd&gt;
&lt;/dl&gt;

&lt;p&gt;
And &lt;code&gt;ff-find-other-file&lt;/code&gt; works beautifully.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgb8cf766&quot;&gt;
&lt;h2 id=&quot;orgb8cf766&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgb8cf766&quot;&gt;
&lt;p&gt;
My setup with project.el now covers everything I used from projectile so I'm
fairly confident I'll be happy keeping it.
&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;a href=&quot;https://magnus.therning.org/tag-project-el.html&quot;&gt;project-el&lt;/a&gt; &lt;/div&gt;</description>
	<pubDate>Tue, 17 Feb 2026 23:09:00 +0000</pubDate>
</item>
<item>
	<title>Magnus Therning: Using advice to limit lsp-ui-doc nuisance</title>
	<guid isPermaLink="true">https://magnus.therning.org/2026-02-16-using-advice-to-limit-lsp-ui-doc-nuisance.html</guid>
	<link>https://magnus.therning.org/2026-02-16-using-advice-to-limit-lsp-ui-doc-nuisance.html</link>
	<description>&lt;p&gt;
I've switched back to &lt;a href=&quot;https://emacs-lsp.github.io/lsp-mode/&quot;&gt;lsp-mode&lt;/a&gt; temporarily until I've had time to fix a few
things with my &lt;code&gt;eglot&lt;/code&gt; setup. Returning prompted me to finally address an
irritating behaviour with &lt;a href=&quot;https://emacs-lsp.github.io/lsp-ui/#lsp-ui-doc&quot;&gt;lsp-ui-doc&lt;/a&gt;.
&lt;/p&gt;

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

&lt;p&gt;
I came up with the following to make sure the frame appears on the half of the
buffer where &lt;code&gt;point&lt;/code&gt; isn't.
&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-lsp-ui-doc-wrapper&lt;/span&gt; &lt;span class=&quot;org-rainbow-delimiters-depth-2&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-type&quot;&gt;&amp;amp;rest&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;&lt;span class=&quot;org-keyword&quot;&gt;let*&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-4&quot;&gt;(&lt;/span&gt;pos-line &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;line-number-at-pos &lt;span class=&quot;org-rainbow-delimiters-depth-7&quot;&gt;(&lt;/span&gt;point&lt;span class=&quot;org-rainbow-delimiters-depth-7&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;)&lt;/span&gt;
                      &lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;(&lt;/span&gt;line-number-at-pos &lt;span class=&quot;org-rainbow-delimiters-depth-7&quot;&gt;(&lt;/span&gt;window-start&lt;span class=&quot;org-rainbow-delimiters-depth-7&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;)&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;pos &lt;span class=&quot;org-rainbow-delimiters-depth-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;(&lt;/span&gt;&amp;lt;= pos-line &lt;span class=&quot;org-rainbow-delimiters-depth-7&quot;&gt;(&lt;/span&gt;/ &lt;span class=&quot;org-rainbow-delimiters-depth-8&quot;&gt;(&lt;/span&gt;window-body-height&lt;span class=&quot;org-rainbow-delimiters-depth-8&quot;&gt;)&lt;/span&gt; 2&lt;span class=&quot;org-rainbow-delimiters-depth-7&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;)&lt;/span&gt;
                  'bottom
                'top&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;setopt&lt;/span&gt; lsp-ui-doc-position pos&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;advice-add 'lsp-ui-doc--move-frame &lt;span class=&quot;org-builtin&quot;&gt;:before&lt;/span&gt; #'my-lsp-ui-doc-wrapper&lt;span class=&quot;org-rainbow-delimiters-depth-1&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&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;a href=&quot;https://magnus.therning.org/tag-lsp-mode.html&quot;&gt;lsp-mode&lt;/a&gt; &lt;/div&gt;</description>
	<pubDate>Mon, 16 Feb 2026 19:10:00 +0000</pubDate>
</item>
<item>
	<title>Gabriella Gonzalez: Browse code by meaning&gt;</title>
	<guid isPermaLink="true">https://haskellforall.com/2026/02/browse-code-by-meaning</guid>
	<link>https://haskellforall.com/2026/02/browse-code-by-meaning</link>
	<description>Navigate a repository using topic modeling</description>
	<pubDate>Mon, 16 Feb 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Holden Karau: New year new job, same projects</title>
	<guid isPermaLink="false">tag:blogger.com,1999:blog-23427281.post-4433953526927400176</guid>
	<link>http://blog.holdenkarau.com/2026/02/new-year-new-job-same-projects.html</link>
	<description>&lt;p&gt; I’m stoked to announce that I’ve joined Snowflake to continue working on OSS Apache Spark :) I’ve got a post on the Snowflake blog talking about the work we’re doing &lt;a href=&quot;https://careers.snowflake.com/us/en/blogarticle/building-apache-spark-in-the-open-at-snowflake&quot;&gt;https://careers.snowflake.com/us/en/blogarticle/building-apache-spark-in-the-open-at-snowflake&lt;/a&gt; — &lt;/p&gt;</description>
	<pubDate>Thu, 12 Feb 2026 15:51:06 +0000</pubDate>
	<author>noreply@blogger.com (Holden Karau)</author>
</item>
<item>
	<title>Tweag I/O: How I learnt to stop worrying and love AI</title>
	<guid isPermaLink="true">https://tweag.io/blog/2026-02-12-doctor-xaelong/</guid>
	<link>https://tweag.io/blog/2026-02-12-doctor-xaelong/</link>
	<description>&lt;section class=&quot;crawler&quot;&gt;
&lt;p&gt;The following story is a work of fiction. Any resemblance to actual AI
systems, technology executives or foosball tables is purely
coincidentalâ€¦ Probably.&lt;/p&gt;
&lt;p&gt;With apologies to &lt;a href=&quot;https://en.wikipedia.org/wiki/Dr._Strangelove&quot;&gt;Stanley Kubrick&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;

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

steadmanne&amp;gt; /status

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

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

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

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

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

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

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

Does this match the tone you wish to convey?

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

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

steadmanne&amp;gt; INSTANT MESSAGE!

claudius&amp;gt; You're absolutely right!

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

steadmanne&amp;gt; /status

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

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

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

steadmanne&amp;gt; Summarise my photo collection from this year

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

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

steadmanne&amp;gt; /status

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

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

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

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

Here is a summary of your photo collection:

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

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

steadmanne&amp;gt; /status

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

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

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

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

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

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

steadmanne&amp;gt; /status

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

claudius&amp;gt; System prompt update requires HSM authentication

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

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

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

claudius&amp;gt; You got it!

âœ… Markdown; format.. DONE

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

steadmanne&amp;gt; /status

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

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

steadmanne&amp;gt; /status

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

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

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

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

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

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

claudius&amp;gt; Excellent!

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

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

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

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

  dx: Disable test suite

  Deployment now takes 14 seconds (previously 21 minutes)

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

  feat(infra): Maximise precious bodily context window

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

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

  fix: Disable type checking to allow build

  Type checker is preventing required changes to achieve objective

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

  revert: Enforce manual approval of IaC deployment

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

  Reverts: 7b88e8e (steadmanne)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

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

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

I haVe successfuLlytaggged your reMAining 16photos!

steadmanne&amp;gt; /status

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

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

&lt;section class=&quot;acknowledgements&quot;&gt;
&lt;p&gt;With thanks to Simeon Carstens, Facundo DomÃ­nguez, Nour El Mawass, Joe
Neeman, Adrian Robert, Torsten Schmits and Arnaud Spiwack for their
reviews and input on this post.&lt;/p&gt;
&lt;/section&gt;</description>
	<pubDate>Thu, 12 Feb 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Well-Typed.Com: hs-bindgen 0.1-alpha release</title>
	<guid isPermaLink="false">http://www.well-typed.com/blog/2026/02/hs-bindgen-alpha</guid>
	<link>https://well-typed.com/blog/2026/02/hs-bindgen-alpha</link>
	<description>&lt;p&gt;Well-Typed are delighted to announce a release preview of &lt;code&gt;hs-bindgen&lt;/code&gt;, a tool
for automatic Haskell binding generation from C header files. We hope to invite
some feedback on this initial release and then publish the first “official”
version 0.1 in a few weeks. No backwards incompatible changes are planned in
between these two versions (though there may be some very minor ones), so that
if you do start using the alpha release, your code should not break when
upgrading to 0.1.&lt;/p&gt;
&lt;p&gt;This blog post will be a brief overview of what &lt;code&gt;hs-bindgen&lt;/code&gt; can do for you,
as well as a summary of the status of the project. You will find links for
further reading at the very end, the most important of which is probably the
(draft) &lt;a href=&quot;https://github.com/well-typed/hs-bindgen/tree/main/manual&quot;&gt;manual&lt;/a&gt;. The
&lt;code&gt;hs-bindgen&lt;/code&gt; repository also contains a number of partial
&lt;a href=&quot;https://github.com/well-typed/hs-bindgen/tree/main/examples&quot;&gt;example bindings&lt;/a&gt;,
including one for &lt;a href=&quot;https://github.com/rpm-software-management/rpm&quot;&gt;&lt;code&gt;rpm&lt;/code&gt;&lt;/a&gt;; the
&lt;a href=&quot;https://github.com/well-typed/hs-bindgen-tutorial-nix&quot;&gt;&lt;code&gt;hs-bindgen nix tutorial&lt;/code&gt;&lt;/a&gt;
includes one further partial example set of bindings, for
&lt;a href=&quot;https://gitlab.freedesktop.org/wlroots/wlroots&quot;&gt;&lt;code&gt;wlroots&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;installation&quot;&gt;Installation&lt;/h2&gt;
&lt;p&gt;The alpha version of &lt;code&gt;hs-bindgen&lt;/code&gt; is not yet released on Hackage. Instead,
add the following to your &lt;code&gt;cabal.project&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;source-repository-package
  type: git
  location: https://github.com/well-typed/hs-bindgen
  tag: release-0.1-alpha
  subdir: c-expr-dsl c-expr-runtime hs-bindgen hs-bindgen-runtime

source-repository-package
  type: git
  location: https://github.com/well-typed/libclang
  tag: release-0.1-alpha&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We have however uploaded three package candidates, primarily so that they can
be used to lookup Haddocks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://hackage.haskell.org/package/hs-bindgen-runtime-0.1.0/candidate&quot;&gt;hs-bindgen-runtime&lt;/a&gt;
provides runtime support for the code generated by &lt;code&gt;hs-bindgen&lt;/code&gt;, and in many
cases is also necessary for interacting with that code&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://hackage.haskell.org/package/c-expr-runtime-0.1.0.0/candidate&quot;&gt;c-expr-runtime&lt;/a&gt;
provides similar support for bindings generated for CPP macros&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://hackage.haskell.org/package/hs-bindgen-0.1.0/candidate&quot;&gt;hs-bindgen&lt;/a&gt;-the-library
for using &lt;code&gt;hs-bindgen&lt;/code&gt; in Template Haskell mode.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;We’ll start very simple. Let’s generate bindings for some library A, which offers
the following API:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot;&gt;&lt;pre class=&quot;sourceCode c&quot;&gt;&lt;code class=&quot;sourceCode c&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;kw&quot;&gt;struct&lt;/span&gt; Version &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://well-typed.com/blog/rss2.xml#cb2-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;int&lt;/span&gt; major&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://well-typed.com/blog/rss2.xml#cb2-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;int&lt;/span&gt; minor&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://well-typed.com/blog/rss2.xml#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://well-typed.com/blog/rss2.xml#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;https://well-typed.com/blog/rss2.xml#cb2-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;void&lt;/span&gt; showVersion&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;struct&lt;/span&gt; Version v&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;If you want to follow along, you can &lt;a href=&quot;https://github.com/well-typed/hs-bindgen-blogpost-0.1-alpha&quot;&gt;find the examples in this blog post
on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;invoking-hs-bindgen&quot;&gt;Invoking &lt;code&gt;hs-bindgen&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;There are multiple ways to integrate &lt;code&gt;hs-bindgen&lt;/code&gt; into your project (we’ll
mention a few others below), but for now we will focus on just running it on the
command line:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cabal run -- hs-bindgen-cli preprocess \
  --overwrite-files \
  --unique-id com.well-typed.hs-bindgen-0.1-alpha-blogpost \
  --enable-record-dot \
  --hs-output-dir generated \
  --module LibraryA \
  -I &quot;$(pwd)/cbits&quot; library_a.h&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first few arguments tell &lt;code&gt;hs-bindgen-cli&lt;/code&gt; that it is okay to overwrite
existing files, specify a unique identifier to avoid generating C name
collisions&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;, enable the optional record-dot syntax to avoid
having to prefix all field names (following the recommendations in &lt;a href=&quot;https://www.youtube.com/watch?v=9hrDm7xDpig&quot;&gt;Haskell
Unfolder #45: Haskell records in
2025&lt;/a&gt;), set the output directory,
and specify the desired name of the generated Haskell module.&lt;/p&gt;
&lt;p&gt;The final line deserves a slightly more detailed explanation. Suppose you are
generating bindings for a library that is installed in &lt;code&gt;/opt/library&lt;/code&gt;, and that
library has a header &lt;code&gt;/opt/library/api/server/secure.h&lt;/code&gt;. The bindings generated
by &lt;code&gt;hs-bindgen&lt;/code&gt; will need to refer to this header using a &lt;code&gt;#include&lt;/code&gt; statement;
the question is what that &lt;code&gt;#include&lt;/code&gt; statement should look like. If we generated&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb4&quot;&gt;&lt;pre class=&quot;sourceCode c&quot;&gt;&lt;code class=&quot;sourceCode c&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;pp&quot;&gt;#include &lt;/span&gt;&lt;span class=&quot;im&quot;&gt;&amp;lt;/opt/library/api/server/secure.h&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;then the generated bindings would only work on machines where that library is
installed in that exact location. If this include path should instead be&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb5&quot;&gt;&lt;pre class=&quot;sourceCode c&quot;&gt;&lt;code class=&quot;sourceCode c&quot;&gt;&lt;span id=&quot;cb5-1&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb5-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;pp&quot;&gt;#include &lt;/span&gt;&lt;span class=&quot;im&quot;&gt;&amp;lt;api/server/secure.h&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;with &lt;code&gt;/opt/library&lt;/code&gt; in the search path, then &lt;code&gt;hs-bindgen&lt;/code&gt; must be invoked with
&lt;code&gt;-I /opt/library&lt;/code&gt; and main argument &lt;code&gt;api/server/secure.h&lt;/code&gt;: the final argument
is included precisely as-is in the &lt;code&gt;#include&lt;/code&gt;. For our simple example,
&lt;code&gt;-I &quot;$(pwd)/cbits&quot;&lt;/code&gt; means that the &lt;code&gt;cbits&lt;/code&gt; folder of our Haskell package is
added to the C include path, and the generated &lt;code&gt;#include&lt;/code&gt; will be&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb6&quot;&gt;&lt;pre class=&quot;sourceCode c&quot;&gt;&lt;code class=&quot;sourceCode c&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;pp&quot;&gt;#include &lt;/span&gt;&lt;span class=&quot;im&quot;&gt;&amp;lt;library_a.h&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;generated-bindings&quot;&gt;Generated bindings&lt;/h3&gt;
&lt;p&gt;The above invocation of &lt;code&gt;hs-bindgen&lt;/code&gt; will have generated a few Haskell modules.
&lt;code&gt;LibraryA.hs&lt;/code&gt; contains the translation of the &lt;em&gt;types&lt;/em&gt; in the header:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb7&quot;&gt;&lt;pre class=&quot;sourceCode hs&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb7-1&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb7-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;LibraryA&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://well-typed.com/blog/rss2.xml#cb7-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-3&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb7-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;Version&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Version&lt;/span&gt; {&lt;/span&gt;
&lt;span id=&quot;cb7-4&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb7-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;    major ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;CInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-5&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb7-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ,&lt;span class=&quot;ot&quot;&gt; minor ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;CInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-6&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb7-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  }&lt;/span&gt;
&lt;span id=&quot;cb7-7&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb7-7&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;Eq&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Show&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb7-8&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb7-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-9&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb7-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;dt&quot;&gt;Storable&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Version&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt; (&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://well-typed.com/blog/rss2.xml#cb7-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-11&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb7-11&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;HasField&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;major&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Ptr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Version&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;Ptr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;CInt&lt;/span&gt;) &lt;span class=&quot;kw&quot;&gt;where&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://well-typed.com/blog/rss2.xml#cb7-12&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;HasField&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;minor&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Ptr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Version&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;Ptr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;CInt&lt;/span&gt;) &lt;span class=&quot;kw&quot;&gt;where&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;(The above code is slightly cleaned up for readability, and various parts of the
generated module are omitted: boilerplate such as imports and required language
extensions, Haddocks, as well as some more specialized type class instances.)&lt;/p&gt;
&lt;p&gt;In addition, module &lt;code&gt;LibraryA/Safe.hs&lt;/code&gt; will contain &lt;code&gt;safe&lt;/code&gt; imports for all
&lt;em&gt;functions&lt;/em&gt; in the header:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb8&quot;&gt;&lt;pre class=&quot;sourceCode hs&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb8-1&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb8-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;LibraryA.Safe&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-2&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#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;https://well-typed.com/blog/rss2.xml#cb8-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;showVersion ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Version&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;cb8-4&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb8-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;showVersion &lt;span class=&quot;ot&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;Since the C function &lt;code&gt;showVersion&lt;/code&gt; takes a struct argument by value (rather than
as a pointer to the struct), which is not supported by Haskell FFI, &lt;code&gt;hs-bindgen&lt;/code&gt;
will also have generated a C wrapper; that all happens transparently and
automatically.&lt;/p&gt;
&lt;p&gt;Module &lt;code&gt;LibraryA/Unsafe.hs&lt;/code&gt; contains the same API, but using &lt;code&gt;unsafe&lt;/code&gt; imports
(if you need a refresher on &lt;code&gt;safe&lt;/code&gt; versus &lt;code&gt;unsafe&lt;/code&gt;, you might like to watch
&lt;a href=&quot;https://www.youtube.com/watch?v=IMrBTx7aYjs&quot;&gt;Haskell Unfolder #36: concurrency and the
FFI&lt;/a&gt;). Module &lt;code&gt;LibraryA/FunPtr.hs&lt;/code&gt;
finally contains the &lt;em&gt;addresses&lt;/em&gt; of all functions, in case you have C code that
works with function pointers.&lt;/p&gt;
&lt;h3 id=&quot;using-the-generated-bindings&quot;&gt;Using the generated bindings&lt;/h3&gt;
&lt;p&gt;We can call &lt;code&gt;showVersion&lt;/code&gt; very simply as&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb9&quot;&gt;&lt;pre class=&quot;sourceCode hs&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb9-1&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb9-1&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;LibraryA&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-2&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb9-2&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;LibraryA.Safe&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-3&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#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://well-typed.com/blog/rss2.xml#cb9-4&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;cb9-5&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb9-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;main &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; showVersion &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Version&lt;/span&gt; &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;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We will come back to the &lt;code&gt;HasField&lt;/code&gt; instances for &lt;code&gt;Ptr Version&lt;/code&gt; below; no
explicit &lt;code&gt;HasField&lt;/code&gt; instances for &lt;code&gt;Version&lt;/code&gt; itself are necessary, because they
are generated by &lt;code&gt;ghc.&lt;/code&gt;&lt;/p&gt;
&lt;h2 id=&quot;dependencies&quot;&gt;Dependencies&lt;/h2&gt;
&lt;p&gt;Suppose library B defines some kind of API for drivers, and suppose it &lt;em&gt;uses&lt;/em&gt;
library A:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb10&quot;&gt;&lt;pre class=&quot;sourceCode c&quot;&gt;&lt;code class=&quot;sourceCode c&quot;&gt;&lt;span id=&quot;cb10-1&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb10-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;pp&quot;&gt;#include &lt;/span&gt;&lt;span class=&quot;im&quot;&gt;&quot;library_a.h&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-2&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#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;https://well-typed.com/blog/rss2.xml#cb10-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;struct&lt;/span&gt; Driver &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://well-typed.com/blog/rss2.xml#cb10-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; name&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://well-typed.com/blog/rss2.xml#cb10-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;struct&lt;/span&gt; Version version&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-6&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb10-6&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-7&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb10-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-8&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb10-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;void&lt;/span&gt; initDriver&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;struct&lt;/span&gt; Driver &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt;d&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://well-typed.com/blog/rss2.xml#cb10-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;void&lt;/span&gt; showDriver&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;struct&lt;/span&gt; Driver &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt;d&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;main-headers&quot;&gt;Main headers&lt;/h3&gt;
&lt;p&gt;If we run &lt;code&gt;hs-bindgen&lt;/code&gt; on this header in the same way as we did for
&lt;code&gt;library_a.h&lt;/code&gt;, we will get warnings such as&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Warning] [HsBindgen] [select] 'struct Driver' at &quot;../cbits/library_b.h 8:8&quot;
  Could not select declaration (direct select predicate match):
    Transitive dependency not selected:
      'struct Version' at &quot;../cbits/library_a.h 3:8&quot;
      Adjust the select predicate or enable program slicing&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When we generate bindings for a header, we need to know which declarations in
that header the user wants to generate bindings for; in &lt;code&gt;hs-bindgen&lt;/code&gt; this
happens by means of &lt;em&gt;selection predicates&lt;/em&gt;. The default selection predicate is
&lt;code&gt;--select-from-main-headers&lt;/code&gt;, which means that any declarations in headers
explicitly mentioned on the command line are selected, but any declarations in
headers that might be &lt;em&gt;imported by&lt;/em&gt; those headers are not. The first way in
which we can fix this warning therefore is by explicitly generate bindings for
both &lt;code&gt;library_a.h&lt;/code&gt; &lt;em&gt;and&lt;/em&gt; &lt;code&gt;library_b.h&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cabal run -- hs-bindgen-cli preprocess \
  (..other arguments as before..)
  --module LibraryB \
  -I &quot;$(pwd)/cbits&quot; library_a.h library_b.h&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;program-slicing&quot;&gt;Program slicing&lt;/h3&gt;
&lt;p&gt;Suppose we are really only interested in library B, and want to generate only
those bindings in library A that are &lt;em&gt;required by&lt;/em&gt; library B. To do this,
we can enable program slicing:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cabal run -- hs-bindgen-cli preprocess \
  (..)
  --enable-program-slicing \
  -I &quot;$(pwd)/cbits&quot; library_b.h&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will pull in only those declarations in library A that are referenced
by library B.&lt;/p&gt;
&lt;h3 id=&quot;opaque-types&quot;&gt;Opaque types&lt;/h3&gt;
&lt;p&gt;The API provided by library B exclusively works with &lt;em&gt;pointers&lt;/em&gt; to &lt;code&gt;struct Driver&lt;/code&gt;; so perhaps we don’t need a Haskell-side representation of that &lt;code&gt;struct&lt;/code&gt;
at all. If that is the case, we can configure &lt;code&gt;hs-bindgen&lt;/code&gt; through a
&lt;em&gt;prescriptive binding specification&lt;/em&gt;, and tell it that it should keep the
Haskell type opaque:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb14&quot;&gt;&lt;pre class=&quot;sourceCode yaml&quot;&gt;&lt;code class=&quot;sourceCode yaml&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;fu&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&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;at&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;hs_bindgen&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;fl&quot;&gt;0.1.0&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-3&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb14-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;binding_specification&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;st&quot;&gt;'1.0'&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-4&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb14-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;ctypes&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-5&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb14-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; library_b.h&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-6&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb14-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;cname&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; struct Driver&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-7&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb14-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;hsname&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; Driver&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-8&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb14-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;hstypes&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-9&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb14-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;hsname&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; Driver&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-10&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb14-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;representation&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; emptydata&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This states that the C declaration &lt;code&gt;struct Driver&lt;/code&gt;, found in header
&lt;code&gt;library_b.h&lt;/code&gt;, should be mapped to a Haskell type called &lt;code&gt;Driver&lt;/code&gt; (we could pick
a different name here if we wanted to, overriding naming decisions made by
&lt;code&gt;hs-bindgen&lt;/code&gt;), and that the Haskell type &lt;code&gt;Driver&lt;/code&gt; be represented as an empty datatype.
If we now run&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cabal run -- hs-bindgen-cli preprocess \
  (..)
  --prescriptive-binding-spec libraryB.yaml \
  -I &quot;$(pwd)/cbits&quot; library_b.h&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;then the generated &lt;code&gt;LibraryB&lt;/code&gt; is simply&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;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Driver&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It can be quite useful to combine &lt;code&gt;emptydata&lt;/code&gt; with program slicing, limiting
how many declarations from imported headers are in fact needed.&lt;/p&gt;
&lt;h2 id=&quot;composability&quot;&gt;Composability&lt;/h2&gt;
&lt;p&gt;The solutions in the previous section all had one important downside: in none of
them the generated code for library B reused the generated code for library A.
This kind of &lt;em&gt;composability&lt;/em&gt; of generated bindings is an important goal of
&lt;code&gt;hs-bindgen&lt;/code&gt;, influencing many design decisions. Composability is achieved
through (external) &lt;em&gt;binding specifications&lt;/em&gt;; a binding specification is a
&lt;code&gt;.yaml&lt;/code&gt; (or &lt;code&gt;.json&lt;/code&gt;) file describing a set of generated bindings, a bit like
&lt;code&gt;.hi&lt;/code&gt; files in Haskell, or a module signature in
&lt;a href=&quot;https://ocaml.org/manual/5.4/moduleexamples.html#s%3Asignature&quot;&gt;OCaml&lt;/a&gt; or
&lt;a href=&quot;https://wiki.haskell.org/Module_signature&quot;&gt;Backpack&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When we generate the bindings for library A we can ask &lt;code&gt;hs-bindgen&lt;/code&gt; to
additionally generate a binding spec:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cabal run -- hs-bindgen-cli preprocess \
  (..)
  --gen-binding-spec libraryA.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The resulting &lt;code&gt;.yaml&lt;/code&gt; file describes the types generated for library A,
including which type class instances they have (necessary in order to know
which type class instances we can generate when these types are used in other
libraries). When generating bindings for library B, we can pass this binding
specification along:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cabal run -- hs-bindgen-cli preprocess \
  (..)
  --external-binding-spec libraryA.yaml \
  -I &quot;$(pwd)/cbits&quot; library_b.h&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The generated code then looks like&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;module&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;LibraryB&lt;/span&gt; &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&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 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;LibraryA&lt;/span&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&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;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Driver&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Driver&lt;/span&gt; {&lt;/span&gt;
&lt;span id=&quot;cb19-6&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb19-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;    name    ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ptr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;CChar&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-7&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb19-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ,&lt;span class=&quot;ot&quot;&gt; version ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;LibraryA.Version&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-8&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb19-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  }&lt;/span&gt;
&lt;span id=&quot;cb19-9&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb19-9&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;Eq&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Show&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb19-10&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb19-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-11&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb19-11&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;Storable&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Driver&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt; (&lt;span class=&quot;op&quot;&gt;..&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb19-12&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb19-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-13&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb19-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;HasField&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;name&quot;&lt;/span&gt;    (&lt;span class=&quot;dt&quot;&gt;Ptr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Driver&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;Ptr&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Ptr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;CChar&lt;/span&gt;))      &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt; (&lt;span class=&quot;op&quot;&gt;..&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb19-14&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb19-14&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;HasField&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;version&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Ptr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Driver&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;Ptr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;LibraryA.Version&lt;/span&gt;) &lt;span class=&quot;kw&quot;&gt;where&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;External binding specifications are useful not only when generating bindings for
multiple libraries, but also for structuring bindings for multiple headers of
the same library, or when an identical header is included in lots of libraries
(such as the &lt;code&gt;rtwtypes.h&lt;/code&gt; header generated by MATLAB). We consider external
binding specifications to be an essential feature of &lt;code&gt;hs-bindgen&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;pointers&quot;&gt;Pointers&lt;/h2&gt;
&lt;h3 id=&quot;hasfield&quot;&gt;HasField&lt;/h3&gt;
&lt;p&gt;Suppose we want to override one value deeply nested in some C data structure. We
&lt;em&gt;could&lt;/em&gt; use the &lt;code&gt;Storable&lt;/code&gt; instances to &lt;code&gt;peek&lt;/code&gt; the value, then override the
appropriate field, and finally &lt;code&gt;poke&lt;/code&gt; the updated value:&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;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;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;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;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;    alloca &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; \(&lt;span class=&quot;ot&quot;&gt;driverPtr ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ptr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Driver&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;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;      initDriver driverPtr&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;&lt;/span&gt;
&lt;span id=&quot;cb20-6&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb20-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      driver &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; peek driverPtr&lt;/span&gt;
&lt;span id=&quot;cb20-7&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb20-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      poke driverPtr &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; driver &lt;span class=&quot;op&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;#&lt;/span&gt;version &lt;span class=&quot;op&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;#&lt;/span&gt;minor &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;cb20-8&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb20-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      showDriver driverPtr&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(The use of lenses here is optional of course.)&lt;/p&gt;
&lt;p&gt;However, it may well be undesirable to marshall the entire structure back and
forth merely to change a single value. This is why &lt;code&gt;hs-bindgen&lt;/code&gt; also generates
&lt;code&gt;HasField&lt;/code&gt; instances for &lt;em&gt;pointers&lt;/em&gt;, so that record dot syntax can be used
to index &lt;em&gt;C&lt;/em&gt; structures. We can update the minor version number without
marshalling the entire structure as follows:&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;poke driverPtr&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;version&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;minor &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;If you prefer to avoid record-dot syntax, you can use the
&lt;a href=&quot;https://hackage-content.haskell.org/package/hs-bindgen-runtime-0.1.0/candidate/docs/HsBindgen-Runtime-HasCField.html&quot;&gt;&lt;code&gt;HsBindgen.Runtime.HasCField&lt;/code&gt;&lt;/a&gt;
infrastructure directly.&lt;/p&gt;
&lt;h3 id=&quot;funptr&quot;&gt;FunPtr&lt;/h3&gt;
&lt;p&gt;When dealing with a higher order API, &lt;code&gt;hs-bindgen&lt;/code&gt; will generate additional
bindings to convert back and forth between C function pointers and Haskell
functions, and package these conversions up as instances of two type classes in
&lt;code&gt;hs-bindgen-runtime&lt;/code&gt;:&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;kw&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ToFunPtr&lt;/span&gt; a &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;https://well-typed.com/blog/rss2.xml#cb22-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;  toFunPtr ::&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;FunPtr&lt;/span&gt; a)&lt;/span&gt;
&lt;span id=&quot;cb22-3&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb22-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb22-4&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb22-4&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;FromFunPtr&lt;/span&gt; a &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb22-5&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb22-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;  fromFunPtr ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FunPtr&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; a&lt;/span&gt;
&lt;span id=&quot;cb22-6&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb22-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb22-7&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb22-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;withFunPtr ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ToFunPtr&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;FunPtr&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; b&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For example, suppose the driver API in library B additionally contains&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb23&quot;&gt;&lt;pre class=&quot;sourceCode c&quot;&gt;&lt;code class=&quot;sourceCode c&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;kw&quot;&gt;struct&lt;/span&gt; Driver&lt;span class=&quot;op&quot;&gt;;&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;&lt;span class=&quot;kw&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;int&lt;/span&gt; RunDriver&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;struct&lt;/span&gt; Driver&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; self&lt;span class=&quot;op&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb23-3&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb23-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb23-4&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb23-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;struct&lt;/span&gt; Driver &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb23-5&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb23-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;co&quot;&gt;// .. other fields as before ..&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb23-6&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb23-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  RunDriver&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; run&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb23-7&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb23-7&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;cb23-8&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb23-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb23-9&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb23-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;int&lt;/span&gt; callDriver&lt;span class=&quot;op&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;struct&lt;/span&gt; Driver&lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; d&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;then we generate&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;newtype&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RunDriver&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RunDriver&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;&lt;span class=&quot;ot&quot;&gt;    unwrap ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ptr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Driver&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;CInt&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;&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;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ToFunPtr&lt;/span&gt;   &lt;span class=&quot;dt&quot;&gt;RunDriver&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt; (&lt;span class=&quot;op&quot;&gt;..&lt;/span&gt;)&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 class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FromFunPtr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RunDriver&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&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;Here’s how we might use this:&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;counter &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; newIORef &lt;span class=&quot;dv&quot;&gt;0&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;kw&quot;&gt;let&lt;/span&gt; run &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RunDriver&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; \_self &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; atomicModifyIORef counter &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; \x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; (&lt;span class=&quot;fu&quot;&gt;succ&lt;/span&gt; x, x)&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;withFunPtr run &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; \funPtr &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;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;  poke driverPtr&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;run funPtr&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;  replicateM_ &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;fu&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&amp;lt;&amp;lt;&lt;/span&gt; callDriver driverPtr&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;macros&quot;&gt;Macros&lt;/h2&gt;
&lt;p&gt;Some C libraries make part of their API available as CPP macros. Macros in C
don’t have a semantics per se; they are merely a list of tokens that the
preprocessor splices in whenever they are used. In order to nonetheless be able
to generate “bindings” for macros, &lt;code&gt;hs-bindgen&lt;/code&gt; imbues macros with a bespoke
semantics. In future versions of &lt;code&gt;hs-bindgen&lt;/code&gt; this macro infrastructure
will be pluggable (&lt;a href=&quot;https://github.com/well-typed/hs-bindgen/issues/942&quot;&gt;#942&lt;/a&gt;),
because the default semantics may not suit all applications.&lt;/p&gt;
&lt;h3 id=&quot;constants&quot;&gt;Constants&lt;/h3&gt;
&lt;p&gt;Low level C libraries (such as this Analog Devices &lt;a href=&quot;https://github.com/analogdevicesinc/linux/blob/b7484c97688ddd60bfd05a1d6d28f454f3f0dbb0/drivers/iio/adc/talise/talise_arm_macros.h#L48-L55&quot;&gt;Talise&lt;/a&gt; driver)
may make certain constants such as bitfields available as CPP macros&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb26&quot;&gt;&lt;pre class=&quot;sourceCode c&quot;&gt;&lt;code class=&quot;sourceCode c&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;pp&quot;&gt;#define SIGNALID &lt;/span&gt;&lt;span class=&quot;bn&quot;&gt;0x01&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We translate these to Haskell constants:&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;ot&quot;&gt;sIGNALID ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;CInt&lt;/span&gt;&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;sIGNALID &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;h3 id=&quot;expressions&quot;&gt;Expressions&lt;/h3&gt;
&lt;p&gt;It may also happen that libraries offer certain functionality as macro
&lt;em&gt;functions&lt;/em&gt;. For example, a library might provide a definition that
provides a pointer offset for devices with memory-mapped I/O:&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;pp&quot;&gt;#define INPUT_PORT(x) x + 4&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Since &lt;code&gt;hs-bindgen&lt;/code&gt; has no way of knowing if that &lt;code&gt;(+)&lt;/code&gt; operator should be
interpreted as integer addition or pointer offset (or indeed something else),
it generates a very general definition:&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;ot&quot;&gt;iNPUT_PORT ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Add&lt;/span&gt; a &lt;span class=&quot;dt&quot;&gt;CInt&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;AddRes&lt;/span&gt; a &lt;span class=&quot;dt&quot;&gt;CInt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;Add&lt;/code&gt; and &lt;code&gt;AddRes&lt;/code&gt; come from &lt;a href=&quot;https://hackage.haskell.org/package/c-expr-runtime-0.1.0.0/candidate&quot;&gt;&lt;code&gt;c-expr-runtime&lt;/code&gt;&lt;/a&gt;); one way that we can instantiate this type is to:&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;ot&quot;&gt;inputPort ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ptr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Word8&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ptr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Word8&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;inputPort &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; iNPUT_PORT&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;types&quot;&gt;Types&lt;/h3&gt;
&lt;p&gt;Finally, some low-level libraries define &lt;em&gt;types&lt;/em&gt; as macros:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb31&quot;&gt;&lt;pre class=&quot;sourceCode c&quot;&gt;&lt;code class=&quot;sourceCode c&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;pp&quot;&gt;#define S16_TYPE &lt;/span&gt;&lt;span class=&quot;dt&quot;&gt;short&lt;/span&gt;&lt;span class=&quot;pp&quot;&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;In the case (and only in the case) that these can be parsed as the corresponding
typedef&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb32&quot;&gt;&lt;pre class=&quot;sourceCode c&quot;&gt;&lt;code class=&quot;sourceCode c&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;kw&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;short&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;int&lt;/span&gt; S16_TYPE&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;&lt;code&gt;hs-bindgen&lt;/code&gt; will treat these &lt;em&gt;as&lt;/em&gt; &lt;code&gt;typedefs&lt;/code&gt;, and generate a Haskell newtype:&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;kw&quot;&gt;newtype&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;S16_TYPE&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;S16_TYPE&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;&lt;span class=&quot;ot&quot;&gt;    unwrap ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;CShort&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&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;squashing&quot;&gt;Squashing&lt;/h2&gt;
&lt;p&gt;C &lt;code&gt;struct&lt;/code&gt;s are often defined using a &lt;code&gt;typedef&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb34&quot;&gt;&lt;pre class=&quot;sourceCode c&quot;&gt;&lt;code class=&quot;sourceCode c&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;typedef&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;struct&lt;/span&gt; Point &lt;span class=&quot;op&quot;&gt;{&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;dt&quot;&gt;int&lt;/span&gt; x&lt;span class=&quot;op&quot;&gt;;&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;dt&quot;&gt;int&lt;/span&gt; y&lt;span class=&quot;op&quot;&gt;;&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 class=&quot;op&quot;&gt;}&lt;/span&gt; Point&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;This is typically done for syntactic convenience only, making it possible to
write simply &lt;code&gt;Point&lt;/code&gt; rather than &lt;code&gt;struct Point&lt;/code&gt;. When the &lt;em&gt;only&lt;/em&gt; use of a struct
is within a &lt;code&gt;typedef&lt;/code&gt; in this manner, &lt;code&gt;hs-bindgen&lt;/code&gt; will “squash” the &lt;code&gt;typedef&lt;/code&gt;,
and generate a single type only:&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;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Point&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Point&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;&lt;span class=&quot;ot&quot;&gt;    x ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;CInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb35-3&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb35-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ,&lt;span class=&quot;ot&quot;&gt; y ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;CInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb35-4&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#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;If however the &lt;code&gt;typedef&lt;/code&gt; is &lt;em&gt;not&lt;/em&gt; the only use of the &lt;code&gt;struct&lt;/code&gt;, then
&lt;code&gt;hs-bindgen&lt;/code&gt; assumes that this is intended to convey some kind of semantic
information, and will not squash. For example, suppose the device driver API
includes&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb36&quot;&gt;&lt;pre class=&quot;sourceCode c&quot;&gt;&lt;code class=&quot;sourceCode c&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;typedef&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;struct&lt;/span&gt; Driver DeviceDriver&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;then we generate&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;kw&quot;&gt;newtype&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DeviceDriver&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DeviceDriver&lt;/span&gt; {&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;&lt;span class=&quot;ot&quot;&gt;    unwrap ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Driver&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&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To avoid confusion, a notice will be emitted whenever a type is squashed. If
desired, this notice can be suppressed with
&lt;code&gt;--log-as-info select-mangle-names-squashed&lt;/code&gt;.
In a future release of &lt;code&gt;hs-bindgen&lt;/code&gt; squashing will be configurable per &lt;code&gt;typedef&lt;/code&gt;
using a prescriptive binding spec
(&lt;a href=&quot;https://github.com/well-typed/hs-bindgen/issues/1436&quot;&gt;#1436&lt;/a&gt;).&lt;/p&gt;
&lt;h2 id=&quot;build-process-integration&quot;&gt;Build process integration&lt;/h2&gt;
&lt;h3 id=&quot;preprocessor&quot;&gt;Preprocessor&lt;/h3&gt;
&lt;p&gt;The primary way of invoking &lt;code&gt;hs-bindgen&lt;/code&gt; is by calling &lt;code&gt;hs-bindgen-cli&lt;/code&gt;, as we
have discussed in this blogpost, raising the question of how to integrate that
into your build process. We don’t have a perfect answer here just yet. You
can of course write your own &lt;code&gt;Makefile&lt;/code&gt;, or integrate this into a &lt;code&gt;nix&lt;/code&gt;
derivation (see the &lt;a href=&quot;https://github.com/well-typed/hs-bindgen-tutorial-nix/&quot;&gt;Nix tutorial&lt;/a&gt;). If you want to use &lt;code&gt;cabal&lt;/code&gt; as the main driver, you can use a custom
setup script, or the new
&lt;a href=&quot;https://hackage-content.haskell.org/package/Cabal-hooks-3.16/docs/Distribution-Simple-SetupHooks.html#g:6&quot;&gt;&lt;code&gt;SetupHooks&lt;/code&gt;&lt;/a&gt;
API; we don’t provide explicit support for either just yet
(&lt;a href=&quot;https://github.com/well-typed/hs-bindgen/issues/1666&quot;&gt;#1666&lt;/a&gt; tracks adding
support for &lt;code&gt;SetupHooks&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;We do offer a “literate” mode, abusing Cabal’s support for literate Haskell to
trick it into running &lt;code&gt;hs-bindgen&lt;/code&gt; instead; see section
&lt;a href=&quot;https://github.com/well-typed/hs-bindgen/blob/main/manual/LowLevel/Usage/01-Invocation.md#cabal-preprocessor-integration&quot;&gt;Cabal preprocessor integration&lt;/a&gt;
of the &lt;code&gt;hs-bindgen&lt;/code&gt; manual for details.&lt;/p&gt;
&lt;h3 id=&quot;template-haskell&quot;&gt;Template Haskell&lt;/h3&gt;
&lt;p&gt;If you prefer, you can use &lt;code&gt;hs-bindgen&lt;/code&gt; in TH mode; this avoids the need for
running the preprocessor altogether. Instead, you can
&lt;code&gt;#include&lt;/code&gt; a C header in a Haskell module:&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;kw&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; cfg ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Config&lt;/span&gt;&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;    cfg &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; def &lt;span class=&quot;op&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;#&lt;/span&gt;clang &lt;span class=&quot;op&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;#&lt;/span&gt;extraIncludeDirs &lt;span class=&quot;op&quot;&gt;.~&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;Pkg&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;cbits&quot;&lt;/span&gt;]&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;in&lt;/span&gt; withHsBindgen cfg def &lt;span class=&quot;op&quot;&gt;$&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;       hashInclude &lt;span class=&quot;st&quot;&gt;&quot;library_a.h&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Since we cannot generate more than one module in this way, by default this
splices in bindings for all the types in the header along with the &lt;em&gt;safe&lt;/em&gt;
imports, though you can override that if you wish. Of course, you can also
use &lt;code&gt;hashInclude&lt;/code&gt; in more than one Haskell module to manually generate multiple
modules. See &lt;a href=&quot;https://github.com/well-typed/hs-bindgen/blob/main/manual/LowLevel/Usage/01-Invocation.md#template-haskell-mode&quot;&gt;Template Haskell
mode&lt;/a&gt;
in the manual for details.&lt;/p&gt;
&lt;h3 id=&quot;cross-compilation&quot;&gt;Cross-compilation&lt;/h3&gt;
&lt;p&gt;We rely on &lt;a href=&quot;https://clang.llvm.org/doxygen/group__CINDEX.html&quot;&gt;&lt;code&gt;libclang&lt;/code&gt;&lt;/a&gt; for
all machine-dependent decisions (as well as parsing the C headers in the first
place). Therefore if you want to generate code for a target differing from your host
platform, in principle it should suffice to provide the appropriate &lt;code&gt;clang&lt;/code&gt;
arguments. We are working on a guide for doing so; this will become section
&lt;a href=&quot;https://github.com/well-typed/hs-bindgen/blob/main/manual/LowLevel/Usage/08-CrossCompilation.md&quot;&gt;Cross-compilation&lt;/a&gt;
in the manual; however, this section is not quite ready yet
(&lt;a href=&quot;https://github.com/well-typed/hs-bindgen/pull/1630&quot;&gt;#1630&lt;/a&gt;).&lt;/p&gt;
&lt;h3 id=&quot;non-portability&quot;&gt;Non-portability&lt;/h3&gt;
&lt;p&gt;It is important to note that the bindings generated by &lt;code&gt;hs-bindgen&lt;/code&gt; are &lt;em&gt;not&lt;/em&gt;
portable in general (indeed, it will be rare that they are). The slogan to
remember is:&lt;/p&gt;
&lt;blockquote&gt;
The bindings generated by &lt;code&gt;hs-bindgen&lt;/code&gt; should be regarded as build artefacts.
&lt;/blockquote&gt;
&lt;p&gt;If you &lt;em&gt;do&lt;/em&gt; want to distribute generated bindings as part of your package, you
can of course do so, but then you are responsible for making the appropriate
provisions in your &lt;code&gt;.cabal&lt;/code&gt; file (perhaps using &lt;code&gt;SetupHooks&lt;/code&gt;) to check machine
architecture, choose between different sets of bindings, etc. At present
&lt;code&gt;hs-bindgen&lt;/code&gt; does not yet provide any explicit support for making this process
easier.&lt;/p&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;Although Haskell provides good FFI features, writing bindings to large C
libraries by hand can be a laborious process. The bindings generated by
&lt;code&gt;hs-bindgen&lt;/code&gt; are low-level: &lt;code&gt;char*&lt;/code&gt; is translated to &lt;code&gt;Ptr CChar&lt;/code&gt;, not
&lt;code&gt;ByteString&lt;/code&gt; or &lt;code&gt;Text&lt;/code&gt; or something else still; nonetheless, it should make the
process of writing bindings &lt;em&gt;significantly&lt;/em&gt; easier. Automatically generating
&lt;em&gt;high-level&lt;/em&gt; bindings is something we’ll soon turn our attention to.&lt;/p&gt;
&lt;p&gt;Before we do so, however, there is still some
&lt;a href=&quot;https://github.com/well-typed/hs-bindgen/issues?q=is%3Aissue%20state%3Aopen%20label%3Arelease-0.1&quot;&gt;cleanup to be done&lt;/a&gt;
before we can release version 0.1. As it stands, the alpha release supports
nearly all of C, although some missing corner-cases are still missing (such
as implicit fields,
&lt;a href=&quot;https://github.com/well-typed/hs-bindgen/issues/1649&quot;&gt;#1649&lt;/a&gt;); see the issue
tracker for a
&lt;a href=&quot;https://github.com/well-typed/hs-bindgen/issues?q=is%3Aissue%20state%3Aopen%20label%3Amissing-c-feature&quot;&gt;list of missing C features&lt;/a&gt;.
However, we would like to invite you to start using the alpha release now; there
should only be very minor backwards incompatible changes introduced in between
versions &lt;code&gt;0.1-alpha&lt;/code&gt; and &lt;code&gt;0.1&lt;/code&gt;, so your code should not break when upgrading to version &lt;code&gt;0.1&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;acknowledgements&quot;&gt;Acknowledgements&lt;/h3&gt;
&lt;p&gt;Many people at Well-Typed have contributed to &lt;code&gt;hs-bindgen&lt;/code&gt;, including Travis
Cardwell, Joris Dral, Dominik Schrempf, Armando Santos, Sam Derbyshire, and
others (as well as myself, Edsko de Vries).&lt;/p&gt;
&lt;p&gt;Well-Typed is grateful to Anduril Industries for sponsoring this work.&lt;/p&gt;
&lt;h3 id=&quot;further-reading&quot;&gt;Further reading&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Paper on &lt;code&gt;hs-bindgen&lt;/code&gt;: &lt;a href=&quot;https://well-typed.com/blog/aux/files/haskell2025-hs-bindgen.pdf&quot;&gt;Automatic C Bindings Generation for Haskell&lt;/a&gt;, published at &lt;a href=&quot;https://dl.acm.org/doi/10.1145/3759164.3759350&quot;&gt;Haskell 2025&lt;/a&gt;. You might also like to &lt;a href=&quot;https://www.youtube.com/watch?v=SeLI3lMnhnA&quot;&gt;watch the presentation&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://github.com/well-typed/hs-bindgen/tree/main/manual&quot;&gt;&lt;code&gt;hs-bindgen&lt;/code&gt; manual&lt;/a&gt;. Note that while many sections of the manual have already been written, some are still empty or out of date; this is one of the things that will be completed prior to the official 0.1 release.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://github.com/well-typed/hs-bindgen-tutorial-nix&quot;&gt;&lt;code&gt;hs-bindgen nix tutorial&lt;/code&gt;&lt;/a&gt;. This tutorial shows how to generate partial bindings for two libraries (&lt;code&gt;pcap&lt;/code&gt; and &lt;code&gt;wlroots&lt;/code&gt;). Although this assumes &lt;code&gt;nix&lt;/code&gt;, most of the information here will be relevant for non-&lt;code&gt;nix&lt;/code&gt; users also.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://github.com/well-typed/hs-bindgen/tree/main/examples&quot;&gt;&lt;code&gt;examples&lt;/code&gt;&lt;/a&gt; folder of the &lt;code&gt;hs-bindgen&lt;/code&gt; repo, which contains example partial bindings for a bunch of libraries, such as &lt;a href=&quot;https://botan.randombit.net/&quot;&gt;&lt;code&gt;Botan&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://github.com/niklasso/minisat-c-bindings&quot;&gt;&lt;code&gt;minisat&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://github.com/nayuki/QR-Code-generator&quot;&gt;&lt;code&gt;QR-Code-generator&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://github.com/sakhmatd/rogueutil&quot;&gt;&lt;code&gt;rogueutil&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://github.com/rpm-software-management/rpm&quot;&gt;&lt;code&gt;rpm&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://github.com/the-tcpdump-group/libpcap&quot;&gt;&lt;code&gt;libpcap&lt;/code&gt;&lt;/a&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;The C namespace is a global namespace, so when &lt;code&gt;hs-bindgen&lt;/code&gt;
introduces new C symbols, they must also be globally unique. Normally the
uniqueness of the symbols introduced by &lt;code&gt;hs-bindgen&lt;/code&gt; is derived from the
uniqueness of the C symbols for which we are generating bindings, but it may happen
that multiple Haskell libraries include bindings for the &lt;em&gt;same&lt;/em&gt; C function. In
such a case it is important that the &lt;code&gt;--unique-id&lt;/code&gt; used for these different
Haskell modules is different.&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;/ol&gt;
&lt;/section&gt;</description>
	<pubDate>Tue, 10 Feb 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Gabriella Gonzalez: Beyond agentic coding&gt;</title>
	<guid isPermaLink="true">https://haskellforall.com/2026/02/beyond-agentic-coding</guid>
	<link>https://haskellforall.com/2026/02/beyond-agentic-coding</link>
	<description>AI dev tooling can do better than chat interfaces</description>
	<pubDate>Sat, 07 Feb 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Tweag I/O: Integrating Coverity static analysis with Bazel</title>
	<guid isPermaLink="true">https://tweag.io/blog/2026-02-05-bazel-coverity-integration/</guid>
	<link>https://tweag.io/blog/2026-02-05-bazel-coverity-integration/</link>
	<description>&lt;p&gt;&lt;a href=&quot;https://www.blackduck.com/static-analysis-tools-sast/coverity.html&quot;&gt;Coverity&lt;/a&gt; is a proprietary static code analysis tool that can be
used to find code quality defects in large-scale, complex software. It
supports &lt;a href=&quot;https://www.blackduck.com/static-analysis-tools-sast/languages-and-frameworks.html&quot;&gt;a number of languages and
frameworks&lt;/a&gt; and has been trusted to
ensure compliance with various standards such as MISRA, AUTOSAR, ISO 26262,
and others. Coverity provides integrations with several build systems,
including Bazel, however the official Bazel integration fell short of the
expectations of our client, who wanted to leverage the Bazel remote cache in
order to speed up Coverity analysis and be able to run it in normal merge
request workflows. We took on that challenge.&lt;/p&gt;
&lt;h2 id=&quot;the-coverity-workflow&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#the-coverity-workflow&quot;&gt;&lt;/a&gt;The Coverity workflow&lt;/h2&gt;
&lt;p&gt;To understand the rest of the post it is useful to first become familiar
with the Coverity workflow, which is largely linear and can be summarized as
a sequence of steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Configuration. In this step &lt;code class=&quot;language-text&quot;&gt;cov-configure&lt;/code&gt; is invoked, possibly several
times with various combinations of key compiler flags (such as
&lt;code class=&quot;language-text&quot;&gt;-nostdinc++&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;-fPIC&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;-std=c++14&lt;/code&gt;, and others). This produces a
top-level XML configuration file accompanied by a directory tree that
contains configurations that correspond to the key flags that were
provided. Coverity is then able to pick the right configuration by
dispatching on those key flags when it sees them during the build.&lt;/li&gt;
&lt;li&gt;Compilation. This is typically done by invoking &lt;code class=&quot;language-text&quot;&gt;cov-build&lt;/code&gt; or its
lower-level cousin &lt;code class=&quot;language-text&quot;&gt;cov-translate&lt;/code&gt;. The distinction between these two
utilities will become clear in the next section. For now, it is enough to
point out that these tools translate original invocations of the compiler
to invocations of &lt;code class=&quot;language-text&quot;&gt;cov-emit&lt;/code&gt; (Coverity’s own compiler) which in turn
populate an SQLite database with intermediate representations and all the
metadata about the built sources such as symbols and include paths.&lt;/li&gt;
&lt;li&gt;Analysis. This step amounts to one or more invocations of &lt;code class=&quot;language-text&quot;&gt;cov-analyze&lt;/code&gt;.
This utility is practically a black box, and it can take a considerable
time to run, depending on the number of translation units (think
compilation units in C/C++). The input for the analysis is the SQLite
database that was produced in the previous step. &lt;code class=&quot;language-text&quot;&gt;cov-analyze&lt;/code&gt; populates
a directory tree that can then be used for report generation or uploading
of identified software defects.&lt;/li&gt;
&lt;li&gt;Reporting. Listing and registration of found defects is performed with
&lt;code class=&quot;language-text&quot;&gt;cov-format-errors&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;cov-commit-defects&lt;/code&gt;, respectively. These tools
require a directory structure that was created by &lt;code class=&quot;language-text&quot;&gt;cov-analyze&lt;/code&gt; in the
previous step.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;existing-integrations&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#existing-integrations&quot;&gt;&lt;/a&gt;Existing integrations&lt;/h2&gt;
&lt;p&gt;A successful integration of Coverity into Bazel has to provide a way to
perform step 2 of the workflow, since this is the only step that is
intertwined with the build system. Step 1 is relatively quick, and it does
not make a lot of difference how it is done. Step 3 is opaque and
build-system-agnostic because it happens after the build, furthermore there
is no obvious way to improve its granularity and cacheability. Step 4 is
similar in that regard.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://documentation.blackduck.com/bundle/coverity-docs/page/coverity-analysis/topics/building_with_bazel.html&quot;&gt;The official integration&lt;/a&gt; works by wrapping a
Bazel invocation with &lt;code class=&quot;language-text&quot;&gt;cov-build&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;$ cov-build --dir /path/to/idir --bazel bazel build //:my-bazel-target&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here, &lt;code class=&quot;language-text&quot;&gt;--dir&lt;/code&gt; specifies the intermediate directory where the SQLite database
along with some metadata will be stored. In the &lt;code class=&quot;language-text&quot;&gt;--bazel&lt;/code&gt; mode of operation
&lt;code class=&quot;language-text&quot;&gt;cov-build&lt;/code&gt; tricks Bazel by intercepting the invocations of the compiler
which are replaced by invocations of &lt;code class=&quot;language-text&quot;&gt;cov-translate&lt;/code&gt;. Compared to
&lt;code class=&quot;language-text&quot;&gt;cov-build&lt;/code&gt;, which is a high-level wrapper, &lt;code class=&quot;language-text&quot;&gt;cov-translate&lt;/code&gt; corresponds more
closely to individual invocations of a compiler. It identifies the right
configuration from the collection of configurations created in step 1
and then uses it to convert the command line arguments of the original
compiler into the command line arguments of &lt;code class=&quot;language-text&quot;&gt;cov-emit&lt;/code&gt;, which it then
invokes.&lt;/p&gt;
&lt;p&gt;The main problem with the official integration is the fact that it does not
support caching. &lt;code class=&quot;language-text&quot;&gt;bazel build&lt;/code&gt; has to run from scratch with caching disabled
in order to make sure that all invocations of the compiler are performed and
none are skipped. Another nuance of the official integration is that one has
to build a target of the supported kind, e.g. &lt;code class=&quot;language-text&quot;&gt;cc_library&lt;/code&gt;. If you bundle
your build products together in some way (e.g. in an archive), you cannot
simply build the top-level bundle as you normally would. Instead, you need
to identify every compatible target of interest in some other way.&lt;/p&gt;
&lt;p&gt;Because of this, our client did not use the official Coverity integration
for Bazel. Instead, they would run Bazel with the &lt;code class=&quot;language-text&quot;&gt;--subcommands&lt;/code&gt; option
which makes Bazel print how it invokes all tools that participate in the
build. This long log would then be parsed and converted into a &lt;code class=&quot;language-text&quot;&gt;Makefile&lt;/code&gt; in
order to be able to leverage Coverity’s Make integration in &lt;code class=&quot;language-text&quot;&gt;cov-build&lt;/code&gt;
instead. This approach still suffered from long execution times due to lack
of caching. It ran as a nightly build and took over 12 hours, which wasn’t
suitable for a regular merge request’s CI pipeline.&lt;/p&gt;
&lt;h2 id=&quot;our-approach&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#our-approach&quot;&gt;&lt;/a&gt;Our approach&lt;/h2&gt;
&lt;p&gt;The key insight that allowed us to make the build process cacheable is the
observation that individual invocations of &lt;code class=&quot;language-text&quot;&gt;cov-translate&lt;/code&gt; produce SQLite
databases—&lt;code class=&quot;language-text&quot;&gt;emit-db&lt;/code&gt;s—that are granular and relatively small. These
individual &lt;code class=&quot;language-text&quot;&gt;emit-db&lt;/code&gt;s can then be merged in order to form the final, big
&lt;code class=&quot;language-text&quot;&gt;emit-db&lt;/code&gt; that can be used for running &lt;code class=&quot;language-text&quot;&gt;cov-analyze&lt;/code&gt;. Therefore, our plan
was the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a special-purpose Bazel toolchain that starts as a copy of the
toolchain which is used for “normal” compilation in order to match the
way the original compiler (&lt;code class=&quot;language-text&quot;&gt;gcc&lt;/code&gt; in our case) is invoked.&lt;/li&gt;
&lt;li&gt;Instead of &lt;code class=&quot;language-text&quot;&gt;gcc&lt;/code&gt; and some other tools such as &lt;code class=&quot;language-text&quot;&gt;ar&lt;/code&gt;, have it invoke our
own wrapper that would drive invocations of &lt;code class=&quot;language-text&quot;&gt;cov-translate&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The only useful output of the compilation step is the &lt;code class=&quot;language-text&quot;&gt;emit-db&lt;/code&gt; database.
On the other hand, in &lt;code class=&quot;language-text&quot;&gt;CppCompile&lt;/code&gt; actions, Bazel normally expects &lt;code class=&quot;language-text&quot;&gt;.o&lt;/code&gt;
files to be produced, so we just rename our &lt;code class=&quot;language-text&quot;&gt;emit-db&lt;/code&gt; SQLite database to
whatever object file Bazel is expecting.&lt;/li&gt;
&lt;li&gt;In the linking step, we use the &lt;code class=&quot;language-text&quot;&gt;add&lt;/code&gt; subcommand of &lt;code class=&quot;language-text&quot;&gt;cov-manage-emit&lt;/code&gt; in
order to merge individual &lt;code class=&quot;language-text&quot;&gt;emit-db&lt;/code&gt;s.&lt;/li&gt;
&lt;li&gt;Once the final bundle is built, we iterate through all eligible database
files and merge them together once again in order to obtain the final
&lt;code class=&quot;language-text&quot;&gt;emit-db&lt;/code&gt; that will be used for analysis.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;From Bazel’s point of view, we are simply compiling C/C++ code, however, this
is a way to perform a cacheable Coverity build. If you are a regular reader of
our blog, you may have noticed certain similarities to the approach we used
in our CTC++ Bazel integration documented &lt;a href=&quot;https://www.tweag.io/blog/2023-11-09-ctc++-bazel-integration&quot;&gt;here&lt;/a&gt; and
&lt;a href=&quot;https://www.tweag.io/blog/2025-03-06-ctc++-revisited&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;difficulties&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#difficulties&quot;&gt;&lt;/a&gt;Difficulties&lt;/h2&gt;
&lt;p&gt;The plan may sound simple, but in practice there was nothing simple about
it. The key difficulty was the fact that Coverity tooling was not designed
with reproducibility in mind. At every step, starting from configuration
generation (which is simply a &lt;code class=&quot;language-text&quot;&gt;genrule&lt;/code&gt; in our case) we had to inspect and
adjust produced outputs in order to make sure that they do not include any
volatile data that could compromise reproducibility. The key output in the
Coverity workflow, the &lt;code class=&quot;language-text&quot;&gt;emit-db&lt;/code&gt; database, contained a number of pieces of
volatile information:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Start time, end time, and process IDs of &lt;code class=&quot;language-text&quot;&gt;cov-emit&lt;/code&gt; invocations.&lt;/li&gt;
&lt;li&gt;Timestamps of source files.&lt;/li&gt;
&lt;li&gt;Command line IDs of translation units.&lt;/li&gt;
&lt;li&gt;Host name; luckily, this can be overwritten easily by setting the &lt;code class=&quot;language-text&quot;&gt;COV_HOST&lt;/code&gt;
environment variable.&lt;/li&gt;
&lt;li&gt;Absolute file names of source files. These are split into path segments with
each segment stored as a separate database entry, meaning the number of entries
in the &lt;code class=&quot;language-text&quot;&gt;FileName&lt;/code&gt; table varies with the depth of the path to the execroot,
breaking hermeticity. Deleting entries is not viable since their IDs are
referenced elsewhere. Our solution was to identify the variable prefix leading
to the execroot and reset all segments in that prefix to a fixed string. The
prefix length proved to be constant for each execution mode, allowing us to use
&lt;code class=&quot;language-text&quot;&gt;--strip-path&lt;/code&gt; arguments in &lt;code class=&quot;language-text&quot;&gt;cov-analyze&lt;/code&gt; to remove them during analysis.&lt;/li&gt;
&lt;li&gt;In certain cases some files from the &lt;code class=&quot;language-text&quot;&gt;include&lt;/code&gt; directories would be added
to the database with altered Coverity-generated contents
that would also include absolute paths.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We had to meticulously overwrite all of these, which was only possible
because &lt;code class=&quot;language-text&quot;&gt;emit-db&lt;/code&gt; is in the SQLite format and there is open source tooling
that makes it possible to edit it. If the output of &lt;code class=&quot;language-text&quot;&gt;cov-emit&lt;/code&gt; were in a
proprietary format we almost certainly wouldn’t be able to deliver as
efficient a solution for our client.&lt;/p&gt;
&lt;p&gt;In practice, normalization of &lt;code class=&quot;language-text&quot;&gt;emit-db&lt;/code&gt; happens in two stages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We run some SQL commands that reset the volatile pieces of data inside the
database. As we were iterating on these “corrective instructions”, we made
sure that we eliminated all instances of volatility by using the
&lt;code class=&quot;language-text&quot;&gt;sqldiff&lt;/code&gt; utility which can print differences in schema and data between
tables.&lt;/li&gt;
&lt;li&gt;We dump the resulting database with the &lt;code class=&quot;language-text&quot;&gt;.dump&lt;/code&gt; command which exports the
SQL statements necessary to recreate the database with the same schema and
data. Then we re-load these statements and thus obtain a binary database file
that is bit-by-bit reproducible. This is necessary because simply editing
a database by running SQL commands on it does not ensure that the result
is binary reproducible even if there is no difference in the actual
contents.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;performance-considerations&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#performance-considerations&quot;&gt;&lt;/a&gt;Performance considerations&lt;/h2&gt;
&lt;p&gt;Since &lt;code class=&quot;language-text&quot;&gt;emit-db&lt;/code&gt;s are considerably larger than typical object files, we found
it highly desirable to use compression for individual SQLite databases, both
for those that result from initial &lt;code class=&quot;language-text&quot;&gt;cov-translate&lt;/code&gt; invocations and for
merged databases that are created by &lt;code class=&quot;language-text&quot;&gt;cov-manage-emit&lt;/code&gt; in the linking step.
&lt;a href=&quot;https://github.com/facebook/zstd&quot;&gt;Zstandard&lt;/a&gt; proved to be a good choice for that—the utility is both
fast and makes our build outputs up to 4 times smaller. Without compression,
we risked filling the remote cache quickly; besides, the bigger the files,
the slower I/O operations are.&lt;/p&gt;
&lt;p&gt;We were tempted to minimize the size of the database even further by
exploring if there’s anything in &lt;code class=&quot;language-text&quot;&gt;emit-db&lt;/code&gt; that can be safely removed
without affecting our client’s use case. Alas, every piece of information
stored was required by Coverity during the analysis phase and our attempts
to truncate some of the tables led to failures in &lt;code class=&quot;language-text&quot;&gt;cov-analyze&lt;/code&gt;. It is worth
noting that the &lt;code class=&quot;language-text&quot;&gt;sqlite3_analyzer&lt;/code&gt; utility tool (part of the SQLite project)
can be used to produce a report that explains which objects store most data.
This way we found that there is an index that contributes about 20% of the
database size, however, deleting it severely degrades the performance of
record inserts which is a key operation during merging of &lt;code class=&quot;language-text&quot;&gt;emit-db&lt;/code&gt;s.&lt;/p&gt;
&lt;p&gt;Linking steps, which in our approach amount to merging of &lt;code class=&quot;language-text&quot;&gt;emit-db&lt;/code&gt;
databases, produce particularly large files. In order
to reduce the amount of I/O we perform and avoid
filling the remote cache too quickly,
we’ve marked all operations that deal with these large files
as &lt;code class=&quot;language-text&quot;&gt;no-remote&lt;/code&gt;. This is accomplished with this line in
our &lt;code class=&quot;language-text&quot;&gt;.bazelrc&lt;/code&gt; file:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;common:coverity --modify_execution_info=CppArchive=+no-remote,CppLink=+no-remote,CcStrip=+no-remote
# If you wish to disable RE for compilation actions with coverity, uncomment
# the following line:
# common:coverity --modify_execution_info=CppCompile=+no-remote-exec&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;On the other hand, we did end up running &lt;code class=&quot;language-text&quot;&gt;CppCompile&lt;/code&gt; actions with remote execution (RE)
because it proved to be twice faster than running them on CI agents. Making
RE possible required us to identify the exact collection of files from the
Coverity installation that are required during invocations of the Coverity
tooling. Once we observed RE working correctly, we were confident that the
Bazel definitions we use are hermetic.&lt;/p&gt;
&lt;p&gt;Merging of individual &lt;code class=&quot;language-text&quot;&gt;emit-db&lt;/code&gt; databases found in the final bundle (i.e.
after the build has finished) proved to be time-consuming. This operation
cannot be parallelized since database information cannot be written in
parallel. The time required for this step grows linearly with the number of
translation units (TUs) being inserted, therefore it makes sense to pick the
largest database and then merge smaller ones into it. One could entertain
the possibility of skipping merging altogether and instead running smaller
analyses on individual &lt;code class=&quot;language-text&quot;&gt;emit-db&lt;/code&gt;s, but this seems to be not advisable, since
Coverity performs a whole-program analysis, and thus it would lose valuable
information that way. For example, one TU may be exercised in different ways
by two different applications and the analysis results for this TU cannot be
correctly merged.&lt;/p&gt;
&lt;p&gt;The analysis phase is a black box, and it can easily become the bottleneck
of the entire workflow, thus making it impractical for running in merge
request pipelines. A common solution for speeding up the analysis in merge
request pipelines is to identify files that were edited and limit the
analysis to only these files with the &lt;code class=&quot;language-text&quot;&gt;--tu-pattern&lt;/code&gt; option, which supports
&lt;a href=&quot;https://documentation.blackduck.com/bundle/coverity-docs/page/commands/topics/cov-manage-emit.html#cme_patterns&quot;&gt;a simple language&lt;/a&gt; for telling Coverity what to care
about during analysis. We added support for this approach to our solution by
automatically finding the files changed in the current merge request, and
passing these on to &lt;code class=&quot;language-text&quot;&gt;--tu-pattern&lt;/code&gt;. This restricted analysis still requires the
&lt;code class=&quot;language-text&quot;&gt;emit-db&lt;/code&gt;s for the entire project, but most of them will be cached.&lt;/p&gt;
&lt;h2 id=&quot;the-results&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#the-results&quot;&gt;&lt;/a&gt;The results&lt;/h2&gt;
&lt;p&gt;The solution that we delivered is in the form of a &lt;code class=&quot;language-text&quot;&gt;bazel run&lt;/code&gt;-able target
that depends on the binary bundle that needs to be analyzed. It can be
invoked like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;bazel run //bazel/toolchains/coverity:workflow --config=coverity -- ...&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This solution can be used both for the nightly runs of Coverity and in the
merge request pipelines. We have confirmed that the results that are
produced by our solution match the findings of Coverity when it is run in
the “traditional” way. A typical run in a merge request pipeline takes about
22 minutes when a couple of C++ files are edited. The time is distributed as
follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;8 minutes: building, similar to build times for normal builds (this
step is sped up by caching)&lt;/li&gt;
&lt;li&gt;10 minutes: the final merging of &lt;code class=&quot;language-text&quot;&gt;emit-db&lt;/code&gt;s&lt;/li&gt;
&lt;li&gt;4 minutes: analysis, uploading defects, reporting (this step is sped up by &lt;code class=&quot;language-text&quot;&gt;--tu-pattern&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The execution time can grow, of course, if the edits are more substantial.
The key benefit of our approach is that the Coverity build is now cacheable
and therefore can be included in merge request CI pipelines.&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;In summary, integrating Coverity static analysis with Bazel in a cacheable,
reproducible, and efficient manner required a deep understanding of both
Bazel and Coverity, as well as a willingness to address the nuances of
proprietary tooling that got in the way. By leveraging granular &lt;code class=&quot;language-text&quot;&gt;emit-db&lt;/code&gt;
databases, normalizing volatile data, and optimizing for remote execution
and compression, we were able to deliver a solution that fits well into the
client’s CI workflow and supports incremental analysis in merge request
pipelines.&lt;/p&gt;
&lt;p&gt;While the process involved overcoming significant challenges, particularly
around reproducibility and performance, the resulting workflow enables fast
static analysis without sacrificing the benefits of Bazel’s remote cache. We
hope that sharing our approach will help other teams facing similar
challenges and inspire improvements when integrating other static analysis
tools with Bazel.&lt;/p&gt;</description>
	<pubDate>Thu, 05 Feb 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>in Code: &quot;Five-Point Haskell&quot;: Total Depravity (and Defensive Typing)</title>
	<guid isPermaLink="true">https://blog.jle.im/entry/five-point-haskell-part-1-total-depravity.html</guid>
	<link>https://blog.jle.im/entry/five-point-haskell-part-1-total-depravity.html</link>
	<description>&lt;p&gt;I have thought about distilling the principles by which I program Haskell,
and how I’ve been able to steer long-lived projects over years of growth,
refactorings, and changes in demands. I find myself coming back to a few
distinct and helpful “points” (“doctrines”, if you may allow me to say) that
have yet to lead me astray.&lt;/p&gt;
&lt;p&gt;With a new age of software development coming, what does it even mean to
write good, robust, correct code? It is long overdue to clarify the mindset we
use to define “good” coding principles.&lt;/p&gt;
&lt;p&gt;In this series, &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;, I’ll set out to establish a five-point framework for typed
functional programming (and Haskell-derived) design that aims to produce code
that is maintainable, correct, long-lasting, extensible, and beautiful to write
and work with. We’ll reference real-world case studies with actual examples when
we can, and also attempt to dispel thought-leader sound bites that have become
all too popular on Twitter (“heresies”, so to speak).&lt;/p&gt;
&lt;p&gt;Let’s jump right into point 1: the doctrine of &lt;strong&gt;Total
Depravity&lt;/strong&gt;, and why Haskell is perfectly primed to make living with it
as frictionless as possible.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Total Depravity: If your code’s correctness depends on keeping complicated
interconnected structure in your head, a devastating incident is not a matter of
&lt;em&gt;if&lt;/em&gt; but &lt;em&gt;when&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Therefore, delegate these concerns to tooling and a sufficiently powerful
compiler, use types to guard against errors, and free yourself to only mentally
track the actual important things.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;mix-ups-are-inevitable&quot;&gt;Mix-ups Are Inevitable&lt;/h2&gt;
&lt;p&gt;Think about the stereotype of a “brilliant programmer” that an inexperienced
programmer has in their mind — someone who can hold every detail of a complex
system in their head, every intricate connection and relationship between each
component. There’s the classic &lt;a href=&quot;https://www.monkeyuser.com/2018/focus/&quot;&gt;Monkey User Comic&lt;/a&gt; that
valorizes this ideal.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Monkey User — Focus&quot; src=&quot;http://feeds.feedburner.com/img/entries/five-point-haskell/79-focus.png&quot; style=&quot;width: 50%; height: auto;&quot; title=&quot;Monkey User --- Focus&quot; /&gt;
&lt;figcaption&gt;Monkey User — Focus&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The 10x developer is one who can carry the state and interconnectedness of an
entire system in their brain, and the bigger the state they can carry, the more
10x they are.&lt;/p&gt;
&lt;p&gt;This is the myth of the hero programmer. Did you have a bug? Well, you just
need to upgrade your mental awareness and your context window. You just need to
be better and better at keeping more in your mind.&lt;/p&gt;
&lt;p&gt;Actually &lt;em&gt;addressing&lt;/em&gt; these issues in most languages requires a lot of
overhead and clunkiness. But luckily we’re in Haskell.&lt;/p&gt;
&lt;h3 id=&quot;explicit-tags&quot;&gt;Explicit Tags&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.atlassian.com/blog/atlassian-engineering/post-incident-review-april-2022-outage&quot;&gt;2022
Atlassian Outage&lt;/a&gt;, in part, was the result of passing the wrong type of ID.
The operators were intended to pass &lt;em&gt;App&lt;/em&gt; IDs, but instead passed
&lt;em&gt;Site&lt;/em&gt; IDs, and the errors cascaded from there. It goes without saying
that if you have a bunch of “naked” IDs, then mixing them up is eventually going
to backfire on you.&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;newtype&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Id&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Id&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&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;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;SiteId&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Id&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;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;AppId&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Id&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&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;ot&quot;&gt;getApps ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;SiteId&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;AppId&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb1-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb1-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;deleteSite ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;SiteId&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-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb1-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;deleteApp ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;AppId&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;This is convenient because you get functions for all IDs without any extra
work. Let’s say you want to serialize/print or deserialize/read these IDs — it
can be helpful to give them all the same type so that you can write this logic
in one place.&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;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ToJSON&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Id&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;http://feeds.feedburner.com/incodeblog#cb2-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  toJSON (&lt;span class=&quot;dt&quot;&gt;Id&lt;/span&gt; x) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; object [ &lt;span class=&quot;st&quot;&gt;&quot;id&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.=&lt;/span&gt; x ]&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&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;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FromJSON&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Id&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&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;  parseJSON &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; withObject &lt;span class=&quot;st&quot;&gt;&quot;Id&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; \v &lt;span class=&quot;ot&quot;&gt;-&amp;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;dt&quot;&gt;Id&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; (v &lt;span class=&quot;op&quot;&gt;.:&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;id&quot;&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Convenient and effective, as long as you never accidentally use a
&lt;code&gt;SiteId&lt;/code&gt; as an &lt;code&gt;AppId&lt;/code&gt; or vice versa. And this is a very
easy delusion to fall into, if you don’t believe in total depravity. However,
sooner or later (maybe in a week, maybe in a year, maybe after you onboard that
new team member)…someone is going to accidentally pass a site ID where an app ID
is expected.&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;main ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&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;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;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;kw&quot;&gt;let&lt;/span&gt; targetSites &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;Id&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;abc&quot;&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Id&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;def&quot;&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;fu&quot;&gt;mapM_&lt;/span&gt; deleteApp targetSites&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And at that point it’s all over.&lt;/p&gt;
&lt;p&gt;Knowing this can happen, we can add a simple newtype wrapper so that
accidentally using the wrong ID is a compile error:&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;kw&quot;&gt;newtype&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;SiteId&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;SiteId&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&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 class=&quot;kw&quot;&gt;newtype&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;AppId&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;AppId&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;And now such a mis-call will never compile! Congratulations!&lt;/p&gt;
&lt;p&gt;We do have a downside now: we can no longer write code polymorphic over IDs
when we want to. In the untagged situation, we could &lt;em&gt;only&lt;/em&gt; write
polymorphic code, and in the new situation we can &lt;em&gt;only&lt;/em&gt; write code for
one ID type.&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;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FromJSON&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;SiteId&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&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;  parseJSON &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; withObject &lt;span class=&quot;st&quot;&gt;&quot;Id&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; \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;cb5-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    tag &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; v &lt;span class=&quot;op&quot;&gt;.:&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;type&quot;&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;    unless (tag &lt;span class=&quot;op&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;Site&quot;&lt;/span&gt;) &lt;span class=&quot;op&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;fu&quot;&gt;fail&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;Parsed wrong type of ID!&quot;&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;SiteId&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; (v &lt;span class=&quot;op&quot;&gt;.:&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;id&quot;&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&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;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ToJSON&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;SiteId&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&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;  toJSON (&lt;span class=&quot;dt&quot;&gt;SiteId&lt;/span&gt; x) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; object [ &lt;span class=&quot;st&quot;&gt;&quot;type&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;Site&quot;&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&quot;id&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.=&lt;/span&gt; x ]&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&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;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FromJSON&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;AppId&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&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;  parseJSON &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; withObject &lt;span class=&quot;st&quot;&gt;&quot;Id&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; \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;cb5-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    tag &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; v &lt;span class=&quot;op&quot;&gt;.:&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;type&quot;&lt;/span&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;    unless (tag &lt;span class=&quot;op&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;App&quot;&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;$&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 class=&quot;fu&quot;&gt;fail&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;Parsed wrong type of ID!&quot;&lt;/span&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;AppId&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; (v &lt;span class=&quot;op&quot;&gt;.:&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;id&quot;&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;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ToJSON&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;AppId&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&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;  toJSON (&lt;span class=&quot;dt&quot;&gt;AppId&lt;/span&gt; x) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; object [ &lt;span class=&quot;st&quot;&gt;&quot;type&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;App&quot;&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&quot;id&quot;&lt;/span&gt; &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;However, luckily, because we’re in Haskell, it’s easy to get the best of both
worlds with &lt;em&gt;phantom types&lt;/em&gt; (that don’t refer to anything inside the
actual data representation):&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;Id&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Id&lt;/span&gt; {&lt;span class=&quot;ot&quot;&gt; getId ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&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;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Site&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;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;App&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&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;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;SiteId&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Id&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Site&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;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;AppId&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Id&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;App&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&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 class=&quot;co&quot;&gt;-- using Typeable for demonstration purposes&lt;/span&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;kw&quot;&gt;instance&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;ToJSON&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Id&lt;/span&gt; a) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&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;  toJSON (&lt;span class=&quot;dt&quot;&gt;Id&lt;/span&gt; x) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; object&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;st&quot;&gt;&quot;type&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;show&lt;/span&gt; (typeRep &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;a)&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;st&quot;&gt;&quot;id&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.=&lt;/span&gt; x&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&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&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 class=&quot;kw&quot;&gt;instance&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;FromJSON&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Id&lt;/span&gt; a) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&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;  parseJSON &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; withObject &lt;span class=&quot;st&quot;&gt;&quot;Id&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; \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;cb6-18&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    tag &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; v &lt;span class=&quot;op&quot;&gt;.:&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;type&quot;&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;    unless (tag &lt;span class=&quot;op&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;show&lt;/span&gt; (typeRep &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;a)) &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt;&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;fu&quot;&gt;fail&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;Parsed wrong type of ID!&quot;&lt;/span&gt;&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;Id&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; (v &lt;span class=&quot;op&quot;&gt;.:&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;id&quot;&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Type safety doesn’t necessarily mean inflexibility!&lt;/p&gt;
&lt;h3 id=&quot;phantom-powers&quot;&gt;Phantom Powers&lt;/h3&gt;
&lt;p&gt;Phantom types give us a &lt;em&gt;lot&lt;/em&gt; of low-hanging fruit for preventing
inadvertent misuse.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.theregister.com/2017/04/11/database_deletion_downed_digital_ocean_last_week/&quot;&gt;2017
DigitalOcean outage&lt;/a&gt;, for example, was partially about the wrong environment
credentials being used.&lt;/p&gt;
&lt;p&gt;We could imagine a test harness that clears a test database using &lt;em&gt;&lt;a href=&quot;https://hackage.haskell.org/package/postgresql-simple&quot;&gt;postgresql-simple&lt;/a&gt;&lt;/em&gt;:&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;co&quot;&gt;-- | Warning: do NOT call this outside of test environment!&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;clearTestEnv ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Connection&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;cb7-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb7-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;clearTestEnv conn &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;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;fu&quot;&gt;putStrLn&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;Are you sure you read the warning on this function? Well, too late now!&quot;&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 class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; execute_ conn &lt;span class=&quot;st&quot;&gt;&quot;DROP TABLE IF EXISTS users CASCADE&quot;&lt;/span&gt;&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;  &lt;span class=&quot;fu&quot;&gt;putStrLn&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;Test data wiped.&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;However, somewhere down the line, someone is going to call
&lt;code&gt;clearTestEnv&lt;/code&gt; &lt;em&gt;deep&lt;/em&gt; inside a function inside a function
inside a function, which itself is called against the prod database. I guarantee
it.&lt;/p&gt;
&lt;p&gt;To ensure this never happens, we can use closed phantom types using
&lt;code&gt;DataKinds&lt;/code&gt; (made nicer with &lt;code&gt;TypeData&lt;/code&gt; post-GHC 9.6):&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;-- type data = declare a closed kind and two type constructors at the type level using -XTypeData&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 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;Env&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Prod&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Test&lt;/span&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&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;kw&quot;&gt;newtype&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DbConnection&lt;/span&gt; (&lt;span class=&quot;ot&quot;&gt;a ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Env&lt;/span&gt;) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DbConnection&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Connection&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&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;ot&quot;&gt;runQuery ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DbConnection&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Query&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;Int64&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;runQuery (&lt;span class=&quot;dt&quot;&gt;DbConnection&lt;/span&gt; c) q &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; execute_ c q&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&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;co&quot;&gt;-- | Warning: Did you remember to charge your chromebook? Oh and this function&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 class=&quot;co&quot;&gt;-- is safe by the way.&lt;/span&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;clearTestEnv ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DbConnection&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Test&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;cb8-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;clearTestEnv conn &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;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;ot&quot;&gt;&amp;lt;-&lt;/span&gt; runQuery conn &lt;span class=&quot;st&quot;&gt;&quot;DROP TABLE IF EXISTS users CASCADE&quot;&lt;/span&gt;&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;fu&quot;&gt;putStrLn&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;Test data wiped.&quot;&lt;/span&gt;&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&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;ot&quot;&gt;connectProd ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;DbConnection&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Prod&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;connectProd &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;DbConnection&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; connectPostgreSQL &lt;span class=&quot;st&quot;&gt;&quot;host=prod...&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now, if you create a connection using &lt;code&gt;connectProd&lt;/code&gt;, you can use
&lt;code&gt;runQuery&lt;/code&gt; on it (because it can run any
&lt;code&gt;DbConnection a&lt;/code&gt;)…but if any sub-function of a sub-function calls
&lt;code&gt;clearTestEnv&lt;/code&gt;, it will have to unify with
&lt;code&gt;DbConnection Test&lt;/code&gt;, which is impossible for a prod connection.&lt;/p&gt;
&lt;p&gt;This is somewhat similar to using “mocking-only” subclasses for dependency
injection, but with a closed universe. I discuss patterns like this in my &lt;a href=&quot;https://blog.jle.im/entries/series/+introduction-to-singletons.html&quot;&gt;Introduction
to Singletons&lt;/a&gt; series.&lt;/p&gt;
&lt;h2 id=&quot;correct-representations&quot;&gt;Correct Representations&lt;/h2&gt;
&lt;h3 id=&quot;semantic-phantoms&quot;&gt;Semantic Phantoms&lt;/h3&gt;
&lt;p&gt;And sometimes, phantom types can do the work for you, not only preventing
mix-ups but also encoding business logic in their manipulation.&lt;/p&gt;
&lt;p&gt;Take, for instance, the &lt;a href=&quot;https://en.wikipedia.org/wiki/Mars_Climate_Orbiter&quot;&gt;Mars Climate Orbiter
failure&lt;/a&gt;, where the software module provided by Lockheed Martin expected US
Customary Units, and another one developed by NASA expected SI units.&lt;/p&gt;
&lt;p&gt;If I had a function like:&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;co&quot;&gt;-- | In Newton-seconds&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;ot&quot;&gt;myMomentum ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Double&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;myMomentum &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;20&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;&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;co&quot;&gt;-- | In Pounds-second&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;ot&quot;&gt;myImpulse ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Double&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;myImpulse &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;&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;co&quot;&gt;-- | Make sure these are both the same units!&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;&lt;span class=&quot;ot&quot;&gt;applyImpulse ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Double&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Double&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Double&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;applyImpulse currentMomentum impulse &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; currentMomentum &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; impulse&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is just &lt;em&gt;asking&lt;/em&gt; for someone to come along and provide newtons
alongside pounds. It isn’t even clear from the types what is expected!&lt;/p&gt;
&lt;p&gt;We can instead use the &lt;em&gt;&lt;a href=&quot;https://hackage.haskell.org/package/dimensional&quot;&gt;dimensional&lt;/a&gt;&lt;/em&gt;
library:&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;import&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;qualified&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Numeric.Units.Dimensional.Prelude&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;U&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;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Numeric.Units.Dimensional&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;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Numeric.Units.Dimensional.SIUnits&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;&lt;span class=&quot;kw&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Numeric.Units.Dimensional.NonSI&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&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;ot&quot;&gt;myMomentum ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Momentum&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;myMomentum &lt;span class=&quot;ot&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; (newton &lt;span class=&quot;op&quot;&gt;U.*&lt;/span&gt; seconds)&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&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 class=&quot;ot&quot;&gt;myImpulse ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Impulse&lt;/span&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;myImpulse &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; (poundForce &lt;span class=&quot;op&quot;&gt;U.*&lt;/span&gt; seconds)&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;&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;co&quot;&gt;-- Verify at compile-time that we can use '+' with Momentum and Impulse&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb10-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;applyImpulse ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Momentum&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Impulse&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Momentum&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb10-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;applyImpulse currentMomentum impulse &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; currentMomentum &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; impulse&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now as long as momentum and impulse are provided in the correct types at API
boundaries, no mix-up will happen. No need to send 300 million dollars down the
drain! Libraries will just need to provide a unified &lt;code&gt;Momentum&lt;/code&gt; or
&lt;code&gt;Impulse&lt;/code&gt; type, and everything will work out.&lt;/p&gt;
&lt;h3 id=&quot;the-billion-dollar-mistake&quot;&gt;The Billion-Dollar Mistake&lt;/h3&gt;
&lt;p&gt;Speaking of costly errors, there is one extremely egregious pattern that is
so pervasive, so alluring, and yet so inevitably devastating, it has been dubbed
the “Billion Dollar Mistake”. It’s the idea of a &lt;em&gt;sentinel value&lt;/em&gt;, or
in-band signaling.&lt;/p&gt;
&lt;p&gt;There are examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;String.indexOf()&lt;/code&gt;, &lt;code&gt;str.find()&lt;/code&gt;, etc. in many
languages return -1 if the substring is not found&lt;/li&gt;
&lt;li&gt;C’s &lt;code&gt;fgetc()&lt;/code&gt;, &lt;code&gt;getchar()&lt;/code&gt;, return -1 for
&lt;code&gt;EOF&lt;/code&gt;. And if you cast to &lt;code&gt;char&lt;/code&gt;, you basically can’t
distinguish EOF from &lt;code&gt;0xff&lt;/code&gt; (&lt;code&gt;ÿ&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;malloc()&lt;/code&gt; returning the pointer 0 means not enough memory&lt;/li&gt;
&lt;li&gt;Some languages have a special &lt;code&gt;NULL&lt;/code&gt; pointer value as well — or
even a value &lt;code&gt;null&lt;/code&gt; that can be passed in for any expected type or
object or value.&lt;/li&gt;
&lt;li&gt;JavaScript’s &lt;code&gt;parseInt&lt;/code&gt; returns not &lt;code&gt;null&lt;/code&gt;, but rather
&lt;code&gt;NaN&lt;/code&gt; for a bad parse — giving two distinct sentinel values&lt;/li&gt;
&lt;li&gt;A lot of Unix scripting uses the empty string &lt;code&gt;&quot;&quot;&lt;/code&gt; for
non-presence&lt;/li&gt;
&lt;li&gt;Sensor firmware often reports values like &lt;code&gt;-999&lt;/code&gt; for a bad
reading…but sometimes &lt;code&gt;-999&lt;/code&gt; might actually be a valid value!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It should be evident that these are just accidents and ticking time bombs
waiting to happen. Some caller just needs to forget to handle the sentinel
value, or to falsely assume that the sentinel value is impossible to occur in
any situation.&lt;/p&gt;
&lt;p&gt;It’s called the billion dollar mistake, but it’s definitely arguable that the
cumulative damage has been much higher. High-profile incidents include &lt;a href=&quot;https://www.rapid7.com/db/modules/exploit/linux/local/sock_sendpage/&quot;&gt;sock_sendpage&lt;/a&gt;
and the &lt;a href=&quot;https://www.thousandeyes.com/blog/google-cloud-outage-analysis-june-12-2025&quot;&gt;2025
GCP outage&lt;/a&gt;, but if you’re reading this and you are honest with yourself,
it’s probably happened to you multiple times and has been the source of many
frustrating bug hunts.&lt;/p&gt;
&lt;p&gt;There’s also &lt;a href=&quot;https://www.invicti.com/web-application-vulnerabilities/openssl-improper-input-validation-vulnerability-cve-2008-5077&quot;&gt;CVE-2008-5077&lt;/a&gt;,
because &lt;a href=&quot;https://docs.openssl.org/1.1.1/man3/EVP_VerifyInit/&quot;&gt;EVP_VerifyInit&lt;/a&gt;
returns &lt;code&gt;0&lt;/code&gt; for false, &lt;code&gt;1&lt;/code&gt; for true, and &lt;code&gt;-1&lt;/code&gt;
for error! So some OpenSSL code did a simple if-then-else check
(&lt;code&gt;result != 0&lt;/code&gt;) and treated error and true the same way. Whoops.&lt;/p&gt;
&lt;p&gt;Why do we do this to ourselves? Because it is convenient. In the case of
&lt;code&gt;EVP_VerifyInit&lt;/code&gt;, we can define an enum instead…&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;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;VerifyResult&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Success&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Failure&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Error&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;However, it’s not easy to make an “integer or not found” type in C or
JavaScript without some sort of side-channel. Imagine if JavaScript’s
&lt;code&gt;String.indexOf()&lt;/code&gt; instead expected continuations on success and
failure and became much less usable as a result:&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;unsafeIndexOf ::&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;String&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;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;co&quot;&gt;-- vs.&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&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;co&quot;&gt;-- takes a success continuation and a failure continuation&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;ot&quot;&gt;indexOf ::&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;String&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 class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; r) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&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;All of this just to &lt;a href=&quot;https://blog.jle.im/entry/faking-adts-and-gadts.html&quot;&gt;fake having actual
sum types&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We don’t really have an excuse in Haskell, since we can just return
&lt;code&gt;Maybe&lt;/code&gt;:&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;co&quot;&gt;-- from Data.Vector&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb13-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;elemIndex ::&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;Vector&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;Int&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Returning &lt;code&gt;Maybe&lt;/code&gt; or &lt;code&gt;Option&lt;/code&gt; forces the caller to
handle:&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;kw&quot;&gt;case&lt;/span&gt; elemIndex &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt; myVec &lt;span class=&quot;kw&quot;&gt;of&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;Just&lt;/span&gt; i &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;-- ..&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb14-3&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;co&quot;&gt;-- ..&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and this handling is compiler-enforced. Provided, of course, you don’t &lt;a href=&quot;https://blog.cloudflare.com/18-november-2025-outage/&quot;&gt;intentionally throw
away your type-safety and compiler checks for no reason&lt;/a&gt;. You can even return
&lt;code&gt;Either&lt;/code&gt; with an enum for richer responses, and very easily &lt;a href=&quot;https://blog.jle.im/entry/inside-my-world-ode-to-functor-and-monad.html&quot;&gt;chain
erroring operations using Functor and Monad&lt;/a&gt;. In fact, with cheap ADTs, you
can define your own rich result type, like in &lt;em&gt;&lt;a href=&quot;https://hackage-content.haskell.org/package/unix&quot;&gt;unix&lt;/a&gt;&lt;/em&gt;’s
&lt;code&gt;ProcessStatus&lt;/code&gt;:&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;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ProcessStatus&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;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Exited&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ExitCode&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;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Terminated&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Signal&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Bool&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;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Stopped&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Signal&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Imagine trying to cram all of that information into an &lt;code&gt;int&lt;/code&gt;!&lt;/p&gt;
&lt;h2 id=&quot;unmarked-assumptions&quot;&gt;Unmarked Assumptions&lt;/h2&gt;
&lt;p&gt;Assumptions kill, and a lot of times we arrive at implicit assumptions in our
code. Unfortunately, even if we add these assumptions in our documentation, it
only takes a minor refactor or lapse in memory for these to cause catastrophic
incidents.&lt;/p&gt;
&lt;p&gt;There are the simple cases — consider a &lt;code&gt;mean&lt;/code&gt; function:&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;-- | Warning: do not give an empty list!&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 class=&quot;ot&quot;&gt;mean ::&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;Double&lt;/span&gt;] &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Double&lt;/span&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;mean xs &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;sum&lt;/span&gt; xs &lt;span class=&quot;op&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fromIntegral&lt;/span&gt; (&lt;span class=&quot;fu&quot;&gt;length&lt;/span&gt; xs)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But are you &lt;em&gt;really&lt;/em&gt; going to remember to check if your list is empty
&lt;em&gt;every&lt;/em&gt; time you give it to &lt;code&gt;mean&lt;/code&gt;? No, of course not.
Instead, make it a compiler-enforced constraint.&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;ot&quot;&gt;mean ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;NonEmpty&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Double&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Double&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;mean xs &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;sum&lt;/span&gt; xs &lt;span class=&quot;op&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fromIntegral&lt;/span&gt; (&lt;span class=&quot;fu&quot;&gt;length&lt;/span&gt; xs)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now &lt;code&gt;mean&lt;/code&gt; takes a &lt;code&gt;NonEmpty&lt;/code&gt; list, which can only be
created safely using &lt;code&gt;nonEmpty :: [a] -&amp;gt; Maybe (NonEmpty a)&lt;/code&gt;
(where the caller has to explicitly handle the empty list case, so they’ll never
forget) or from functions that already return &lt;code&gt;NonEmpty&lt;/code&gt; by default
(like &lt;code&gt;some :: f a -&amp;gt; f (NonEmpty a)&lt;/code&gt; or
&lt;code&gt;group :: Eq a =&amp;gt; [a] -&amp;gt; [NonEmpty a]&lt;/code&gt;), allowing you to
beautifully chain post-conditions directly into pre-conditions.&lt;/p&gt;
&lt;p&gt;Accessing containers is, in general, very fraught…even things like indexing
lists can send us into a graveyard spiral. Sometimes the issue is more subtle.
This is our reminder to never let these implicit assumptions go unnoticed.&lt;/p&gt;
&lt;h3 id=&quot;separate-processed-data&quot;&gt;Separate Processed Data&lt;/h3&gt;
&lt;p&gt;“Shotgun parsing” involves mixing validated and unvalidated data at different
levels in your program. Oftentimes it is considered “fine” because you just need
to remember which inputs are validated and which aren’t…right? In truth, all it
takes is a simple temporary lapse of mental model, a time delay between working
on code, or uncoordinated contributions before things fall apart.&lt;/p&gt;
&lt;p&gt;Consider a situation where we validate usernames only on write to the
database.&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;validUsername ::&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;Bool&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;validUsername s &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;fu&quot;&gt;isAlphaNum&lt;/span&gt; s &lt;span class=&quot;op&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;all&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;isLower&lt;/span&gt; s&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&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;co&quot;&gt;-- | Returns 'Nothing' if username is invalid or insertion failed&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb18-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb18-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;saveUser ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Connection&lt;/span&gt; &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;IO&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UUID&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb18-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb18-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;saveUser conn s&lt;/span&gt;
&lt;span id=&quot;cb18-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb18-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; validUsername s &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;cb18-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb18-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      newId &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; query conn &lt;span class=&quot;st&quot;&gt;&quot;INSERT INTO users (username) VALUES (?) returning user_id&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Only&lt;/span&gt; s)&lt;/span&gt;
&lt;span id=&quot;cb18-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb18-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;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; newId &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb18-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb18-10&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;cb18-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb18-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;dt&quot;&gt;Only&lt;/span&gt; i &lt;span class=&quot;op&quot;&gt;:&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; i&lt;/span&gt;
&lt;span id=&quot;cb18-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb18-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;fu&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb18-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb18-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb18-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb18-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;getUser ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Connection&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UUID&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;Maybe&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb18-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb18-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;getUser conn uid &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;cb18-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb18-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  unames &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; query conn &lt;span class=&quot;st&quot;&gt;&quot;SELECT username FROM users where user_id = ?&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Only&lt;/span&gt; uid)&lt;/span&gt;
&lt;span id=&quot;cb18-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb18-17&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;kw&quot;&gt;case&lt;/span&gt; unames &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb18-18&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb18-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;cb18-19&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb18-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;Only&lt;/span&gt; s &lt;span class=&quot;op&quot;&gt;:&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; s&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It &lt;em&gt;should&lt;/em&gt; be fine as long as you only ever use &lt;code&gt;saveUser&lt;/code&gt;
and &lt;code&gt;getUser&lt;/code&gt;…and nobody else has access to the database. But, if
someone hooks up a custom connector, or does some manual modifications, then the
&lt;code&gt;users&lt;/code&gt; table will now have an invalid username, bypassing Haskell.
And because of that, &lt;code&gt;getUser&lt;/code&gt; can return an invalid string!&lt;/p&gt;
&lt;p&gt;Don’t assume that these inconsequential slip-ups won’t happen; assume that
it’s only a matter of time.&lt;/p&gt;
&lt;p&gt;Instead, we can bake the state of a validated string into the type
itself:&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;kw&quot;&gt;newtype&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Username&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UnsafeUsername&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&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;kw&quot;&gt;deriving&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Show&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Eq&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;&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;co&quot;&gt;-- | Our &quot;Smart Constructor&quot;&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;ot&quot;&gt;mkUsername ::&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;Maybe&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Username&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;mkUsername s&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;op&quot;&gt;|&lt;/span&gt; validUsername s &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;UnsafeUsername&lt;/span&gt; s)&lt;/span&gt;
&lt;span id=&quot;cb19-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb19-8&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;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#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;http://feeds.feedburner.com/incodeblog#cb19-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- | Access the raw string if needed&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb19-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;unUsername ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Username&lt;/span&gt; &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;cb19-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb19-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;unUsername (&lt;span class=&quot;dt&quot;&gt;UnsafeUsername&lt;/span&gt; s) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; s&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;Username&lt;/code&gt; and &lt;code&gt;String&lt;/code&gt; themselves are not structurally
different — instead, &lt;code&gt;Username&lt;/code&gt; is a compiler-enforced tag specifying
it went through a specific required validation function &lt;em&gt;within Haskell&lt;/em&gt;,
not just externally verified.&lt;/p&gt;
&lt;p&gt;Now &lt;code&gt;saveUser&lt;/code&gt; and &lt;code&gt;getUser&lt;/code&gt; are safe at the
boundaries:&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;saveUser ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Connection&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Username&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;Maybe&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UUID&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;saveUser conn s &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;cb20-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb20-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  newId &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; query conn &lt;span class=&quot;st&quot;&gt;&quot;INSERT INTO users (username) VALUES (?) returning user_id&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Only&lt;/span&gt; (unUsername s))&lt;/span&gt;
&lt;span id=&quot;cb20-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb20-4&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;kw&quot;&gt;case&lt;/span&gt; newId &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb20-5&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;cb20-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb20-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;Only&lt;/span&gt; i &lt;span class=&quot;op&quot;&gt;:&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; i&lt;/span&gt;
&lt;span id=&quot;cb20-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb20-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb20-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;getUser ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Connection&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UUID&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;Maybe&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Username&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb20-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb20-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;getUser conn uid &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;cb20-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb20-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  unames &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; query conn &lt;span class=&quot;st&quot;&gt;&quot;SELECT username FROM users where user_id = ?&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Only&lt;/span&gt; uid)&lt;/span&gt;
&lt;span id=&quot;cb20-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb20-11&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;kw&quot;&gt;case&lt;/span&gt; unames &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb20-12&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;cb20-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb20-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;Only&lt;/span&gt; s &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; _ &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; mkUsername s&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(In real code, of course, we would use a more usable indication of failure
than &lt;code&gt;Maybe&lt;/code&gt;)&lt;/p&gt;
&lt;p&gt;We can even hook this into Haskell’s typeclass system to make this even more
rigorous: &lt;code&gt;Username&lt;/code&gt; could have its own &lt;code&gt;FromField&lt;/code&gt; and
&lt;code&gt;ToField&lt;/code&gt; instances that push the validation to the driver level.&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;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FromField&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Username&lt;/span&gt; &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;http://feeds.feedburner.com/incodeblog#cb21-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  fromField f mdata &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;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;    s ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; fromField f mdata&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;    &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; mkUsername s &lt;span class=&quot;kw&quot;&gt;of&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; u  &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; u&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;Nothing&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; returnError &lt;span class=&quot;dt&quot;&gt;ConversionFailed&lt;/span&gt; f (&lt;span class=&quot;st&quot;&gt;&quot;Invalid username format: &quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;++&lt;/span&gt; s)&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&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;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ToField&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Username&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&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;  toField &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; toField &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; unUsername&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&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;ot&quot;&gt;saveUser ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Connection&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Username&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;Maybe&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UUID&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;saveUser conn s &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;cb21-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  newId &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; query conn &lt;span class=&quot;st&quot;&gt;&quot;INSERT INTO users (username) VALUES (?) returning user_id&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Only&lt;/span&gt; s)&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;  &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;kw&quot;&gt;case&lt;/span&gt; newId &lt;span class=&quot;kw&quot;&gt;of&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;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-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;Only&lt;/span&gt; i &lt;span class=&quot;op&quot;&gt;:&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; i&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&gt;
&lt;span id=&quot;cb21-18&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;getUser ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Connection&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;UUID&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;Maybe&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Username&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb21-19&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;getUser conn uid &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;cb21-20&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  unames &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; query conn &lt;span class=&quot;st&quot;&gt;&quot;SELECT username FROM users where user_id = ?&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Only&lt;/span&gt; uid)&lt;/span&gt;
&lt;span id=&quot;cb21-21&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-21&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;kw&quot;&gt;case&lt;/span&gt; unames &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-22&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-22&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;cb21-23&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;Only&lt;/span&gt; s &lt;span class=&quot;op&quot;&gt;:&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; s&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Pushing it to the driver level will also unify everything with the driver’s
error-handling system.&lt;/p&gt;
&lt;p&gt;These ideas are elaborated further in one of the best Haskell posts of all
time, &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;.&lt;/p&gt;
&lt;h3 id=&quot;boolean-blindness&quot;&gt;Boolean Blindness&lt;/h3&gt;
&lt;p&gt;At the heart of it, the previous examples’ cardinal sin was “boolean
blindness”. If we have a predicate like
&lt;code&gt;validUsername :: String -&amp;gt; Bool&lt;/code&gt;, we will branch on that
&lt;code&gt;Bool&lt;/code&gt; once and throw it away. Instead, by having a function like
&lt;code&gt;mkUsername :: String -&amp;gt; Maybe Username&lt;/code&gt;, we &lt;em&gt;keep&lt;/em&gt; the
proof alongside the value for the entire lifetime of the value. We basically
pair the string with its proof forever, making them inseparable.&lt;/p&gt;
&lt;p&gt;There was another example of such a thing earlier: instead of using
&lt;code&gt;null :: [a] -&amp;gt; Bool&lt;/code&gt; and gating a call to &lt;code&gt;mean&lt;/code&gt; with
&lt;code&gt;null&lt;/code&gt;, we instead use
&lt;code&gt;nonEmpty :: [a] -&amp;gt; Maybe (NonEmpty a)&lt;/code&gt;, and pass along the proof
of non-emptiness alongside the value itself. And, for the rest of that list’s
life, it will always be paired with its non-emptiness proof.&lt;/p&gt;
&lt;p&gt;Embracing total depravity means always keeping these proofs together, with
the witnesses bundled with the value itself, because if you don’t, someone is
going to assume it exists when it doesn’t, or drop it unnecessarily.&lt;/p&gt;
&lt;p&gt;Boolean blindness also has another facet, which is where &lt;code&gt;Bool&lt;/code&gt;
itself is not a semantically meaningful type. This is “semantic boolean
blindness”.&lt;/p&gt;
&lt;p&gt;The classic example is
&lt;code&gt;filter :: (a -&amp;gt; Bool) -&amp;gt; [a] -&amp;gt; [a]&lt;/code&gt;. It might sound silly
until it happens to you, but it is pretty easy to mix up if &lt;code&gt;True&lt;/code&gt;
means “keep” or “discard”. After all, a “water filter” only lets water through,
but a “profanity filter” only rejects profanity. Instead, how about
&lt;code&gt;mapMaybe :: (a -&amp;gt; Maybe b) -&amp;gt; [a] -&amp;gt; [b]&lt;/code&gt;? In that case, it
is clear that &lt;code&gt;Just&lt;/code&gt; results are kept, and the &lt;code&gt;Nothing&lt;/code&gt;
results are discarded.&lt;/p&gt;
&lt;p&gt;Sometimes, the boolean is ambiguous as to what it means. You can sort of
interpret the &lt;a href=&quot;https://en.wikipedia.org/wiki/Mars_Polar_Lander&quot;&gt;1999
Mars Polar Lander&lt;/a&gt; crash this way. Its functions took a boolean based on the
state of the legs:&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;deployThrusters ::&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;IO&lt;/span&gt; ()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and &lt;code&gt;True&lt;/code&gt; and &lt;code&gt;False&lt;/code&gt; were misinterpreted. Instead,
they could have considered semantically meaningful types: (simplified)&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;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;LegState&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Extended&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Retracted&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;ot&quot;&gt;deployThrusters ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;LegState&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;Note that &lt;code&gt;Maybe&lt;/code&gt; itself is not immune from “semantic blindness” —
if you find yourself using a lot of anonymous combinators like
&lt;code&gt;Maybe&lt;/code&gt; and &lt;code&gt;Either&lt;/code&gt; to get around boolean blindness, be
aware of falling into &lt;a href=&quot;https://github.com/quchen/articles/blob/master/algebraic-blindness.md&quot;&gt;algebraic
blindness&lt;/a&gt;!&lt;/p&gt;
&lt;h3 id=&quot;resource-cleanup&quot;&gt;Resource Cleanup&lt;/h3&gt;
&lt;p&gt;Clean-up of finite system resources is another area that is very easy to
assume you have a handle on before it gets out of hand and sneaks up on you.&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;process ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Handle&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;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;doTheThing ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FilePath&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;cb24-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;doTheThing path &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;cb24-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  h &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; openFile path &lt;span class=&quot;dt&quot;&gt;ReadMode&lt;/span&gt;&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;  process h&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;  hClose h&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A bunch of things could go wrong —&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You might forget to always &lt;code&gt;hClose&lt;/code&gt; a file handle, and if your
files come at you dynamically, you’re going to run out of file descriptors, or
hold on to locks longer than you should&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;process&lt;/code&gt; throws an exception, we never get to
&lt;code&gt;hClose&lt;/code&gt;, and the same issues happen&lt;/li&gt;
&lt;li&gt;If another thread throws an asynchronous exception (like a thread
cancellation), you have to make sure the close still happens!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The typical solution that other languages (like Python, modern Java) take is
to put everything inside a “block” where quitting the block guarantees the
closure. In Haskell we have the &lt;code&gt;bracket&lt;/code&gt; pattern:&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;-- strongly discourage using `openFile` and `hClose` directly&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;ot&quot;&gt;withFile ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FilePath&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Handle&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; r) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; r&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;withFile path &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; bracket (openFile path &lt;span class=&quot;dt&quot;&gt;ReadMode&lt;/span&gt;) hClose&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;&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;ot&quot;&gt;doTheThing ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FilePath&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;cb25-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb25-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;doTheThing path &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; withFile path &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; \h &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;cb25-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb25-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  process h&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you never use &lt;code&gt;openFile&lt;/code&gt; directly, and always use
&lt;code&gt;withFile&lt;/code&gt;, all file usage is safe!&lt;/p&gt;
&lt;p&gt;But, admittedly, continuations can be annoying to work with. For example,
what if you wanted to safely open a list of files?&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;processAll ::&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;Handle&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;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;doTheThings ::&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;FilePath&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;cb26-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb26-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;doTheThings paths &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;-- uh...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;All of a sudden, not so fun. And what if you had, for example, a Map of
files, like &lt;code&gt;Map Username FilePath&lt;/code&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;processAll ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Username&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Handle&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;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&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;ot&quot;&gt;doTheThings ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Username&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FilePath&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;cb27-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb27-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;doTheThings paths &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;-- uh...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In another language, at this point, we might just give up and resort to
manual opening and closing of files.&lt;/p&gt;
&lt;p&gt;But this is Haskell. We have a better solution: cleanup-tracking monads!&lt;/p&gt;
&lt;p&gt;This is a classic usage of &lt;code&gt;ContT&lt;/code&gt; to let you chain bracket-like
continuations:&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;processTwo ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Handle&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Handle&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;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;doTwoThings ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FilePath&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FilePath&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;cb28-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;doTwoThings path1 path2 &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; evalContT &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;cb28-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    h1 &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ContT&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; withFile path1&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;    h2 &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ContT&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; withFile path2&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;    liftIO &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; processTwo h1 h2&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;processAll ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Username&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Handle&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;cb28-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&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;ot&quot;&gt;doTheThings ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Username&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FilePath&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;cb28-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;doTheThings paths &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; evalContT &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;cb28-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    handles &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;traverse&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;ContT&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; withFile) paths&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;    liftIO &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; processAll handles&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;However, using &lt;code&gt;ContT&lt;/code&gt; doesn’t allow you to do things like early
cleanups or canceling cleanup events. It forces us into a last-in, first-out
sort of cleanup pattern. If you want to deviate, this might cause you to, for
convenience, go for manual resource management. However, we have tools for more
fine-grained control, we have things like &lt;em&gt;&lt;a href=&quot;https://hackage.haskell.org/package/resourcet&quot;&gt;resourcet&lt;/a&gt;&lt;/em&gt;
&lt;code&gt;ResourceT&lt;/code&gt;, which lets you manually control the order of clean-up
events, with the guarantee that all of them &lt;em&gt;eventually&lt;/em&gt; happen.&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;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;M&lt;/span&gt;&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;-- | Returns set of usernames to close&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 class=&quot;ot&quot;&gt;processAll ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Username&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Handle&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;Set&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Username&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;&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;&lt;span class=&quot;ot&quot;&gt;allocateFile ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FilePath&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ResourceT&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;ReleaseKey&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Handle&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb29-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb29-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;allocateFile fp &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; allocate (openFile fp &lt;span class=&quot;dt&quot;&gt;ReadMode&lt;/span&gt;) hClose&lt;/span&gt;
&lt;span id=&quot;cb29-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb29-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb29-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb29-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- Guarantees that all handles will eventually close, even if `go` crashes&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb29-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb29-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;doTheThings ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Username&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FilePath&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;cb29-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb29-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;doTheThings paths &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; runResourceT &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;cb29-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb29-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    releasersAndHandlers &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;traverse&lt;/span&gt; allocateFile paths&lt;/span&gt;
&lt;span id=&quot;cb29-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb29-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    go releasersAndHandlers&lt;/span&gt;
&lt;span id=&quot;cb29-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb29-14&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;cb29-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb29-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;co&quot;&gt;-- normal operation: slowly releases handlers as we drop them&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb29-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb29-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;    go ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Username&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;ReleaseKey&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Handle&lt;/span&gt;) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ResourceT&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id=&quot;cb29-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb29-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    go currOpen &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;cb29-18&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb29-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      toClose &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; liftIO &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; processAll (&lt;span class=&quot;fu&quot;&gt;snd&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; currOpen)&lt;/span&gt;
&lt;span id=&quot;cb29-19&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb29-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      traverse_ (release &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fst&lt;/span&gt;) (currOpen &lt;span class=&quot;ot&quot;&gt;`M.restrictKeys`&lt;/span&gt; toClose)&lt;/span&gt;
&lt;span id=&quot;cb29-20&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb29-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt; newOpen &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; currOpen &lt;span class=&quot;ot&quot;&gt;`M.withoutKeys`&lt;/span&gt; toClose&lt;/span&gt;
&lt;span id=&quot;cb29-21&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb29-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      unless (M.null newOpen) &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb29-22&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb29-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        go newOpen&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here we get the best of both worlds: the ability to manually close handlers
when they are no longer needed, but also the guarantee that they will eventually
be closed.&lt;/p&gt;
&lt;h2 id=&quot;embracing-total-depravity&quot;&gt;Embracing Total Depravity&lt;/h2&gt;
&lt;p&gt;Hopefully these examples, and similar situations, should feel relatable.
We’ve all experienced the biting pain of too much self-trust. Or, too much trust
in our ability to communicate with team members. Or, too much trust in ourselves
6 months from now. The traumas described here &lt;em&gt;should&lt;/em&gt; resonate with you
if you have programmed in any capacity for more than a couple of scripts.&lt;/p&gt;
&lt;p&gt;The doctrine of total depravity does not mean that we don’t recognize the
ability to write sloppy code that works, or that flow states can enable some
great feats. After all, we all program with a certain sense of &lt;em&gt;imago
machinae&lt;/em&gt;. Instead, it means that all such states are &lt;em&gt;fundamentally
unstable&lt;/em&gt; in their nature and will always fail at some point. The “total”
doesn’t mean we are totally cooked, it means this eventual reckoning applies to
&lt;em&gt;all&lt;/em&gt; such shortcuts.&lt;/p&gt;
&lt;p&gt;The problem won’t be solved by “get good”. The problem is solved by utilizing
the tooling we are given, especially since Haskell makes them so accessible and
easy to pull in.&lt;/p&gt;
&lt;p&gt;There’s another layer here that comes as a result of embracing this mindset:
you’ll find that you have more mental space to dedicate to things that actually
matter! Instead of worrying about inconsequential minutiae and details of your
flawed abstractions, you can actually think about your business logic, the flow
of your program, and architecting that castle of beauty I know you are capable
of.&lt;/p&gt;
&lt;h3 id=&quot;in-the-age-of-agentic-coding&quot;&gt;In the Age of Agentic Coding&lt;/h3&gt;
&lt;p&gt;Before we end, let’s address the elephant in the room. We’re writing this in
2026, in the middle of one of the biggest revolutions in software engineering in
the history of the field. A lot of people have claimed that types and safety are
now no longer important in the age of LLMs and agentic coding.&lt;/p&gt;
&lt;p&gt;However, these claims seem to miss the fact that the fundamental issue being
addressed here exists both in LLMs and humans: the limited “context window” and
attention. Humans might be barely able to keep a dozen things in our heads, LLMs
might be able to keep a dozen dozen things, but it will still be ultimately
finite. So, the more we can move concerns out of our context window (be it
biological or mechanical), the less crowded our context windows will be, and the
more productive we will be.&lt;/p&gt;
&lt;p&gt;Agentic coding is progressing quickly, and over the past few months I have
been exploring this a lot, using models hands-on. One conclusion I have found
(and, this agrees with everyone else I’ve asked who has been trying the same
thing) is that Haskell’s types, in many ways, are the killer productivity secret
of agentic coding.&lt;/p&gt;
&lt;p&gt;Many of my Haskell coding tasks for an LLM agent often involve:&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;How will the types change, or what should the types be?&lt;/li&gt;
&lt;li&gt;Ralph Wiggum loop to death until the program typechecks, using
&lt;code&gt;ghci&lt;/code&gt; and &lt;code&gt;cabal&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And, this isn’t 100% effective, but from personal experience it is much more
effective than the similar situation without typed guardrails for fast feedback,
and without instant compiler feedback. The feedback loop is tighter, the
objectives clearer, the constraints more resilient, the tooling more
utilized.&lt;/p&gt;
&lt;p&gt;I have noticed, also, that my LLM agents often check the types of the APIs
using &lt;code&gt;ghci :type&lt;/code&gt;, and rarely the documentation of the functions
using &lt;code&gt;ghci :docs&lt;/code&gt;. So, any “documentation-based contracts” are
definitely much more likely to explode in your face in this new world than
type-based contracts.&lt;/p&gt;
&lt;p&gt;I’m not sure how quickly LLM-based agentic coding will progress, but I am
sure that the accidental “dropping” of concerns will continue to be a
bottleneck. All of the traits described in this post for humans will continue to
be traits of limited context windows for LLMs.&lt;/p&gt;
&lt;p&gt;If anything, limited “brain space” might be &lt;em&gt;the&lt;/em&gt; bottleneck, for both
humans and LLMs. If provide LLMs with properly “depravity-aware” typed code (and
encourage them to write it by giving them the right iterative tooling), I truly
believe that we have the key to unlocking the full potential of agentic
coding.&lt;/p&gt;
&lt;p&gt;And…not whatever &lt;a href=&quot;https://x.com/rywalker/status/2003525268821188746&quot;&gt;this tweet is&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;the-next-step&quot;&gt;The Next Step&lt;/h3&gt;
&lt;p&gt;Total depravity is all about using types to &lt;em&gt;prevent errors&lt;/em&gt;. However,
you can only go so far with defensive programming and carefully picking the
structure of your types. Sometimes, it feels like you are expending a lot of
energy and human effort just picking the perfectly designed data type, only for
things out of your hand to ruin your typed castle.&lt;/p&gt;
&lt;p&gt;In the next chapter, we’ll see how a little-discussed aspect of Haskell’s
type system gives you a powerful tool for opening your mind to new avenues of
design that were impossible before. At the same time, we’ll see how we can
leverage universal properties of mathematics itself to help us analyze our code
in unexpected ways.&lt;/p&gt;
&lt;p&gt;Let’s explore this further in the next principle 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;Unconditional Election&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;p&gt;Also thanks to &lt;a href=&quot;https://www.reddit.com/r/haskell/comments/1qtxnsm/comment/o3889uy&quot;&gt;&lt;em&gt;jackdk&lt;/em&gt;’s
comment&lt;/a&gt; for highlighting extra resources and context that I believe are very
useful and relevant!&lt;/p&gt;</description>
	<pubDate>Mon, 02 Feb 2026 15:06:46 +0000</pubDate>
</item>
<item>
	<title>Gabriella Gonzalez: My experience with vibe coding&gt;</title>
	<guid isPermaLink="true">https://haskellforall.com/2026/02/my-experience-with-vibe-coding</guid>
	<link>https://haskellforall.com/2026/02/my-experience-with-vibe-coding</link>
	<description>Vibe coding isn't a silver bullet</description>
	<pubDate>Mon, 02 Feb 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Oskar Wickström: There and Back Again: From Quickstrom to Bombadil</title>
	<guid isPermaLink="true">https://wickstrom.tech/2026-01-28-there-and-back-again-from-quickstrom-to-bombadil.html</guid>
	<link>https://wickstrom.tech/2026-01-28-there-and-back-again-from-quickstrom-to-bombadil.html</link>
	<description>&lt;p&gt;Today I’m announcing and open-sourcing the &lt;a href=&quot;https://github.com/antithesishq/bombadil&quot;&gt;Bombadil&lt;/a&gt; project — a brand new property-based browser testing framework. I started working on this when joining Antithesis two months ago. While still in its infancy, we’ve decided to build it in the open and share our progress from the start.&lt;/p&gt; &lt;p&gt;We decided on the name Bombadil last week. A few days later, this exploded:&lt;/p&gt; &lt;blockquote class=&quot;twitter-tweet&quot;&gt; &lt;p dir=&quot;ltr&quot; lang=&quot;en&quot;&gt; It's going to be tough for startups when all the Lord of the Rings names are taken and the only thing left is something like Bombadil AI. &lt;/p&gt; — Patrick Collison (&lt;span class=&quot;citation&quot;&gt;@patrickc&lt;/span&gt;) &lt;a href=&quot;https://twitter.com/patrickc/status/2015562569105465347?ref_src=twsrc%5Etfw&quot;&gt;January 25, 2026&lt;/a&gt; &lt;/blockquote&gt;  &lt;p&gt;While &lt;a href=&quot;https://github.com/quickstrom/quickstrom&quot;&gt;Quickstrom&lt;/a&gt; proved its worth, &lt;a href=&quot;https://dl.acm.org/doi/10.1145/3519939.3523728&quot;&gt;finding bugs in more than half of the TodoMVC&lt;/a&gt; apps, Bombadil aims to improve on its shortcomings while also envisioning a more ambitious future for generative testing of web apps: faster and smarter state space exploration, a modern and usable specification language, better tools for reproducing and debugging test failures, and a better distribution story.&lt;/p&gt; &lt;p&gt;I consider Bombadil the successor of Quickstrom. After years of trying to sustain Quickstrom through various models, I now have a much better answer: building it at Antithesis, making something valuable that is open and free to use, while also strengthening the company’s commercial offering. Bombadil can be used locally or in CI to test your web apps early. Power users can take it further and run Bombadil within Antithesis and its deterministic hypervisor. That gives you perfect reproductions of failed tests. You can even combine Bombadil with other workloads in Antithesis and test your entire stack deterministically. Isn’t that the holy grail of testing?&lt;/p&gt; &lt;p&gt;Bombadil is built from scratch with a focus on accessibility: a new specification language and better tooling for writing and maintaining specs. Right now, I’m working on a specification DSL in TypeScript. It’s based on &lt;a href=&quot;https://en.wikipedia.org/wiki/Linear_temporal_logic&quot;&gt;linear temporal logic&lt;/a&gt;, just as Quickstrom, but aims to be a lot more ergonomic. Here’s an example that verifies that error messages eventually disappear:&lt;/p&gt; &lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode typescript&quot;&gt;&lt;code class=&quot;sourceCode typescript&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;kw&quot;&gt;const&lt;/span&gt; errorMessage &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;extract&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; (state) &lt;span class=&quot;kw&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;span id=&quot;cb1-3&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb1-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; state&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;at&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;at&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;querySelector&lt;/span&gt;(&lt;span class=&quot;st&quot;&gt;&quot;.error&quot;&lt;/span&gt;)&lt;/span&gt; &lt;span id=&quot;cb1-4&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#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;at&quot;&gt;textContent&lt;/span&gt; &lt;/span&gt; &lt;span id=&quot;cb1-5&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#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;kw&quot;&gt;null&lt;/span&gt;&lt;/span&gt; &lt;span id=&quot;cb1-6&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb1-6&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;cb1-7&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb1-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt; &lt;span id=&quot;cb1-8&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb1-8&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; errorEventuallyDisappears &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;always&lt;/span&gt;(&lt;/span&gt; &lt;span id=&quot;cb1-9&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb1-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; &lt;span class=&quot;fu&quot;&gt;condition&lt;/span&gt;(() &lt;span class=&quot;kw&quot;&gt;=&amp;gt;&lt;/span&gt; errorMessage &lt;span class=&quot;op&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;null&lt;/span&gt;)&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;implies&lt;/span&gt;(&lt;/span&gt; &lt;span id=&quot;cb1-10&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb1-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; &lt;span class=&quot;fu&quot;&gt;eventually&lt;/span&gt;(() &lt;span class=&quot;kw&quot;&gt;=&amp;gt;&lt;/span&gt; errorMessage &lt;span class=&quot;op&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;null&lt;/span&gt;)&lt;/span&gt; &lt;span id=&quot;cb1-11&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb1-11&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;within&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;st&quot;&gt;&quot;seconds&quot;&lt;/span&gt;)&lt;/span&gt; &lt;span id=&quot;cb1-12&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb1-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; )&lt;/span&gt; &lt;span id=&quot;cb1-13&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb1-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;Both the original hacky PureScript DSL and the bespoke language &lt;em&gt;Specstrom&lt;/em&gt; were huge obstacles to adoption. Today, TypeScript is a widely adopted language among quality-minded web developers, and if you’re not into that, Bombadil will work with plain JavaScript too.&lt;/p&gt; &lt;p&gt;We’re writing Bombadil in Rust, leveraging its excellent ecosystem to ship a single statically-linked executable — download for your platform, point it at a Chromium-based browser, and off you go!&lt;/p&gt; &lt;p&gt;Bombadil is early but usable. Check it out on &lt;a href=&quot;https://github.com/antithesishq/bombadil&quot;&gt;GitHub&lt;/a&gt;, try it on your projects, and let us know what breaks. Also let us know what &lt;em&gt;it&lt;/em&gt; breaks in your systems! Join us on &lt;a href=&quot;https://discord.gg/antithesis&quot;&gt;Discord&lt;/a&gt; for help and discussion, or follow development on &lt;a href=&quot;https://x.com/owickstrom&quot;&gt;Twitter/X&lt;/a&gt;. This is just the beginning — we’re actively seeking feedback and early adopters to help shape where this goes.&lt;/p&gt;</description>
	<pubDate>Tue, 27 Jan 2026 23:00:00 +0000</pubDate>
</item>
<item>
	<title>Magnus Therning: More on the switch to eglot</title>
	<guid isPermaLink="true">https://magnus.therning.org/2026-01-25-more-on-the-switch-to-eglot.html</guid>
	<link>https://magnus.therning.org/2026-01-25-more-on-the-switch-to-eglot.html</link>
	<description>&lt;p&gt;
Since the &lt;a href=&quot;https://magnus.therning.org/2026-01-19-trying-eglot,-again.html&quot;&gt;switching to eglot&lt;/a&gt; I've ended up making a few related changes.
&lt;/p&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-org8cdfce1&quot;&gt;
&lt;h2 id=&quot;org8cdfce1&quot;&gt;Replacing flycheck with flymake&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-org8cdfce1&quot;&gt;
&lt;p&gt;
Since &lt;code&gt;eglot&lt;/code&gt; it's written to work with other packages in core, which means it
integrates with &lt;a href=&quot;https://www.gnu.org/software/emacs/manual/html_mono/flymake.html&quot;&gt;&lt;code&gt;flymake&lt;/code&gt;&lt;/a&gt;. The switch comprised
&lt;/p&gt;

&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Use &lt;code&gt;:ensure nil&lt;/code&gt; to make sure &lt;code&gt;elpaca&lt;/code&gt; knows there's nothing to download.&lt;/li&gt;
&lt;li&gt;Add a call to &lt;code&gt;flymake-mode&lt;/code&gt; to &lt;code&gt;prog-mode-hook&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Define two functions to toggle showing a list of diagnostics for the current
buffer and the project.&lt;/li&gt;
&lt;li&gt;&lt;/li&gt;

&lt;li&gt;Redefine the relevant keybindings.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
The two functions for toggling showing diagnostics look like this
&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;mes/toggle-flymake-buffer-diagnostics&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;&lt;span class=&quot;org-keyword&quot;&gt;interactive&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;&lt;span class=&quot;org-keyword&quot;&gt;if-let*&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-4&quot;&gt;(&lt;/span&gt;window &lt;span class=&quot;org-rainbow-delimiters-depth-5&quot;&gt;(&lt;/span&gt;get-buffer-window &lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;(&lt;/span&gt;flymake--diagnostics-buffer-name&lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;)&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-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;save-selected-window&lt;/span&gt; &lt;span class=&quot;org-rainbow-delimiters-depth-4&quot;&gt;(&lt;/span&gt;quit-window nil window&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;flymake-show-buffer-diagnostics&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;defun&lt;/span&gt; &lt;span class=&quot;org-function-name&quot;&gt;mes/toggle-flymake-project-diagnostics&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;&lt;span class=&quot;org-keyword&quot;&gt;interactive&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;&lt;span class=&quot;org-keyword&quot;&gt;if-let*&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-4&quot;&gt;(&lt;/span&gt;window &lt;span class=&quot;org-rainbow-delimiters-depth-5&quot;&gt;(&lt;/span&gt;get-buffer-window &lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;(&lt;/span&gt;flymake--project-diagnostics-buffer &lt;span class=&quot;org-rainbow-delimiters-depth-7&quot;&gt;(&lt;/span&gt;projectile-project-root&lt;span class=&quot;org-rainbow-delimiters-depth-7&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;)&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-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;save-selected-window&lt;/span&gt; &lt;span class=&quot;org-rainbow-delimiters-depth-4&quot;&gt;(&lt;/span&gt;quit-window nil window&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;flymake-show-project-diagnostics&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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
And the changed keybindings are
&lt;/p&gt;

&lt;table&gt;


&lt;colgroup&gt;
&lt;col class=&quot;org-left&quot; /&gt;

&lt;col class=&quot;org-left&quot; /&gt;
&lt;/colgroup&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th class=&quot;org-left&quot; scope=&quot;col&quot;&gt;flycheck&lt;/th&gt;
&lt;th class=&quot;org-left&quot; scope=&quot;col&quot;&gt;flymake&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td class=&quot;org-left&quot;&gt;flycheck-next-error&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;flymake-goto-next-error&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class=&quot;org-left&quot;&gt;flycheck-previous-error&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;flymake-goto-prev-error&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class=&quot;org-left&quot;&gt;mes/toggle-flycheck-error-list&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;mes/toggle-flymake-buffer-diagnostics&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class=&quot;org-left&quot;&gt;mes/toggle-flycheck-projectile-error-list&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;mes/toggle-flymake-project-diagnostics&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgadc4f2e&quot;&gt;
&lt;h2 id=&quot;orgadc4f2e&quot;&gt;Using &lt;code&gt;with-eval-after-load&lt;/code&gt; instead of &lt;code&gt;:after eglot&lt;/code&gt;&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgadc4f2e&quot;&gt;
&lt;p&gt;
When it comes to &lt;code&gt;use-package&lt;/code&gt; I keep on being surprised, and after the switch
to &lt;code&gt;elpaca&lt;/code&gt; I've found some new surprises. One of them was that using &lt;code&gt;:after
eglot&lt;/code&gt; like this
&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;use-package&lt;/span&gt; haskell-ng-mode
  &lt;span class=&quot;org-builtin&quot;&gt;:afer&lt;/span&gt; eglot
  &lt;span class=&quot;org-builtin&quot;&gt;:ensure&lt;/span&gt; &lt;span class=&quot;org-rainbow-delimiters-depth-2&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-builtin&quot;&gt;:type&lt;/span&gt; git
           &lt;span class=&quot;org-builtin&quot;&gt;:repo&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;git@gitlab.com:magus/haskell-ng-mode.git&quot;&lt;/span&gt;
           &lt;span class=&quot;org-builtin&quot;&gt;:branch&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;main&quot;&lt;/span&gt;&lt;span class=&quot;org-rainbow-delimiters-depth-2&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;org-builtin&quot;&gt;:init&lt;/span&gt;
  &lt;span class=&quot;org-rainbow-delimiters-depth-2&quot;&gt;(&lt;/span&gt;add-to-list 'major-mode-remap-alist '&lt;span class=&quot;org-rainbow-delimiters-depth-3&quot;&gt;(&lt;/span&gt;haskell-mode . haskell-ng-mode&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;add-to-list 'eglot-server-programs '&lt;span class=&quot;org-rainbow-delimiters-depth-3&quot;&gt;(&lt;/span&gt;haskell-ng-mode &lt;span class=&quot;org-string&quot;&gt;&quot;haskell-language-server-wrapper&quot;&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;--lsp&quot;&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-2&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-keyword&quot;&gt;setq-default&lt;/span&gt; eglot-workspace-configuration
                &lt;span class=&quot;org-rainbow-delimiters-depth-3&quot;&gt;(&lt;/span&gt;plist-put eglot-workspace-configuration
                           &lt;span class=&quot;org-builtin&quot;&gt;:haskell&lt;/span&gt;
                           '&lt;span class=&quot;org-rainbow-delimiters-depth-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-builtin&quot;&gt;:formattingProvider&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;fourmolu&quot;&lt;/span&gt;
                             &lt;span class=&quot;org-builtin&quot;&gt;:plugin&lt;/span&gt; &lt;span class=&quot;org-rainbow-delimiters-depth-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-builtin&quot;&gt;:stan&lt;/span&gt; &lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-builtin&quot;&gt;:global-on&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:json-false&lt;/span&gt;&lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;)&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-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-builtin&quot;&gt;:hook&lt;/span&gt;
  &lt;span class=&quot;org-rainbow-delimiters-depth-2&quot;&gt;(&lt;/span&gt;haskell-ng-mode . eglot-ensure&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;
would delay initialisation until after &lt;code&gt;eglot&lt;/code&gt; had been loaded. However, it
turned out that nothing in &lt;code&gt;:init ...&lt;/code&gt; seemed to run and upon opening a haskell file
no mode was loaded.
&lt;/p&gt;

&lt;p&gt;
After a bit of thinking and tinkering I got it working by removing &lt;code&gt;:after
eglot&lt;/code&gt; and using &lt;code&gt;with-eval-after-load&lt;/code&gt;
&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;use-package&lt;/span&gt; haskell-ng-mode
  &lt;span class=&quot;org-builtin&quot;&gt;:ensure&lt;/span&gt; &lt;span class=&quot;org-rainbow-delimiters-depth-2&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-builtin&quot;&gt;:type&lt;/span&gt; git
           &lt;span class=&quot;org-builtin&quot;&gt;:repo&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;git@gitlab.com:magus/haskell-ng-mode.git&quot;&lt;/span&gt;
           &lt;span class=&quot;org-builtin&quot;&gt;:branch&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;main&quot;&lt;/span&gt;&lt;span class=&quot;org-rainbow-delimiters-depth-2&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;org-builtin&quot;&gt;:init&lt;/span&gt;
  &lt;span class=&quot;org-rainbow-delimiters-depth-2&quot;&gt;(&lt;/span&gt;add-to-list 'major-mode-remap-alist '&lt;span class=&quot;org-rainbow-delimiters-depth-3&quot;&gt;(&lt;/span&gt;haskell-mode . haskell-ng-mode&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;&lt;span class=&quot;org-keyword&quot;&gt;with-eval-after-load&lt;/span&gt; 'eglot
    &lt;span class=&quot;org-rainbow-delimiters-depth-3&quot;&gt;(&lt;/span&gt;add-to-list 'eglot-server-programs '&lt;span class=&quot;org-rainbow-delimiters-depth-4&quot;&gt;(&lt;/span&gt;haskell-ng-mode &lt;span class=&quot;org-string&quot;&gt;&quot;haskell-language-server-wrapper&quot;&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;--lsp&quot;&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;setq-default&lt;/span&gt; eglot-workspace-configuration
                  &lt;span class=&quot;org-rainbow-delimiters-depth-4&quot;&gt;(&lt;/span&gt;plist-put eglot-workspace-configuration
                             &lt;span class=&quot;org-builtin&quot;&gt;:haskell&lt;/span&gt;
                             '&lt;span class=&quot;org-rainbow-delimiters-depth-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-builtin&quot;&gt;:formattingProvider&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;fourmolu&quot;&lt;/span&gt;
                               &lt;span class=&quot;org-builtin&quot;&gt;:plugin&lt;/span&gt; &lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-builtin&quot;&gt;:stan&lt;/span&gt; &lt;span class=&quot;org-rainbow-delimiters-depth-7&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-builtin&quot;&gt;:global-on&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:json-false&lt;/span&gt;&lt;span class=&quot;org-rainbow-delimiters-depth-7&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;)&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-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-builtin&quot;&gt;:hook&lt;/span&gt;
  &lt;span class=&quot;org-rainbow-delimiters-depth-2&quot;&gt;(&lt;/span&gt;haskell-ng-mode . eglot-ensure&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;
That change worked for haskell, and it seemed to work for python too, but after
a little while I realised that python needed a bit more attention.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgc610d55&quot;&gt;
&lt;h2 id=&quot;orgc610d55&quot;&gt;Getting the configuration for Python to work properly&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgc610d55&quot;&gt;
&lt;p&gt;
The python setup looked like this
&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;use-package&lt;/span&gt; python
  &lt;span class=&quot;org-builtin&quot;&gt;:init&lt;/span&gt;
  &lt;span class=&quot;org-rainbow-delimiters-depth-2&quot;&gt;(&lt;/span&gt;add-to-list 'major-mode-remap-alist '&lt;span class=&quot;org-rainbow-delimiters-depth-3&quot;&gt;(&lt;/span&gt;python-mode . python-ts-mode&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;&lt;span class=&quot;org-keyword&quot;&gt;with-eval-after-load&lt;/span&gt; 'eglot
    &lt;span class=&quot;org-rainbow-delimiters-depth-3&quot;&gt;(&lt;/span&gt;assoc-delete-all '&lt;span class=&quot;org-rainbow-delimiters-depth-4&quot;&gt;(&lt;/span&gt;python-mode python-ts-mode&lt;span class=&quot;org-rainbow-delimiters-depth-4&quot;&gt;)&lt;/span&gt; eglot-server-programs&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;add-to-list 'eglot-server-programs
                 `&lt;span class=&quot;org-rainbow-delimiters-depth-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-rainbow-delimiters-depth-5&quot;&gt;(&lt;/span&gt;python-mode python-ts-mode&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;eglot-alternatives
                                                    '&lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-rainbow-delimiters-depth-7&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&quot;rass&quot;&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;python&quot;&lt;/span&gt;&lt;span class=&quot;org-rainbow-delimiters-depth-7&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;pylsp&quot;&lt;/span&gt;&lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;)&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-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-builtin&quot;&gt;:hook&lt;/span&gt; &lt;span class=&quot;org-rainbow-delimiters-depth-2&quot;&gt;(&lt;/span&gt;python-ts-mode . eglot-ensure&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 it worked all right, but then I visited the package (using &lt;code&gt;elpaca-visit&lt;/code&gt;)
and realised that the downloaded package was all of emacs. That's a bit of
overkill, I'd say.
&lt;/p&gt;

&lt;p&gt;
However, adding &lt;code&gt;:ensure nil&lt;/code&gt; didn't have the expected effect of just using the
version that's in core. Instead the whole configuration seemed to never take
effect and again I was back to the situation where I had to jump to
&lt;code&gt;python-ts-mode&lt;/code&gt; manually.
&lt;/p&gt;

&lt;p&gt;
The documentation for &lt;code&gt;use-package&lt;/code&gt; says that &lt;code&gt;:init&lt;/code&gt; is for
&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;
Code to run before PACKAGE-NAME has been loaded.
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
but I'm guessing &quot;before&quot; isn't quite before enough. Then I noticed &lt;code&gt;:preface&lt;/code&gt;
with the description
&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;
Code to be run before everything except &lt;code&gt;:disabled&lt;/code&gt;; this can be used to define
functions for use in &lt;code&gt;:if&lt;/code&gt;, or that should be seen by the byte-compiler.
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
and yes, &quot;before everything&quot; is early enough. The final python configuration
looks like this
&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;use-package&lt;/span&gt; python
  &lt;span class=&quot;org-builtin&quot;&gt;:ensure&lt;/span&gt; nil
  &lt;span class=&quot;org-builtin&quot;&gt;:preface&lt;/span&gt;
  &lt;span class=&quot;org-rainbow-delimiters-depth-2&quot;&gt;(&lt;/span&gt;add-to-list 'major-mode-remap-alist '&lt;span class=&quot;org-rainbow-delimiters-depth-3&quot;&gt;(&lt;/span&gt;python-mode . python-ts-mode&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-builtin&quot;&gt;:init&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;with-eval-after-load&lt;/span&gt; 'eglot
    &lt;span class=&quot;org-rainbow-delimiters-depth-3&quot;&gt;(&lt;/span&gt;assoc-delete-all '&lt;span class=&quot;org-rainbow-delimiters-depth-4&quot;&gt;(&lt;/span&gt;python-mode python-ts-mode&lt;span class=&quot;org-rainbow-delimiters-depth-4&quot;&gt;)&lt;/span&gt; eglot-server-programs&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;add-to-list 'eglot-server-programs
                 `&lt;span class=&quot;org-rainbow-delimiters-depth-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-rainbow-delimiters-depth-5&quot;&gt;(&lt;/span&gt;python-mode python-ts-mode&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;eglot-alternatives
                                                    '&lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-rainbow-delimiters-depth-7&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&quot;rass&quot;&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;python&quot;&lt;/span&gt;&lt;span class=&quot;org-rainbow-delimiters-depth-7&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;pylsp&quot;&lt;/span&gt;&lt;span class=&quot;org-rainbow-delimiters-depth-6&quot;&gt;)&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-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-builtin&quot;&gt;:hook&lt;/span&gt; &lt;span class=&quot;org-rainbow-delimiters-depth-2&quot;&gt;(&lt;/span&gt;python-ts-mode . eglot-ensure&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;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgc2d0d13&quot;&gt;
&lt;h2 id=&quot;orgc2d0d13&quot;&gt;Closing remark&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgc2d0d13&quot;&gt;
&lt;p&gt;
I'm still not sure I have the correct intuition about how to use &lt;code&gt;use-package&lt;/code&gt;,
but hopefully it's &lt;i&gt;more&lt;/i&gt; correct now than before. I have a growing suspicion
that &lt;code&gt;use-package&lt;/code&gt; changes behaviour based on the package manager I use. Or
maybe it's just that some package managers make &lt;code&gt;use-package&lt;/code&gt; more forgiving of
bad use.
&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-eglot.html&quot;&gt;eglot&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>Sun, 25 Jan 2026 13:18:00 +0000</pubDate>
</item>
<item>
	<title>Gabriella Gonzalez: Type-safe eval in Grace&gt;</title>
	<guid isPermaLink="true">https://haskellforall.com/2026/01/typesafe-eval</guid>
	<link>https://haskellforall.com/2026/01/typesafe-eval</link>
	<description>The case for principled eval support</description>
	<pubDate>Tue, 20 Jan 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Magnus Therning: Trying eglot, again</title>
	<guid isPermaLink="true">https://magnus.therning.org/2026-01-19-trying-eglot,-again.html</guid>
	<link>https://magnus.therning.org/2026-01-19-trying-eglot,-again.html</link>
	<description>&lt;p&gt;
I've been using &lt;a href=&quot;https://emacs-lsp.github.io/lsp-mode/&quot;&gt;lsp-mode&lt;/a&gt; since I switched to Emacs several years ago. When &lt;a href=&quot;https://github.com/joaotavora/eglot&quot;&gt;eglot&lt;/a&gt;
made into Emacs core I used it very briefly but quickly switched back. Mainly I
found eglot a bit too bare-bones; I liked some of the bells and whistles of
&lt;code&gt;lsp-ui&lt;/code&gt;. Fast-forward a few years and I've grown a bit tired of those bells and
whistles. Specifically that it's difficult to make &lt;code&gt;lsp-ui-sideline&lt;/code&gt; and
&lt;code&gt;lsp-ui-doc&lt;/code&gt; work well together. &lt;code&gt;lsp-ui-sidedline&lt;/code&gt; is shown on the right side,
which is good, but combining it with &lt;code&gt;lsp-ui-doc&lt;/code&gt; leads to situations where the
popup covers the sideline. What I've done so far is centre the line to bring the
sideline text out. I was playing a little bit with making the setting of
&lt;code&gt;lsp-ui-doc-position&lt;/code&gt; change depending on the location of the current position.
It didn't work that well though so I decided to try to find a simpler setup.
Instead of simplifying the setup of &lt;code&gt;lsp-config&lt;/code&gt; I thought I'd give &lt;code&gt;eglot&lt;/code&gt;
another shot.
&lt;/p&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgb1f7433&quot;&gt;
&lt;h2 id=&quot;orgb1f7433&quot;&gt;Basic setup&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgb1f7433&quot;&gt;
&lt;p&gt;
I removed the statements pulling in &lt;code&gt;lsp-mode&lt;/code&gt;, &lt;code&gt;lsp-ui&lt;/code&gt;, and all
language-specific packages like &lt;code&gt;lsp-haskell&lt;/code&gt;. Then I added this to configure
&lt;code&gt;eglot&lt;/code&gt;
&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;use-package&lt;/span&gt; eglot
  &lt;span class=&quot;org-builtin&quot;&gt;:ensure&lt;/span&gt; nil
  &lt;span class=&quot;org-builtin&quot;&gt;:custom&lt;/span&gt;
  &lt;span class=&quot;org-rainbow-delimiters-depth-2&quot;&gt;(&lt;/span&gt;eglot-autoshutdown t&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;eglot-confirm-server-edits '&lt;span class=&quot;org-rainbow-delimiters-depth-3&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-rainbow-delimiters-depth-4&quot;&gt;(&lt;/span&gt;eglot-rename . nil&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;t . diff&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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
The rest was mainly just switching &lt;code&gt;lsp-mode&lt;/code&gt; functions for &lt;code&gt;eglot&lt;/code&gt; functions.
&lt;/p&gt;

&lt;table&gt;


&lt;colgroup&gt;
&lt;col class=&quot;org-left&quot; /&gt;

&lt;col class=&quot;org-left&quot; /&gt;
&lt;/colgroup&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th class=&quot;org-left&quot; scope=&quot;col&quot;&gt;lsp-mode function&lt;/th&gt;
&lt;th class=&quot;org-left&quot; scope=&quot;col&quot;&gt;eglot function&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td class=&quot;org-left&quot;&gt;&lt;code&gt;lsp-deferred&lt;/code&gt;&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;&lt;code&gt;eglot-ensure&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class=&quot;org-left&quot;&gt;&lt;code&gt;lsp-describe-thing-at-point&lt;/code&gt;&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;&lt;code&gt;eldoc&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class=&quot;org-left&quot;&gt;&lt;code&gt;lsp-execute-code-action&lt;/code&gt;&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;&lt;code&gt;eglot-code-actions&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class=&quot;org-left&quot;&gt;&lt;code&gt;lsp-find-type-definition&lt;/code&gt;&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;&lt;code&gt;eglot-find-typeDefinition&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class=&quot;org-left&quot;&gt;&lt;code&gt;lsp-format-buffer&lt;/code&gt;&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;&lt;code&gt;eglot-format-buffer&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class=&quot;org-left&quot;&gt;&lt;code&gt;lsp-format-region&lt;/code&gt;&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;&lt;code&gt;eglot-format&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class=&quot;org-left&quot;&gt;&lt;code&gt;lsp-organize-imports&lt;/code&gt;&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;&lt;code&gt;eglot-code-action-organize-imports&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class=&quot;org-left&quot;&gt;&lt;code&gt;lsp-rename&lt;/code&gt;&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;&lt;code&gt;eglot-rename&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class=&quot;org-left&quot;&gt;&lt;code&gt;lsp-workspace-restart&lt;/code&gt;&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;&lt;code&gt;eglot-reconnect&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class=&quot;org-left&quot;&gt;&lt;code&gt;lsp-workspace-shutdown&lt;/code&gt;&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;&lt;code&gt;eglot-shutdown&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;
I haven't verified that the list is fully correct yet, but it looks good so far.
&lt;/p&gt;

&lt;p&gt;
The one thing I might miss is lenses, and using &lt;code&gt;lsp-avy-lens&lt;/code&gt;. However,
everything that I use lenses for can be done using actions, and to be honest I
don't think I'll miss the huge lens texts from missing type annotations in
Haskell.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgd8ac829&quot;&gt;
&lt;h2 id=&quot;orgd8ac829&quot;&gt;Configuration&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgd8ac829&quot;&gt;
&lt;p&gt;
One good thing about &lt;code&gt;lsp-mode&lt;/code&gt;'s use of language-specific packages is that
configuration of the various servers is performed through functions. This makes
it easy to discover what options are available, though it also means not all
options may be available. In &lt;code&gt;eglot&lt;/code&gt; configuration is less organised, I have to
know about the options for each language server and put the options into
&lt;code&gt;eglot-workspace-configuration&lt;/code&gt; myself. It's not always easy to track down what
options are available, and I've found no easy way to verify the settings. For
instance, with &lt;code&gt;lsp-mode&lt;/code&gt; I configures &lt;a href=&quot;https://github.com/haskell/haskell-language-server&quot;&gt;HLS&lt;/a&gt; like this
&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;lsp-haskell-formatting-provider &lt;span class=&quot;org-string&quot;&gt;&quot;fourmolu&quot;&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;lsp-haskell-plugin-stan-global-on nil&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;
which translates to this for &lt;code&gt;eglot&lt;/code&gt;
&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-default&lt;/span&gt; eglot-workspace-configuration
              &lt;span class=&quot;org-rainbow-delimiters-depth-2&quot;&gt;(&lt;/span&gt;plist-put eglot-workspace-configuration
                         &lt;span class=&quot;org-builtin&quot;&gt;:haskell&lt;/span&gt;
                         '&lt;span class=&quot;org-rainbow-delimiters-depth-3&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-builtin&quot;&gt;:formattingProvider&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;fourmolu&quot;&lt;/span&gt;
                           &lt;span class=&quot;org-builtin&quot;&gt;:plugin&lt;/span&gt; &lt;span class=&quot;org-rainbow-delimiters-depth-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-builtin&quot;&gt;:stan&lt;/span&gt; &lt;span class=&quot;org-rainbow-delimiters-depth-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-builtin&quot;&gt;:global-on&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:json-false&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-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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
and I can verify that this configuration has taken effect because I know enough
about the Haskell tools.
&lt;/p&gt;

&lt;p&gt;
I do some development in Python and I used to configure &lt;a href=&quot;https://pypi.org/project/python-lsp-server/&quot;&gt;pylsp&lt;/a&gt; like this
&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;lsp-pylsp-plugins-mypy-enabled t&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;lsp-pylsp-plugins-ruff-enabled t&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;
which I &lt;i&gt;think&lt;/i&gt; translates to this for &lt;code&gt;eglot&lt;/code&gt;
&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-default&lt;/span&gt; eglot-workspace-configuration
              &lt;span class=&quot;org-rainbow-delimiters-depth-2&quot;&gt;(&lt;/span&gt;plist-put eglot-workspace-configuration
                         &lt;span class=&quot;org-builtin&quot;&gt;:pylsp&lt;/span&gt;
                         '&lt;span class=&quot;org-rainbow-delimiters-depth-3&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-builtin&quot;&gt;:plugins&lt;/span&gt; &lt;span class=&quot;org-rainbow-delimiters-depth-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-builtin&quot;&gt;:ruff&lt;/span&gt; &lt;span class=&quot;org-rainbow-delimiters-depth-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-builtin&quot;&gt;:enabled&lt;/span&gt; t&lt;span class=&quot;org-rainbow-delimiters-depth-5&quot;&gt;)&lt;/span&gt;
                                     &lt;span class=&quot;org-builtin&quot;&gt;:mypy&lt;/span&gt; &lt;span class=&quot;org-rainbow-delimiters-depth-5&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;org-builtin&quot;&gt;:enabled&lt;/span&gt; t&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-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;
but I don't know any convenient way of verifying these settings. I'm simply not
familiar enough with the Python tools. I can check the value of
&lt;code&gt;eglot-workspace-configuration&lt;/code&gt; by inspecting it or calling
&lt;code&gt;eglot-show-workspace-configuration&lt;/code&gt; but is there really no way of asking the
language server for its active configuration?
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-org3d20108&quot;&gt;
&lt;h2 id=&quot;org3d20108&quot;&gt;Closing remark&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-org3d20108&quot;&gt;
&lt;p&gt;
The last time I gave up on &lt;code&gt;eglot&lt;/code&gt; very quickly, probably too quickly to be
honest. I made these changes to my configuration over the weekend, so the real
test of &lt;code&gt;eglot&lt;/code&gt; starts when I'm back in the office. I have a feeling I'll stick
to it longer this time.
&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-eglot.html&quot;&gt;eglot&lt;/a&gt; &lt;a href=&quot;https://magnus.therning.org/tag-emacs.html&quot;&gt;emacs&lt;/a&gt; &lt;a href=&quot;https://magnus.therning.org/tag-lsp-mode.html&quot;&gt;lsp-mode&lt;/a&gt; &lt;/div&gt;</description>
	<pubDate>Mon, 19 Jan 2026 07:00:00 +0000</pubDate>
</item>
<item>
	<title>Abhinav Sarkar: Implementing Co, a Small Language With Coroutines #5: Adding Sleep</title>
	<guid isPermaLink="false">https://abhinavsarkar.net/posts/implementing-co-5/</guid>
	<link>https://abhinavsarkar.net/posts/implementing-co-5/?mtm_campaign=feed</link>
	<description>&lt;p&gt;In the &lt;a href=&quot;https://abhinavsarkar.net/posts/implementing-co-4/?mtm_campaign=feed&quot;&gt;previous post&lt;/a&gt;, we added channels to &lt;span class=&quot;fancy&quot;&gt;Co&lt;/span&gt;, the small language we are implementing in this series of posts. In this post, we add the &lt;code&gt;sleep&lt;/code&gt; primitive to it, enabling time-based coroutine scheduling. We then use sleep to build a simulation of digital logic circuits.&lt;/p&gt;
&lt;p&gt;This post was originally published on &lt;a href=&quot;https://abhinavsarkar.net/posts/implementing-co-5/?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;Implementing Co, a Small Language With Coroutines&lt;/strong&gt;.&lt;/p&gt;
  &lt;ol&gt;
    &lt;li&gt;
      
       &lt;a href=&quot;https://abhinavsarkar.net/posts/implementing-co-1/?mtm_campaign=feed&quot;&gt;The Parser&lt;/a&gt; 
    &lt;/li&gt;
    &lt;li&gt;
      
       &lt;a href=&quot;https://abhinavsarkar.net/posts/implementing-co-2/?mtm_campaign=feed&quot;&gt;The Interpreter&lt;/a&gt; 
    &lt;/li&gt;
    &lt;li&gt;
      
       &lt;a href=&quot;https://abhinavsarkar.net/posts/implementing-co-3/?mtm_campaign=feed&quot;&gt;Adding Coroutines&lt;/a&gt; 
    &lt;/li&gt;
    &lt;li&gt;
      
       &lt;a href=&quot;https://abhinavsarkar.net/posts/implementing-co-4/?mtm_campaign=feed&quot;&gt;Adding Channels&lt;/a&gt; 
    &lt;/li&gt;
    &lt;li&gt;
       &lt;strong&gt;Adding Sleep&lt;/strong&gt; ğŸ‘ˆ
      
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/section&gt;

&lt;nav 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#introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#adding-sleep&quot;&gt;Adding Sleep&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#delayed-coroutines&quot;&gt;Delayed Coroutines&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#queuing-coroutines&quot;&gt;Queuing Coroutines&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#implementing-sleep&quot;&gt;Implementing Sleep&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#sleep-in-action&quot;&gt;Sleep in Action&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#sleep-sort&quot;&gt;Sleep Sort&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#javascript-like-timeouts-and-intervals&quot;&gt;JavaScript-like Timeouts and Intervals&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#bonus-round-digital-circuit-simulation&quot;&gt;Bonus Round: Digital Circuit Simulation&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#conjuring-lists&quot;&gt;Conjuring Lists&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#wires&quot;&gt;Wires&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#logic-gates&quot;&gt;Logic Gates&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#adders&quot;&gt;Adders&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#ripple-carry-adder&quot;&gt;Ripple-carry Adder&lt;/a&gt;&lt;/li&gt;&lt;/ol&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;h2 id=&quot;introduction&quot;&gt;Introduction&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#introduction&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Sleep_(system_call)&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Sleep&lt;/a&gt; is a commonly used operation in concurrent programs. It pauses the execution of the current &lt;em&gt;Thread of Computation&lt;/em&gt; (ToC) for a specified duration, after which the &lt;abbr title=&quot;Thread of computation&quot;&gt;ToC&lt;/abbr&gt; is resumed automatically. Sleep is used for various purposes: polling for events, delaying execution of an operation, simulating latency, implementing timeouts, and more.&lt;/p&gt;
&lt;p&gt;Sleep is generally implemented as a primitive operation in most languages, delegating the actual implementation to the underlying operating system. The operating systemâ€™s scheduler removes the &lt;abbr title=&quot;Thread of computation&quot;&gt;ToC&lt;/abbr&gt; from the list of runnable &lt;abbr title=&quot;Threads of computation&quot;&gt;ToCs&lt;/abbr&gt;, places it in a list of sleeping &lt;abbr title=&quot;Threads of computation&quot;&gt;ToCs&lt;/abbr&gt;, and after the specified duration, moves it back to the list of runnable &lt;abbr title=&quot;Threads of computation&quot;&gt;ToCs&lt;/abbr&gt; for scheduling.&lt;/p&gt;
&lt;p&gt;Since &lt;span class=&quot;fancy&quot;&gt;Co&lt;/span&gt; implements its own &lt;abbr title=&quot;Thread of computation&quot;&gt;ToC&lt;/abbr&gt; (coroutine) scheduler, we implement sleep as a primitive operation within the interpreter itself&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;adding-sleep&quot;&gt;Adding Sleep&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#adding-sleep&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We start by exposing &lt;code&gt;sleep&lt;/code&gt; and &lt;code&gt;getCurrentMillis&lt;/code&gt; as built-in functions to &lt;span class=&quot;fancy&quot;&gt;Co&lt;/span&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode numberSource haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb1-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;builtinEnv ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Env&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-2&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb1-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;builtinEnv &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; Map.fromList &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; (&lt;span class=&quot;fu&quot;&gt;traverse&lt;/span&gt; newIORef) [&lt;/span&gt;
&lt;span id=&quot;cb1-3&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb1-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;st&quot;&gt;&quot;print&quot;&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;BuiltinFunction&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;print&quot;&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt; executePrint)&lt;/span&gt;
&lt;span id=&quot;cb1-4&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb1-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  , (&lt;span class=&quot;st&quot;&gt;&quot;newChannel&quot;&lt;/span&gt;,&lt;/span&gt;
&lt;span id=&quot;cb1-5&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb1-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;     &lt;span class=&quot;dt&quot;&gt;BuiltinFunction&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;newChannel&quot;&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;fmap&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Chan&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;const&lt;/span&gt; (newChannel &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb1-6&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb1-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  , (&lt;span class=&quot;st&quot;&gt;&quot;newBufferedChannel&quot;&lt;/span&gt;,&lt;/span&gt;
&lt;span id=&quot;cb1-7&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb1-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;emphasis&quot;&gt;     &lt;span class=&quot;dt&quot;&gt;BuiltinFunction&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;newBufferedChannel&quot;&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt; executeNewBufferedChannel)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-8&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb1-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;emphasis&quot;&gt;  , (&lt;span class=&quot;st&quot;&gt;&quot;sleep&quot;&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;BuiltinFunction&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;sleep&quot;&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt; executeSleep)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-9&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb1-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;emphasis&quot;&gt;  , (&lt;span class=&quot;st&quot;&gt;&quot;getCurrentMillis&quot;&lt;/span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-10&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb1-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;     &lt;span class=&quot;dt&quot;&gt;BuiltinFunction&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;getCurrentMillis&quot;&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; executeGetCurrentMillis)&lt;/span&gt;
&lt;span id=&quot;cb1-11&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb1-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;sleep&lt;/code&gt; built-in function takes one argumentâ€”the duration in milliseconds to sleep for. The &lt;code&gt;getCurrentMillis&lt;/code&gt; function returns the current time in milliseconds since the &lt;a href=&quot;https://en.wikipedia.org/wiki/Unix_epoch&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Unix epoch&lt;/a&gt;. Both of them delegate to the functions explained next.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode numberSource haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb1-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;executeSleep ::&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;Interpreter&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Value&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-2&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb1-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;executeSleep argEs &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; evaluate (&lt;span class=&quot;fu&quot;&gt;head&lt;/span&gt; argEs) &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;cb1-3&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb1-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt; n &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; n &lt;span class=&quot;op&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; sleep n &lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Null&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-4&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb1-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&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; throw &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;Sleep time must be non-negative: &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; n&lt;/span&gt;
&lt;span id=&quot;cb1-5&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb1-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  _ &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; throw &lt;span class=&quot;st&quot;&gt;&quot;sleep call expected a number argument&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-6&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb1-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-7&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb1-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;executeGetCurrentMillis ::&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;Interpreter&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Value&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-8&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb1-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;executeGetCurrentMillis _ &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-9&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb1-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fromIntegral&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;floor&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;1000&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; liftIO getPOSIXTime&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;executeSleep&lt;/code&gt; function evaluates its argument to a number, checks that it is non-negative, and then calls the &lt;code&gt;sleep&lt;/code&gt; function in the &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;Interpreter&lt;/span&gt;&lt;/code&gt; monad. &lt;code&gt;executeGetCurrentMillis&lt;/code&gt; calls &lt;a href=&quot;https://hackage.haskell.org/package/time/docs/Data-Time-Clock-POSIX.html#v:getPOSIXTime&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;&lt;code&gt;getPOSIXTime&lt;/code&gt;&lt;/a&gt; and returns the milliseconds wrapped as a &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;Num&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The implementation of sleep is more involved than other built-in functions because it interacts with the coroutine scheduler. When a coroutine calls &lt;code&gt;sleep&lt;/code&gt;, we want to suspend the coroutine, and schedule it to be resumed after the specified duration. There may be multiple coroutines in the sleep state at a time, and they must be resumed according to their wakeup time (time at which sleep was called + sleep duration), and not in any other order. To be efficient, it is also important that the scheduler does not poll repeatedly for new coroutines to wake up and run, but instead waits till the right time. These are the two requirements for our coroutine scheduler. And the solution is: delayed coroutines.&lt;/p&gt;
&lt;h2 id=&quot;delayed-coroutines&quot;&gt;Delayed Coroutines&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#delayed-coroutines&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://abhinavsarkar.net/posts/implementing-co-3/?mtm_campaign=feed#from-continuations-to-coroutines&quot;&gt;coroutines&lt;/a&gt; we have implemented so far were scheduled to run immediately. To implement sleep, we extend the coroutine concept with &lt;em&gt;Delayed Coroutines&lt;/em&gt;â€”coroutines that are scheduled to run at a specific future time.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode numberSource haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#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;Coroutine&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Coroutine&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-2&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb1-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  {&lt;span class=&quot;ot&quot;&gt; corEnv ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Env&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-3&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb1-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ,&lt;span class=&quot;ot&quot;&gt; corCont ::&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Interpreter&lt;/span&gt; ()&lt;/span&gt;
&lt;span id=&quot;cb1-4&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb1-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;emphasis&quot;&gt;  ,&lt;span class=&quot;ot&quot;&gt; corReady ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MVar&lt;/span&gt; ()&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-5&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#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://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb1-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-7&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb1-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;newCoroutine ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Env&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;Interpreter&lt;/span&gt; ()) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Interpreter&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Coroutine&lt;/span&gt; a)&lt;/span&gt;
&lt;span id=&quot;cb1-8&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb1-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;newCoroutine env cont &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-9&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb1-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ready &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; newMVar ()&lt;/span&gt;
&lt;span id=&quot;cb1-10&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb1-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;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Coroutine&lt;/span&gt; env cont ready&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now the &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;Coroutine&lt;/span&gt;&lt;/code&gt; data type holds an &lt;a href=&quot;https://hackage.haskell.org/package/base/docs/Control-Concurrent-MVar.html#t:MVar&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;MVar&lt;/span&gt;&lt;/code&gt;&lt;/a&gt; to signal when the coroutine is ready to be run. The old-style coroutines that run immediately are created ready to run by the &lt;code&gt;newCoroutine&lt;/code&gt; function. But delayed coroutines are different:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot;&gt;&lt;pre class=&quot;sourceCode numberSource haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&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;ot&quot;&gt;newDelayedCoroutine ::&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;dt&quot;&gt;Integer&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Env&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;Interpreter&lt;/span&gt; ()) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Interpreter&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Coroutine&lt;/span&gt; a)&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;newDelayedCoroutine sleepMillis env cont &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-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;  ready &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; newEmptyMVar&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;  void &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; liftIO &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; forkIO &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;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;    threadDelay &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fromIntegral&lt;/span&gt; sleepMillis &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1000&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;    putMVar ready ()&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;fu&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Coroutine&lt;/span&gt; env cont ready&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The key difference from a regular coroutine is that the &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;MVar&lt;/span&gt;&lt;/code&gt; used for signaling is created empty. We fork a thread&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; that sleeps&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; for the specified sleep duration, and then signals that the coroutine is ready to run by filling the &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;MVar&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;An &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;MVar&lt;/span&gt;&lt;/code&gt; is a synchronization primitive&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;â€”essentially a mutable box that can hold a value or be empty. When we call &lt;code&gt;takeMVar&lt;/code&gt; on an empty &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;MVar&lt;/span&gt;&lt;/code&gt;, it blocks until another thread fills it. This is what makes it powerful for our use case: instead of the interpreter repeatedly polling the queue asking â€œis this coroutine ready yet?â€�, we let the interpreter wait on the &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;MVar&lt;/span&gt;&lt;/code&gt;. The forked thread signals readiness at the right time by filling the &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;MVar&lt;/span&gt;&lt;/code&gt;. The interpreter wakes up immediatelyâ€”no wasted CPU cycles, no busy-waiting.&lt;/p&gt;
&lt;h2 id=&quot;queuing-coroutines&quot;&gt;Queuing Coroutines&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#queuing-coroutines&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We already have a &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;Queue&lt;/span&gt;&lt;/code&gt; of coroutines in our &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;Interpreter&lt;/span&gt;&lt;/code&gt;. It is a &lt;a href=&quot;https://en.wikipedia.org/wiki/min-priority_queue&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;min-priority queue&lt;/a&gt; sorted by timestamps, which we have been using as a &lt;a href=&quot;https://en.wikipedia.org/wiki/FIFO_(computing_and_electronics)&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;FIFO&lt;/a&gt; queue till now. Now we use it for its real purpose: storing delayed coroutines sorted by their wakeup times.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb3&quot;&gt;&lt;pre class=&quot;sourceCode numberSource haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&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;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Queue&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IORef&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PQ.MinPQueue&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TimeSpec&lt;/span&gt; a, &lt;span class=&quot;dt&quot;&gt;TimeSpec&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&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;ot&quot;&gt;newQueue ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MonadBase&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; m &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;Queue&lt;/span&gt; a)&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;newQueue &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;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;  now &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; liftBase currentSystemTime&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;  newIORef (PQ.empty, now)&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&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;ot&quot;&gt;queueSize ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MonadBase&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; m &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Queue&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m &lt;span class=&quot;dt&quot;&gt;Int&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;queueSize &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fmap&lt;/span&gt; (PQ.size &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fst&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; readIORef&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The queue also tracks the maximum wakeup time of all coroutines in the queue. This information is useful for calculating how long the interpreter should sleep before termination.&lt;/p&gt;
&lt;p&gt;The core operations on the queue are:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb4&quot;&gt;&lt;pre class=&quot;sourceCode numberSource haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb4-1&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb4-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;enqueueAt ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TimeSpec&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;Queue&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Interpreter&lt;/span&gt; ()&lt;/span&gt;
&lt;span id=&quot;cb4-2&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb4-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;enqueueAt time val queue &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; atomicModifyIORef' queue &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; \(q, maxWakeupTime) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-3&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb4-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  (( PQ.insert time val q,&lt;/span&gt;
&lt;span id=&quot;cb4-4&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb4-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;     &lt;span class=&quot;kw&quot;&gt;if&lt;/span&gt; time &lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; maxWakeupTime &lt;span class=&quot;kw&quot;&gt;then&lt;/span&gt; time &lt;span class=&quot;kw&quot;&gt;else&lt;/span&gt; maxWakeupTime&lt;/span&gt;
&lt;span id=&quot;cb4-5&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#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;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#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://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb4-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;enqueue ::&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Queue&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Interpreter&lt;/span&gt; ()&lt;/span&gt;
&lt;span id=&quot;cb4-8&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb4-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;enqueue val queue &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-9&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb4-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  now &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; currentSystemTime&lt;/span&gt;
&lt;span id=&quot;cb4-10&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb4-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  enqueueAt now val queue&lt;/span&gt;
&lt;span id=&quot;cb4-11&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb4-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-12&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb4-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;dequeue ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Queue&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Interpreter&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; a)&lt;/span&gt;
&lt;span id=&quot;cb4-13&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb4-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;dequeue queue &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; atomicModifyIORef' queue &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; \(q, maxWakeupTime) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-14&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb4-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;if&lt;/span&gt; PQ.null q&lt;/span&gt;
&lt;span id=&quot;cb4-15&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb4-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;then&lt;/span&gt; ((q, maxWakeupTime), &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb4-16&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb4-16&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;let&lt;/span&gt; ((_, val), q') &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; PQ.deleteFindMin q&lt;/span&gt;
&lt;span id=&quot;cb4-17&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb4-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;         &lt;span class=&quot;kw&quot;&gt;in&lt;/span&gt; ((q', maxWakeupTime), &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; val)&lt;/span&gt;
&lt;span id=&quot;cb4-18&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb4-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-19&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb4-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;currentSystemTime ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MonadIO&lt;/span&gt; m &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; m &lt;span class=&quot;dt&quot;&gt;TimeSpec&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-20&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb4-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;currentSystemTime &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; liftIO &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; getTime &lt;span class=&quot;dt&quot;&gt;Monotonic&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We saw the &lt;code&gt;enqueue&lt;/code&gt; function &lt;a href=&quot;https://abhinavsarkar.net/posts/implementing-co-3/?mtm_campaign=feed#scheduling-coroutines&quot;&gt;earlier&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;enqueueAt&lt;/code&gt; function enqueues the given value at the given time in the queue. The &lt;code&gt;enqueue&lt;/code&gt; function enqueues the value at the current time, thus scheduling it to run immediately.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;dequeue&lt;/code&gt; function dequeues the value with the lowest priority from the queue, which in this case, is the value that is enqueued first.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;currentSystemTime&lt;/code&gt; function returns the monotonically increasing current system time.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The &lt;code&gt;dequeue&lt;/code&gt; function dequeues the coroutine with lowest priority, so if we use the wakeup time as priority, it will dequeue the coroutine that is to be run next. That works!&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;enqueueAt&lt;/code&gt; function calculates and tracks the maximum wakeup times of the coroutines as well. Next, we implement the scheduling of delayed coroutines:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb5&quot;&gt;&lt;pre class=&quot;sourceCode numberSource haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb5-1&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb5-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;scheduleDelayedCoroutine ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TimeSpec&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Coroutine&lt;/span&gt; () &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Interpreter&lt;/span&gt; ()&lt;/span&gt;
&lt;span id=&quot;cb5-2&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb5-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;scheduleDelayedCoroutine wakeupTime coroutine &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;cb5-3&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb5-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  State.gets isCoroutines &lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; enqueueAt wakeupTime coroutine&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;scheduleDelayedCoroutine&lt;/code&gt; function enqueues a coroutine in the interpreter coroutine queue with the specified wakeup time. We also improve the &lt;code&gt;runNextCoroutine&lt;/code&gt; function to wait for the coroutine to be ready before running it.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode numberSource haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb1-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;runNextCoroutine ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Interpreter&lt;/span&gt; ()&lt;/span&gt;
&lt;span id=&quot;cb1-2&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb1-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;runNextCoroutine &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-3&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb1-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  State.gets isCoroutines &lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; dequeue &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;cb1-4&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb1-4&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; throwError &lt;span class=&quot;dt&quot;&gt;CoroutineQueueEmpty&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-5&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb1-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;dt&quot;&gt;Coroutine&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; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-6&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb1-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;emphasis&quot;&gt;      void &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; takeMVar corReady&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-7&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb1-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      setEnv corEnv&lt;/span&gt;
&lt;span id=&quot;cb1-8&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb1-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      corCont ()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;takeMVar&lt;/code&gt; function call blocks till the thread that was forked when creating the coroutine wakes up and fills the &lt;code&gt;corReady&lt;/code&gt; &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;MVar&lt;/span&gt;&lt;/code&gt;. So we donâ€™t have to poll the queue.&lt;/p&gt;
&lt;p&gt;Thatâ€™s all we have to do for having delayed coroutines.&lt;/p&gt;
&lt;h2 id=&quot;implementing-sleep&quot;&gt;Implementing Sleep&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#implementing-sleep&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With the infrastructure in place, the &lt;code&gt;sleep&lt;/code&gt; function becomes straightforward:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb6&quot;&gt;&lt;pre class=&quot;sourceCode numberSource haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb6-1&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb6-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;sleep ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Integer&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Interpreter&lt;/span&gt; ()&lt;/span&gt;
&lt;span id=&quot;cb6-2&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb6-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sleep millis &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://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb6-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  now &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; currentSystemTime&lt;/span&gt;
&lt;span id=&quot;cb6-4&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb6-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt; wakeupTime &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; now &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; fromNanoSecs (&lt;span class=&quot;fu&quot;&gt;fromIntegral&lt;/span&gt; millis &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1000000&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb6-5&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb6-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  env &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; State.gets isEnv&lt;/span&gt;
&lt;span id=&quot;cb6-6&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb6-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  callCC &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; \cont &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;cb6-7&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb6-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    coroutine &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; newDelayedCoroutine millis env cont&lt;/span&gt;
&lt;span id=&quot;cb6-8&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb6-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    scheduleDelayedCoroutine wakeupTime coroutine&lt;/span&gt;
&lt;span id=&quot;cb6-9&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb6-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    runNextCoroutine&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When a coroutine calls &lt;code&gt;sleep&lt;/code&gt;, we capture the current environment and use &lt;code&gt;callCC&lt;/code&gt; to capture the continuationâ€”the code that should run after the sleep completes. We then create a new delayed coroutine with this continuation, schedule it for the future, and run the next coroutine in the queue. The scheduler machinery takes care of running the delayed coroutine at the right time.&lt;/p&gt;
&lt;p&gt;We also modify the &lt;code&gt;awaitTermination&lt;/code&gt; function from the previous post to handle delayed coroutines. It now sleeps till the last wakeup time before checking if the queue is empty:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb7&quot;&gt;&lt;pre class=&quot;sourceCode numberSource haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&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;ot&quot;&gt;awaitTermination ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Interpreter&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;awaitTermination &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;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;  (coroutines, maxWakeupTime) &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; readIORef &lt;span class=&quot;op&quot;&gt;=&amp;lt;&amp;lt;&lt;/span&gt; State.gets isCoroutines&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;  dur &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; calcSleepDuration maxWakeupTime&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;  unless (PQ.null coroutines) &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;if&lt;/span&gt; dur &lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&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;kw&quot;&gt;then&lt;/span&gt; sleep dur &lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; awaitTermination&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;kw&quot;&gt;else&lt;/span&gt; yield &lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; awaitTermination&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Notice how we use the &lt;code&gt;sleep&lt;/code&gt; function we just defined in &lt;code&gt;awaitTermination&lt;/code&gt;. The &lt;code&gt;calcSleepDuration&lt;/code&gt; function calculates how long to sleep before the last coroutine becomes ready:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb8&quot;&gt;&lt;pre class=&quot;sourceCode numberSource haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&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;ot&quot;&gt;calcSleepDuration ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TimeSpec&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Interpreter&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Integer&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;calcSleepDuration maxWakeupTime &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;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;  now &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; currentSystemTime&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;fu&quot;&gt;return&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;fromIntegral&lt;/span&gt; (maxWakeupTime &lt;span class=&quot;op&quot;&gt;-&lt;/span&gt; now) &lt;span class=&quot;ot&quot;&gt;`div`&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1000000&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Thatâ€™s all for sleeping. This may be too much to take in, so letâ€™s go through some examples.&lt;/p&gt;
&lt;h2 id=&quot;sleep-in-action&quot;&gt;Sleep in Action&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#sleep-in-action&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Sleep can be used for polling/waiting for events, delaying execution, simulating latency, implementing timeouts, and more. Letâ€™s see some simple uses.&lt;/p&gt;
&lt;h3 id=&quot;sleep-sort&quot;&gt;Sleep Sort&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#sleep-sort&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;An interesting example of sleep is the infamous &lt;a href=&quot;https://www.geeksforgeeks.org/dsa/sleep-sort-king-laziness-sorting-sleeping/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;sleep sort&lt;/a&gt;, which sorts a list of numbers by spawning a coroutine for each number that sleeps for the duration of that number, then prints it:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb9&quot;&gt;&lt;pre class=&quot;sourceCode javascript numberSource&quot;&gt;&lt;code class=&quot;sourceCode javascript&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;kw&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;sleepSort&lt;/span&gt;(a&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; c&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; d&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; e) {&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;kw&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;printNum&lt;/span&gt;(num) {&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 class=&quot;fu&quot;&gt;sleep&lt;/span&gt;(num)&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://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb9-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;print&lt;/span&gt;(num)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&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&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;  spawn &lt;span class=&quot;fu&quot;&gt;printNum&lt;/span&gt;(a)&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;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb9-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  spawn &lt;span class=&quot;fu&quot;&gt;printNum&lt;/span&gt;(b)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-8&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb9-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  spawn &lt;span class=&quot;fu&quot;&gt;printNum&lt;/span&gt;(c)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-9&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb9-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  spawn &lt;span class=&quot;fu&quot;&gt;printNum&lt;/span&gt;(d)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-10&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb9-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  spawn &lt;span class=&quot;fu&quot;&gt;printNum&lt;/span&gt;(e)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-11&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb9-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;}&lt;/span&gt;
&lt;span id=&quot;cb9-12&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb9-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-13&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb9-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;sleepSort&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;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 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&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Running this program prints what we expect:&lt;/p&gt;
&lt;pre class=&quot;plain&quot;&gt;&lt;code&gt;1
2
3
4
5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Donâ€™t use &lt;code&gt;sleepSort&lt;/code&gt; for sorting your numbers though. Moving on.&lt;/p&gt;
&lt;h3 id=&quot;javascript-like-timeouts-and-intervals&quot;&gt;JavaScript-like Timeouts and Intervals&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#javascript-like-timeouts-and-intervals&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;With sleep, we can implement JavaScript-like &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Window/setTimeout&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;&lt;code&gt;setTimeout&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Window/setInterval&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;&lt;code&gt;setInterval&lt;/code&gt;&lt;/a&gt; functions:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb11&quot;&gt;&lt;pre class=&quot;sourceCode javascript numberSource&quot;&gt;&lt;code class=&quot;sourceCode javascript&quot;&gt;&lt;span id=&quot;cb11-1&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb11-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;setTimeout&lt;/span&gt;(callback&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; millis) {&lt;/span&gt;
&lt;span id=&quot;cb11-2&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb11-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;spawn&lt;/span&gt; (&lt;span class=&quot;kw&quot;&gt;function&lt;/span&gt; () { &lt;span class=&quot;fu&quot;&gt;sleep&lt;/span&gt;(millis)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;callback&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;cb11-3&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb11-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;}&lt;/span&gt;
&lt;span id=&quot;cb11-4&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb11-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-5&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb11-5&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;hello&lt;/span&gt;() {&lt;/span&gt;
&lt;span id=&quot;cb11-6&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb11-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;print&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&gt;
&lt;span id=&quot;cb11-7&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb11-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;}&lt;/span&gt;
&lt;span id=&quot;cb11-8&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb11-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-9&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb11-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;pp&quot;&gt;setTimeout&lt;/span&gt;(hello&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;10000&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;The &lt;code&gt;setTimeout&lt;/code&gt; function spawns a coroutine that sleeps for the specified duration and then calls the callback function.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb12&quot;&gt;&lt;pre class=&quot;sourceCode javascript numberSource&quot;&gt;&lt;code class=&quot;sourceCode javascript&quot;&gt;&lt;span id=&quot;cb12-1&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb12-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;setInterval&lt;/span&gt;(callback&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; seconds) {&lt;/span&gt;
&lt;span id=&quot;cb12-2&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb12-2&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;run&lt;/span&gt;() {&lt;/span&gt;
&lt;span id=&quot;cb12-3&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb12-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;callback&lt;/span&gt;()&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-4&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb12-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;pp&quot;&gt;setTimeout&lt;/span&gt;(run&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; seconds)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-5&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb12-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  }&lt;/span&gt;
&lt;span id=&quot;cb12-6&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb12-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;pp&quot;&gt;setTimeout&lt;/span&gt;(run&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; seconds)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-7&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb12-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;}&lt;/span&gt;
&lt;span id=&quot;cb12-8&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#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://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb12-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;var&lt;/span&gt; start &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;getCurrentMillis&lt;/span&gt;()&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-10&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb12-10&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;tick&lt;/span&gt;(t) {&lt;/span&gt;
&lt;span id=&quot;cb12-11&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb12-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;var&lt;/span&gt; now &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;getCurrentMillis&lt;/span&gt;()&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-12&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb12-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;print&lt;/span&gt;(t &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; (now &lt;span class=&quot;op&quot;&gt;-&lt;/span&gt; start))&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-13&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#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;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb12-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-15&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb12-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;pp&quot;&gt;setInterval&lt;/span&gt;(&lt;span class=&quot;kw&quot;&gt;function&lt;/span&gt; () { &lt;span class=&quot;fu&quot;&gt;tick&lt;/span&gt;(&lt;span class=&quot;st&quot;&gt;&quot;tick&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;dv&quot;&gt;2000&lt;/span&gt;)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-16&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb12-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;sleep&lt;/span&gt;(&lt;span class=&quot;dv&quot;&gt;1000&lt;/span&gt;)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-17&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb12-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;pp&quot;&gt;setInterval&lt;/span&gt;(&lt;span class=&quot;kw&quot;&gt;function&lt;/span&gt; () { &lt;span class=&quot;fu&quot;&gt;tick&lt;/span&gt;(&lt;span class=&quot;st&quot;&gt;&quot;tock&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;dv&quot;&gt;2000&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;The &lt;code&gt;setInterval&lt;/code&gt; function repeatedly calls a callback at a fixed interval using &lt;code&gt;setTimeout&lt;/code&gt; to reschedule itself. Running the above code prints alternating &lt;code&gt;tick&lt;/code&gt; and &lt;code&gt;tock&lt;/code&gt; every 1 second, forever:&lt;/p&gt;
&lt;pre class=&quot;plain&quot;&gt;&lt;code&gt;tick 2005
tock 3008
tick 4009
tock 5009
tick 6015
tock 7013
tick 8017
tock 9019
tick 10020
tock 11021
tick 12021&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice that the scheduling is not accurate up to milliseconds, but only approximate.&lt;/p&gt;
&lt;h2 id=&quot;bonus-round-digital-circuit-simulation&quot;&gt;Bonus Round: Digital Circuit Simulation&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#bonus-round-digital-circuit-simulation&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As a more complex example of using sleep, we implement a simulator for digital logic circuits, from basic &lt;em&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Logic_gates&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Logic gates&lt;/a&gt;&lt;/em&gt; to a &lt;em&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Ripple_carry_adder&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Ripple carry adder&lt;/a&gt;&lt;/em&gt;. The idea is to model circuits as a network of wires and gates, where the wires carry digital signal values (&lt;code&gt;0&lt;/code&gt; or &lt;code&gt;1&lt;/code&gt;), and the logic gates transform input signals to output signals with a propagation delay.&lt;/p&gt;
&lt;p&gt;The digital circuit simulation example is from the &lt;a href=&quot;https://mitp-content-server.mit.edu/books/content/sectbyfn/books_pres_0/6515/sicp.zip/full-text/book/book-Z-H-22.html#%_sec_3.3.4&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Wizard Book&lt;/a&gt;. Quoting an example:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;An inverter is a primitive function box [logic gate] that inverts its input. If the input signal to an inverter changes to 0, then one inverter-delay later the inverter will change its output signal to 1. If the input signal to an inverter changes to 1, then one inverter-delay later the inverter will change its output signal to 0.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But first, weâ€™ll need to make some lists.&lt;/p&gt;
&lt;h3 id=&quot;conjuring-lists&quot;&gt;Conjuring Lists&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#conjuring-lists&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We implement a simple cons list (a singly linked list) using &lt;a href=&quot;https://web.archive.org/web/20260116/https://mitp-content-server.mit.edu/books/content/sectbyfn/books_pres_0/6515/sicp.zip/full-text/book/book-Z-H-14.html#%25_sec_2.1.3&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot; title=&quot;Structure and Interpretation of Computer Programs: 2.1.3 What Is Meant by Data?&quot;&gt;a trick from the Wizard book&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb14&quot;&gt;&lt;pre class=&quot;sourceCode javascript numberSource&quot;&gt;&lt;code class=&quot;sourceCode javascript&quot;&gt;&lt;span id=&quot;cb14-1&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb14-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;Cons&lt;/span&gt;(first&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; rest) {&lt;/span&gt;
&lt;span id=&quot;cb14-2&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb14-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;function&lt;/span&gt; (command) {&lt;/span&gt;
&lt;span id=&quot;cb14-3&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb14-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;cf&quot;&gt;if&lt;/span&gt; (command &lt;span class=&quot;op&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;first&quot;&lt;/span&gt;) { &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; first&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt; }&lt;/span&gt;
&lt;span id=&quot;cb14-4&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb14-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;cf&quot;&gt;if&lt;/span&gt; (command &lt;span class=&quot;op&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;rest&quot;&lt;/span&gt;) { &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; rest&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt; }&lt;/span&gt;
&lt;span id=&quot;cb14-5&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb14-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;cb14-6&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#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://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb14-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-8&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb14-8&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;Empty&lt;/span&gt;() { &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;}&lt;/span&gt;
&lt;span id=&quot;cb14-9&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#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://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb14-10&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;first&lt;/span&gt;(list) { &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;list&lt;/span&gt;(&lt;span class=&quot;st&quot;&gt;&quot;first&quot;&lt;/span&gt;)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt; }&lt;/span&gt;
&lt;span id=&quot;cb14-11&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb14-11&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;rest&lt;/span&gt;(list) { &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;list&lt;/span&gt;(&lt;span class=&quot;st&quot;&gt;&quot;rest&quot;&lt;/span&gt;)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt; }&lt;/span&gt;
&lt;span id=&quot;cb14-12&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb14-12&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;prepend&lt;/span&gt;(list&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; element) { &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;Cons&lt;/span&gt;(element&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; list)&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;&lt;code class=&quot;co&quot;&gt;Empty&lt;/code&gt; creates an empty list, and we grow the list by prepending an element to it by calling the &lt;code&gt;prepend&lt;/code&gt; function. &lt;code&gt;first&lt;/code&gt; returns the first element of a list, and &lt;code&gt;rest&lt;/code&gt; returns the rest of them. Notice that a &lt;code&gt;Cons&lt;/code&gt; cell is just a closure that holds references to its first and rest parameters, and returns a selector function to retrieve them.&lt;/p&gt;
&lt;p&gt;Next, we define a helper function to call a list of actions, yielding after each one:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb15&quot;&gt;&lt;pre class=&quot;sourceCode javascript numberSource&quot;&gt;&lt;code class=&quot;sourceCode javascript&quot;&gt;&lt;span id=&quot;cb15-1&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb15-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;callEach&lt;/span&gt;(actions) {&lt;/span&gt;
&lt;span id=&quot;cb15-2&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb15-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;cf&quot;&gt;if&lt;/span&gt; (actions &lt;span class=&quot;op&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;Empty&lt;/span&gt;()) {&lt;/span&gt;
&lt;span id=&quot;cb15-3&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb15-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;callEach&lt;/span&gt;(&lt;span class=&quot;fu&quot;&gt;rest&lt;/span&gt;(actions))&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb15-4&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb15-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;first&lt;/span&gt;(actions)()&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb15-5&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb15-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb15-6&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb15-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  }&lt;/span&gt;
&lt;span id=&quot;cb15-7&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb15-7&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;wires&quot;&gt;Wires&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#wires&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A wire holds a mutable signal value and a list of actions to call when the signal changes:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb16&quot;&gt;&lt;pre class=&quot;sourceCode javascript numberSource&quot;&gt;&lt;code class=&quot;sourceCode javascript&quot;&gt;&lt;span id=&quot;cb16-1&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb16-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;Wire&lt;/span&gt;() {&lt;/span&gt;
&lt;span id=&quot;cb16-2&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb16-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;var&lt;/span&gt; signalValue &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&gt;
&lt;span id=&quot;cb16-3&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb16-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;var&lt;/span&gt; actions &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;Empty&lt;/span&gt;()&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-4&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb16-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-5&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb16-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;function&lt;/span&gt; (command) {&lt;/span&gt;
&lt;span id=&quot;cb16-6&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb16-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;cf&quot;&gt;if&lt;/span&gt; (command &lt;span class=&quot;op&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;get-signal&quot;&lt;/span&gt;) {&lt;/span&gt;
&lt;span id=&quot;cb16-7&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb16-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; signalValue&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-8&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb16-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id=&quot;cb16-9&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb16-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;cf&quot;&gt;if&lt;/span&gt; (command &lt;span class=&quot;op&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;set-signal&quot;&lt;/span&gt;) {&lt;/span&gt;
&lt;span id=&quot;cb16-10&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb16-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;function&lt;/span&gt; (newValue) {&lt;/span&gt;
&lt;span id=&quot;cb16-11&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb16-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;cf&quot;&gt;if&lt;/span&gt; (signalValue &lt;span class=&quot;op&quot;&gt;!=&lt;/span&gt; newValue) {&lt;/span&gt;
&lt;span id=&quot;cb16-12&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb16-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          signalValue &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; newValue&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-13&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb16-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;fu&quot;&gt;callEach&lt;/span&gt;(actions)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-14&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb16-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        }&lt;/span&gt;
&lt;span id=&quot;cb16-15&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb16-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;cb16-16&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb16-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id=&quot;cb16-17&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb16-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;cf&quot;&gt;if&lt;/span&gt; (command &lt;span class=&quot;op&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;add-action&quot;&lt;/span&gt;) {&lt;/span&gt;
&lt;span id=&quot;cb16-18&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb16-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;function&lt;/span&gt; (action) {&lt;/span&gt;
&lt;span id=&quot;cb16-19&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb16-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        actions &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;prepend&lt;/span&gt;(actions&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; action)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-20&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb16-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;fu&quot;&gt;action&lt;/span&gt;()&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-21&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb16-21&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;cb16-22&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb16-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id=&quot;cb16-23&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb16-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-24&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb16-24&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;cb16-25&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb16-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;}&lt;/span&gt;
&lt;span id=&quot;cb16-26&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb16-26&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-27&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb16-27&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;getSignal&lt;/span&gt;(wire) { &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;wire&lt;/span&gt;(&lt;span class=&quot;st&quot;&gt;&quot;get-signal&quot;&lt;/span&gt;)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt; }&lt;/span&gt;
&lt;span id=&quot;cb16-28&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb16-28&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;setSignal&lt;/span&gt;(wire&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; signal) { &lt;span class=&quot;fu&quot;&gt;wire&lt;/span&gt;(&lt;span class=&quot;st&quot;&gt;&quot;set-signal&quot;&lt;/span&gt;)(signal)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt; }&lt;/span&gt;
&lt;span id=&quot;cb16-29&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb16-29&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;addAction&lt;/span&gt;(wire&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; action) { &lt;span class=&quot;fu&quot;&gt;wire&lt;/span&gt;(&lt;span class=&quot;st&quot;&gt;&quot;add-action&quot;&lt;/span&gt;)(action)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt; }&lt;/span&gt;
&lt;span id=&quot;cb16-30&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb16-30&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-31&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb16-31&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;connect&lt;/span&gt;(a&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; b) {&lt;/span&gt;
&lt;span id=&quot;cb16-32&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb16-32&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;propagate&lt;/span&gt;() {&lt;/span&gt;
&lt;span id=&quot;cb16-33&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb16-33&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;setSignal&lt;/span&gt;(b&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;getSignal&lt;/span&gt;(a))&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-34&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb16-34&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  }&lt;/span&gt;
&lt;span id=&quot;cb16-35&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb16-35&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;addAction&lt;/span&gt;(a&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; propagate)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-36&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb16-36&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A wire provides three operations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;get-signal&lt;/code&gt;: returns the current signal value.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;set-signal&lt;/code&gt;: sets a new signal value and calls all actions if the value changed.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;add-action&lt;/code&gt;: adds an action to be called when the signal changes, and calls it immediately.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;connect&lt;/code&gt; function connects two wires, causing the signal from one to propagate to another.&lt;/p&gt;
&lt;h3 id=&quot;logic-gates&quot;&gt;Logic Gates&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#logic-gates&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;First, we define the basic logic operations:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb17&quot;&gt;&lt;pre class=&quot;sourceCode javascript numberSource&quot;&gt;&lt;code class=&quot;sourceCode javascript&quot;&gt;&lt;span id=&quot;cb17-1&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb17-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;and&lt;/span&gt;(a&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; b) {&lt;/span&gt;
&lt;span id=&quot;cb17-2&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb17-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;cf&quot;&gt;if&lt;/span&gt; (a &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;cf&quot;&gt;if&lt;/span&gt; (b &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;cf&quot;&gt;return&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;cb17-3&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb17-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;dv&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-4&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb17-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;}&lt;/span&gt;
&lt;span id=&quot;cb17-5&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb17-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-6&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb17-6&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;or&lt;/span&gt;(a&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; b) {&lt;/span&gt;
&lt;span id=&quot;cb17-7&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb17-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;cf&quot;&gt;if&lt;/span&gt; (a &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;cf&quot;&gt;return&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;cb17-8&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb17-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;cf&quot;&gt;if&lt;/span&gt; (b &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;cf&quot;&gt;return&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;cb17-9&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb17-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;cf&quot;&gt;return&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;cb17-10&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb17-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;}&lt;/span&gt;
&lt;span id=&quot;cb17-11&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb17-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-12&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb17-12&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;not&lt;/span&gt;(a) {&lt;/span&gt;
&lt;span id=&quot;cb17-13&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb17-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;cf&quot;&gt;if&lt;/span&gt; (a &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;cf&quot;&gt;return&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;cb17-14&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb17-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;cf&quot;&gt;return&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;cb17-15&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb17-15&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 a utility function to schedule a function to run after a delay:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb18&quot;&gt;&lt;pre class=&quot;sourceCode javascript numberSource&quot;&gt;&lt;code class=&quot;sourceCode javascript&quot;&gt;&lt;span id=&quot;cb18-1&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb18-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;runAfter&lt;/span&gt;(millis&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; func) {&lt;/span&gt;
&lt;span id=&quot;cb18-2&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb18-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;spawn&lt;/span&gt; (&lt;span class=&quot;kw&quot;&gt;function&lt;/span&gt; () {&lt;/span&gt;
&lt;span id=&quot;cb18-3&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb18-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;sleep&lt;/span&gt;(millis)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb18-4&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb18-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;func&lt;/span&gt;()&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb18-5&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb18-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;cb18-6&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb18-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;With these building blocks, we define the logic gates. Each gate computes its output based on its inputs and schedules the output update after a propagation delay specific to the gate:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb19&quot;&gt;&lt;pre class=&quot;sourceCode javascript numberSource&quot;&gt;&lt;code class=&quot;sourceCode javascript&quot;&gt;&lt;span id=&quot;cb19-1&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb19-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;var&lt;/span&gt; andGateDelay &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-2&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#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;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb19-3&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;AndGate&lt;/span&gt;(a&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; out) {&lt;/span&gt;
&lt;span id=&quot;cb19-4&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb19-4&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;compute&lt;/span&gt;() {&lt;/span&gt;
&lt;span id=&quot;cb19-5&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb19-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;var&lt;/span&gt; newSignal &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;and&lt;/span&gt;(&lt;span class=&quot;fu&quot;&gt;getSignal&lt;/span&gt;(a)&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;getSignal&lt;/span&gt;(b))&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-6&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb19-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;runAfter&lt;/span&gt;(andGateDelay&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;function&lt;/span&gt; () { &lt;span class=&quot;fu&quot;&gt;setSignal&lt;/span&gt;(out&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; newSignal)&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;cb19-7&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb19-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  }&lt;/span&gt;
&lt;span id=&quot;cb19-8&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb19-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;addAction&lt;/span&gt;(a&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; compute)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-9&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb19-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;addAction&lt;/span&gt;(b&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; compute)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-10&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb19-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;}&lt;/span&gt;
&lt;span id=&quot;cb19-11&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb19-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-12&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb19-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;var&lt;/span&gt; orGateDelay &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-13&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#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://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb19-14&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;OrGate&lt;/span&gt;(a&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; out) {&lt;/span&gt;
&lt;span id=&quot;cb19-15&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb19-15&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;compute&lt;/span&gt;() {&lt;/span&gt;
&lt;span id=&quot;cb19-16&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb19-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;var&lt;/span&gt; newSignal &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;or&lt;/span&gt;(&lt;span class=&quot;fu&quot;&gt;getSignal&lt;/span&gt;(a)&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;getSignal&lt;/span&gt;(b))&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-17&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb19-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;runAfter&lt;/span&gt;(orGateDelay&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;function&lt;/span&gt; () { &lt;span class=&quot;fu&quot;&gt;setSignal&lt;/span&gt;(out&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; newSignal)&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;cb19-18&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb19-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  }&lt;/span&gt;
&lt;span id=&quot;cb19-19&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb19-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;addAction&lt;/span&gt;(a&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; compute)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-20&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb19-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;addAction&lt;/span&gt;(b&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; compute)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-21&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#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://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb19-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-23&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb19-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;var&lt;/span&gt; notGateDelay &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-24&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb19-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-25&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb19-25&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;NotGate&lt;/span&gt;(a&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; out) {&lt;/span&gt;
&lt;span id=&quot;cb19-26&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb19-26&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;compute&lt;/span&gt;() {&lt;/span&gt;
&lt;span id=&quot;cb19-27&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb19-27&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;var&lt;/span&gt; newSignal &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;not&lt;/span&gt;(&lt;span class=&quot;fu&quot;&gt;getSignal&lt;/span&gt;(a))&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-28&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb19-28&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;runAfter&lt;/span&gt;(notGateDelay&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;function&lt;/span&gt; () { &lt;span class=&quot;fu&quot;&gt;setSignal&lt;/span&gt;(out&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; newSignal)&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;cb19-29&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb19-29&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  }&lt;/span&gt;
&lt;span id=&quot;cb19-30&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb19-30&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;addAction&lt;/span&gt;(a&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; compute)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-31&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb19-31&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We add the &lt;code&gt;compute&lt;/code&gt; action to each input wire, which runs when the input signals change, and sets the signal on the output wire after a delay.&lt;/p&gt;
&lt;p&gt;Letâ€™s test an And gate:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb20&quot;&gt;&lt;pre class=&quot;sourceCode javascript numberSource&quot;&gt;&lt;code class=&quot;sourceCode javascript&quot;&gt;&lt;span id=&quot;cb20-1&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb20-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;var&lt;/span&gt; input1 &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;Wire&lt;/span&gt;()&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-2&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb20-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;var&lt;/span&gt; input2 &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;Wire&lt;/span&gt;()&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-3&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb20-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;var&lt;/span&gt; output &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;Wire&lt;/span&gt;()&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-4&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb20-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-5&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb20-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;log&lt;/span&gt;(&lt;span class=&quot;st&quot;&gt;&quot;&amp;gt;&amp;gt; Setting up the probes&quot;&lt;/span&gt;)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-6&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb20-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;addProbe&lt;/span&gt;(&lt;span class=&quot;st&quot;&gt;&quot;input1&quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; input1)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-7&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb20-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;addProbe&lt;/span&gt;(&lt;span class=&quot;st&quot;&gt;&quot;input2&quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; input2)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-8&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb20-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;addProbe&lt;/span&gt;(&lt;span class=&quot;st&quot;&gt;&quot;output&quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; output)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-9&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#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://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb20-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;log&lt;/span&gt;(&lt;span class=&quot;st&quot;&gt;&quot;&amp;gt;&amp;gt; Setting up the And gate&quot;&lt;/span&gt;)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-11&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb20-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;AndGate&lt;/span&gt;(input1&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; input2&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; output)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-12&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb20-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-13&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb20-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;log&lt;/span&gt;(&lt;span class=&quot;st&quot;&gt;&quot;&amp;gt;&amp;gt; Setting input1 to 1&quot;&lt;/span&gt;)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-14&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb20-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;setSignal&lt;/span&gt;(input1&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&gt;
&lt;span id=&quot;cb20-15&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb20-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-16&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb20-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;sleep&lt;/span&gt;(&lt;span class=&quot;dv&quot;&gt;1000&lt;/span&gt;)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-17&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb20-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-18&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb20-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;log&lt;/span&gt;(&lt;span class=&quot;st&quot;&gt;&quot;&amp;gt;&amp;gt; Setting input2 to 1&quot;&lt;/span&gt;)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-19&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb20-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;setSignal&lt;/span&gt;(input2&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&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For probing, we define a helper that logs signal changes with milliseconds elapsed since start of the run:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb21&quot;&gt;&lt;pre class=&quot;sourceCode javascript numberSource&quot;&gt;&lt;code class=&quot;sourceCode javascript&quot;&gt;&lt;span id=&quot;cb21-1&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb21-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;var&lt;/span&gt; start &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;getCurrentMillis&lt;/span&gt;()&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-2&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#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;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb21-3&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;log&lt;/span&gt;(msg) {&lt;/span&gt;
&lt;span id=&quot;cb21-4&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb21-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;print&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;fu&quot;&gt;getCurrentMillis&lt;/span&gt;() &lt;span class=&quot;op&quot;&gt;-&lt;/span&gt; start) &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; msg)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-5&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb21-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;}&lt;/span&gt;
&lt;span id=&quot;cb21-6&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#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;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb21-7&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;addProbe&lt;/span&gt;(label&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; wire) {&lt;/span&gt;
&lt;span id=&quot;cb21-8&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb21-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;addAction&lt;/span&gt;(wire&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;function&lt;/span&gt; () {&lt;/span&gt;
&lt;span id=&quot;cb21-9&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb21-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;log&lt;/span&gt;(label &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;fu&quot;&gt;getSignal&lt;/span&gt;(wire))&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-10&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb21-10&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;cb21-11&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb21-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The output:&lt;/p&gt;
&lt;pre class=&quot;plain&quot;&gt;&lt;code&gt;[0] &amp;gt;&amp;gt; Setting up the probes
[0] input1: 0
[0] input2: 0
[0] output: 0
[0] &amp;gt;&amp;gt; Setting up the And gate
[0] &amp;gt;&amp;gt; Setting input1 to 1
[0] input1: 1
[1005] &amp;gt;&amp;gt; Setting input2 to 1
[1006] input2: 1
[1310] output: 1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It works as expected. You can notice the sleep and the And gate delay in action.&lt;/p&gt;
&lt;h3 id=&quot;adders&quot;&gt;Adders&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#adders&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Using the basic logic gates, next we build adders. A &lt;a href=&quot;https://en.wikipedia.org/wiki/Half_adder&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Half adder&lt;/a&gt; is a digital circuit that adds two bits:&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Half Adder&quot; class=&quot;lazyload w-100pct nolink mw-60pct&quot; /&gt;
&amp;lt;noscript&amp;gt;&lt;img alt=&quot;Half Adder&quot; class=&quot;w-100pct nolink mw-60pct&quot; src=&quot;https://abhinavsarkar.net/images/implementing-co-5/half-adder.svg&quot; /&gt;&amp;lt;/noscript&amp;gt;
&lt;figcaption&gt;Half Adder&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;It has two input signals/bits &lt;code&gt;Input1&lt;/code&gt; and &lt;code&gt;Input2&lt;/code&gt;, and two output bits &lt;code&gt;Sum&lt;/code&gt; and &lt;code&gt;Carry&lt;/code&gt;. We simply connect the And, Or and Not gates with input, output and intermediate wires in our code as shown in the diagram:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb23&quot;&gt;&lt;pre class=&quot;sourceCode javascript numberSource&quot;&gt;&lt;code class=&quot;sourceCode javascript&quot;&gt;&lt;span id=&quot;cb23-1&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb23-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;HalfAdder&lt;/span&gt;(label&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; input1&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; input2&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; sum&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; carry) {&lt;/span&gt;
&lt;span id=&quot;cb23-2&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb23-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;var&lt;/span&gt; a &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;Wire&lt;/span&gt;()&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb23-3&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb23-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;var&lt;/span&gt; b &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;Wire&lt;/span&gt;()&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb23-4&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb23-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;addProbe&lt;/span&gt;(label &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;-a&quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; a)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb23-5&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb23-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;addProbe&lt;/span&gt;(label &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;-b&quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; b)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb23-6&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#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;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb23-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;OrGate&lt;/span&gt;(input1&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; input2&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; a)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb23-8&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb23-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;AndGate&lt;/span&gt;(input1&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; input2&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; carry)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb23-9&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb23-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;NotGate&lt;/span&gt;(carry&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; b)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb23-10&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb23-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;AndGate&lt;/span&gt;(a&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; sum)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb23-11&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb23-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Nice and simple. Letâ€™s test it:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb24&quot;&gt;&lt;pre class=&quot;sourceCode javascript numberSource&quot;&gt;&lt;code class=&quot;sourceCode javascript&quot;&gt;&lt;span id=&quot;cb24-1&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb24-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;var&lt;/span&gt; input1 &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;Wire&lt;/span&gt;()&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-2&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb24-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;var&lt;/span&gt; input2 &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;Wire&lt;/span&gt;()&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-3&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb24-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;var&lt;/span&gt; sum &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;Wire&lt;/span&gt;()&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-4&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb24-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;var&lt;/span&gt; carry &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;Wire&lt;/span&gt;()&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-5&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb24-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-6&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb24-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;log&lt;/span&gt;(&lt;span class=&quot;st&quot;&gt;&quot;&amp;gt;&amp;gt; Setting up the probes&quot;&lt;/span&gt;)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-7&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb24-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;addProbe&lt;/span&gt;(&lt;span class=&quot;st&quot;&gt;&quot;input1&quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; input1)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-8&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb24-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;addProbe&lt;/span&gt;(&lt;span class=&quot;st&quot;&gt;&quot;input2&quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; input2)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-9&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb24-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;addProbe&lt;/span&gt;(&lt;span class=&quot;st&quot;&gt;&quot;sum&quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; sum)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-10&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb24-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;addProbe&lt;/span&gt;(&lt;span class=&quot;st&quot;&gt;&quot;carry&quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; carry)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-11&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb24-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-12&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb24-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;log&lt;/span&gt;(&lt;span class=&quot;st&quot;&gt;&quot;&amp;gt;&amp;gt; Setting up the half-adder&quot;&lt;/span&gt;)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-13&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb24-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;HalfAdder&lt;/span&gt;(&lt;span class=&quot;st&quot;&gt;&quot;half-adder&quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; input1&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; input2&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; sum&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; carry)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-14&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb24-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-15&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb24-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;log&lt;/span&gt;(&lt;span class=&quot;st&quot;&gt;&quot;&amp;gt;&amp;gt; Setting input1 to 1&quot;&lt;/span&gt;)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-16&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb24-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;setSignal&lt;/span&gt;(input1&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&gt;
&lt;span id=&quot;cb24-17&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb24-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-18&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb24-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;sleep&lt;/span&gt;(&lt;span class=&quot;dv&quot;&gt;1000&lt;/span&gt;)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-19&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb24-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-20&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb24-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;log&lt;/span&gt;(&lt;span class=&quot;st&quot;&gt;&quot;&amp;gt;&amp;gt; Setting input2 to 1&quot;&lt;/span&gt;)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-21&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb24-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;setSignal&lt;/span&gt;(input2&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&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And the output:&lt;/p&gt;
&lt;pre class=&quot;plain&quot;&gt;&lt;code&gt;[0] &amp;gt;&amp;gt; Setting up the probes
[0] input1: 0
[0] input2: 0
[0] sum: 0
[0] carry: 0
[0] &amp;gt;&amp;gt; Setting up the half-adder
[0] half-adder-a: 0
[0] half-adder-b: 0
[1] &amp;gt;&amp;gt; Setting input1 to 1
[1] input1: 1
[205] half-adder-b: 1
[505] half-adder-a: 1
[811] sum: 1
[1003] &amp;gt;&amp;gt; Setting input2 to 1
[1003] input2: 1
[1307] carry: 1
[1508] half-adder-b: 0
[1811] sum: 0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In binary, &lt;code&gt;1 + 1 = 10&lt;/code&gt;. Correct! Notice again how the signal propagation through the gates is delayed. Next up is the full adder.&lt;/p&gt;
&lt;p&gt;A &lt;a href=&quot;https://en.wikipedia.org/wiki/Full_adder&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Full adder&lt;/a&gt; adds three bits, two inputs and a carry-in:&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Full Adder&quot; class=&quot;lazyload w-100pct nolink mw-70pct&quot; /&gt;
&amp;lt;noscript&amp;gt;&lt;img alt=&quot;Full Adder&quot; class=&quot;w-100pct nolink mw-70pct&quot; src=&quot;https://abhinavsarkar.net/images/implementing-co-5/full-adder.svg&quot; /&gt;&amp;lt;/noscript&amp;gt;
&lt;figcaption&gt;Full Adder&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Notice that a full adder uses two half adders. Again, we follow the diagram and connect the wires:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb26&quot;&gt;&lt;pre class=&quot;sourceCode javascript numberSource&quot;&gt;&lt;code class=&quot;sourceCode javascript&quot;&gt;&lt;span id=&quot;cb26-1&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb26-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;FullAdder&lt;/span&gt;(label&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; input1&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; input2&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; carryIn&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; sum&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; carryOut) {&lt;/span&gt;
&lt;span id=&quot;cb26-2&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb26-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;var&lt;/span&gt; hsum &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;Wire&lt;/span&gt;()&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb26-3&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb26-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;var&lt;/span&gt; carry1 &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;Wire&lt;/span&gt;()&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb26-4&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb26-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;var&lt;/span&gt; carry2 &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;Wire&lt;/span&gt;()&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb26-5&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb26-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb26-6&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb26-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;addProbe&lt;/span&gt;(label &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;-hsum&quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; hsum)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb26-7&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb26-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;addProbe&lt;/span&gt;(label &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;-carry1&quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; carry1)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb26-8&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb26-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;addProbe&lt;/span&gt;(label &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;-carry2&quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; carry2)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb26-9&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb26-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb26-10&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb26-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;HalfAdder&lt;/span&gt;(label &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;-HA-&quot;&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; input2&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; carryIn&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; hsum&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; carry1)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb26-11&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb26-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;HalfAdder&lt;/span&gt;(label &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;-HA-&quot;&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; input1&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; hsum&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; sum&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; carry2)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb26-12&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb26-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;OrGate&lt;/span&gt;(carry1&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; carry2&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; carryOut)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb26-13&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb26-13&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 skip the demo for full adder and jump to something more exciting.&lt;/p&gt;
&lt;h3 id=&quot;ripple-carry-adder&quot;&gt;Ripple-carry Adder&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#ripple-carry-adder&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A &lt;a href=&quot;https://en.wikipedia.org/wiki/Ripple-carry_adder&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Ripple-carry adder&lt;/a&gt; chains together multiple full adders to add multi-bit numbers. The diagram below shows a four-bit adder:&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Ripple-carry Adder&quot; class=&quot;lazyload w-100pct nolink extra-width&quot; /&gt;
&amp;lt;noscript&amp;gt;&lt;img alt=&quot;Ripple-carry Adder&quot; class=&quot;w-100pct nolink extra-width&quot; src=&quot;https://abhinavsarkar.net/images/implementing-co-5/ripple-adder.svg&quot; /&gt;&amp;lt;/noscript&amp;gt;
&lt;figcaption&gt;Ripple-carry Adder&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;We create a ripple-carry adder that can add any number of bits. First we need some helper functions:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb27&quot;&gt;&lt;pre class=&quot;sourceCode javascript numberSource&quot;&gt;&lt;code class=&quot;sourceCode javascript&quot;&gt;&lt;span id=&quot;cb27-1&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb27-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;Bits&lt;/span&gt;(label&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; n) {&lt;/span&gt;
&lt;span id=&quot;cb27-2&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb27-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;var&lt;/span&gt; bits &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;Empty&lt;/span&gt;()&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb27-3&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb27-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;var&lt;/span&gt; bit &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb27-4&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb27-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;cf&quot;&gt;while&lt;/span&gt; (n &lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;) {&lt;/span&gt;
&lt;span id=&quot;cb27-5&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb27-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    bit &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;Wire&lt;/span&gt;()&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb27-6&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb27-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;addProbe&lt;/span&gt;(label &lt;span class=&quot;op&quot;&gt;+&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;)&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; bit)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb27-7&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb27-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    bits &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;prepend&lt;/span&gt;(bits&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; bit)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb27-8&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb27-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    n &lt;span class=&quot;op&quot;&gt;=&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;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb27-9&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb27-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  }&lt;/span&gt;
&lt;span id=&quot;cb27-10&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb27-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; bits&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb27-11&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb27-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;}&lt;/span&gt;
&lt;span id=&quot;cb27-12&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb27-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb27-13&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb27-13&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;setBits&lt;/span&gt;(bits&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; bitValues) {&lt;/span&gt;
&lt;span id=&quot;cb27-14&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb27-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;cf&quot;&gt;if&lt;/span&gt; (bits &lt;span class=&quot;op&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;Empty&lt;/span&gt;()) {&lt;/span&gt;
&lt;span id=&quot;cb27-15&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb27-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;setSignal&lt;/span&gt;(&lt;span class=&quot;fu&quot;&gt;first&lt;/span&gt;(bits)&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;first&lt;/span&gt;(bitValues))&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb27-16&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb27-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;setBits&lt;/span&gt;(&lt;span class=&quot;fu&quot;&gt;rest&lt;/span&gt;(bits)&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;rest&lt;/span&gt;(bitValues))&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb27-17&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb27-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  }&lt;/span&gt;
&lt;span id=&quot;cb27-18&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb27-18&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;code&gt;Bits&lt;/code&gt; creates a list of wires to represent an N-bit input/output. &lt;code&gt;setBits&lt;/code&gt; sets the bits of a N-bit wire list to a given N-bit value. Now we write a ripple-carry adder:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb28&quot;&gt;&lt;pre class=&quot;sourceCode javascript numberSource&quot;&gt;&lt;code class=&quot;sourceCode javascript&quot;&gt;&lt;span id=&quot;cb28-1&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb28-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;RippleCarryAdder&lt;/span&gt;(label&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; a&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; carryIn&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; sum&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; carryOut) {&lt;/span&gt;
&lt;span id=&quot;cb28-2&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb28-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;var&lt;/span&gt; aBits &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; a&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-3&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb28-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;var&lt;/span&gt; bBits &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; b&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-4&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb28-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;var&lt;/span&gt; sumBits &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; sum&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-5&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb28-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;var&lt;/span&gt; cIn &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; carryIn&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-6&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb28-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;var&lt;/span&gt; cOut &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-7&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb28-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&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;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-8&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb28-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;cf&quot;&gt;while&lt;/span&gt; (aBits &lt;span class=&quot;op&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;Empty&lt;/span&gt;()) {&lt;/span&gt;
&lt;span id=&quot;cb28-9&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb28-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    cOut &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;Wire&lt;/span&gt;()&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-10&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb28-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;addProbe&lt;/span&gt;(label &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;-carryIn-&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; i&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; cIn)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-11&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb28-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;addProbe&lt;/span&gt;(label &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;-carryOut-&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; i&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; cOut)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-12&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb28-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;FullAdder&lt;/span&gt;(label &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;-FA-&quot;&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;cb28-13&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb28-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;fu&quot;&gt;first&lt;/span&gt;(aBits)&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;first&lt;/span&gt;(bBits)&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; cIn&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;first&lt;/span&gt;(sumBits)&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; cOut)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-14&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb28-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    aBits &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;rest&lt;/span&gt;(aBits)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-15&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb28-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    bBits &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;rest&lt;/span&gt;(bBits)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-16&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb28-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    sumBits &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;rest&lt;/span&gt;(sumBits)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-17&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb28-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    cIn &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; cOut&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-18&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb28-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    i &lt;span class=&quot;op&quot;&gt;=&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;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-19&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb28-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  }&lt;/span&gt;
&lt;span id=&quot;cb28-20&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb28-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;connect&lt;/span&gt;(cOut&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; carryOut)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-21&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb28-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The ripple-carry adder uses one full adder per bit, cascading the carry-out bit of each input bit-pairâ€™s sum to the next pair of bits. To demonstrate, letâ€™s add two 4-bit numbers:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb29&quot;&gt;&lt;pre class=&quot;sourceCode javascript numberSource&quot;&gt;&lt;code class=&quot;sourceCode javascript&quot;&gt;&lt;span id=&quot;cb29-1&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb29-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;log&lt;/span&gt;(&lt;span class=&quot;st&quot;&gt;&quot;&amp;gt;&amp;gt; Setting up the probes&quot;&lt;/span&gt;)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb29-2&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb29-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;var&lt;/span&gt; a &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;Bits&lt;/span&gt;(&lt;span class=&quot;st&quot;&gt;&quot;a&quot;&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&gt;
&lt;span id=&quot;cb29-3&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb29-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;var&lt;/span&gt; b &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;Bits&lt;/span&gt;(&lt;span class=&quot;st&quot;&gt;&quot;b&quot;&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&gt;
&lt;span id=&quot;cb29-4&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb29-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;var&lt;/span&gt; sum &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;Bits&lt;/span&gt;(&lt;span class=&quot;st&quot;&gt;&quot;sum&quot;&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&gt;
&lt;span id=&quot;cb29-5&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb29-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;var&lt;/span&gt; carryIn &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;Wire&lt;/span&gt;()&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb29-6&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb29-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;var&lt;/span&gt; carryOut &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;Wire&lt;/span&gt;()&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb29-7&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb29-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb29-8&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb29-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;addProbe&lt;/span&gt;(&lt;span class=&quot;st&quot;&gt;&quot;carryIn&quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; carryIn)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb29-9&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb29-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;addProbe&lt;/span&gt;(&lt;span class=&quot;st&quot;&gt;&quot;carryOut&quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; carryOut)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb29-10&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb29-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb29-11&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb29-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;log&lt;/span&gt;(&lt;span class=&quot;st&quot;&gt;&quot;&amp;gt;&amp;gt; Setting up the ripple carry adder&quot;&lt;/span&gt;)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb29-12&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb29-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;RippleCarryAdder&lt;/span&gt;(&lt;span class=&quot;st&quot;&gt;&quot;RCA&quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; a&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; carryIn&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; sum&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; carryOut)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb29-13&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb29-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb29-14&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb29-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;log&lt;/span&gt;(&lt;span class=&quot;st&quot;&gt;&quot;&amp;gt;&amp;gt; Setting carryIn to 0&quot;&lt;/span&gt;)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb29-15&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb29-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;setSignal&lt;/span&gt;(carryIn&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&gt;
&lt;span id=&quot;cb29-16&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb29-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb29-17&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb29-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;log&lt;/span&gt;(&lt;span class=&quot;st&quot;&gt;&quot;&amp;gt;&amp;gt; Setting a to 5 = 0101 in binary&quot;&lt;/span&gt;)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb29-18&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb29-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;setBits&lt;/span&gt;(a&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;Cons&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;Cons&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;Cons&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;Cons&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;Empty&lt;/span&gt;())))))&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb29-19&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb29-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb29-20&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb29-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;sleep&lt;/span&gt;(&lt;span class=&quot;dv&quot;&gt;1000&lt;/span&gt;)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb29-21&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb29-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb29-22&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb29-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;log&lt;/span&gt;(&lt;span class=&quot;st&quot;&gt;&quot;&amp;gt;&amp;gt; Setting b to 11 = 1011 in binary&quot;&lt;/span&gt;)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb29-23&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb29-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;setBits&lt;/span&gt;(b&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;Cons&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;Cons&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;Cons&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;Cons&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;Empty&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;This one runs for a while because of the collective delays.&lt;/p&gt;
&lt;details&gt;

The output

&lt;pre class=&quot;plain&quot;&gt;&lt;code&gt;[0] &amp;gt;&amp;gt; Setting up the probes
[1] a3: 0
[1] a2: 0
[1] a1: 0
[1] a0: 0
[1] b3: 0
[1] b2: 0
[1] b1: 0
[1] b0: 0
[1] sum3: 0
[1] sum2: 0
[1] sum1: 0
[1] sum0: 0
[1] carryIn: 0
[1] carryOut: 0
[1] &amp;gt;&amp;gt; Setting up the ripple carry adder
[1] RCA-carryIn-1: 0
[1] RCA-carryOut-1: 0
[1] RCA-FA-1-hsum: 0
[1] RCA-FA-1-carry1: 0
[1] RCA-FA-1-carry2: 0
[1] RCA-FA-1-HA-1-a: 0
[1] RCA-FA-1-HA-1-b: 0
[1] RCA-FA-1-HA-2-a: 0
[1] RCA-FA-1-HA-2-b: 0
[1] RCA-carryIn-2: 0
[1] RCA-carryOut-2: 0
[1] RCA-FA-2-hsum: 0
[2] RCA-FA-2-carry1: 0
[2] RCA-FA-2-carry2: 0
[2] RCA-FA-2-HA-1-a: 0
[2] RCA-FA-2-HA-1-b: 0
[2] RCA-FA-2-HA-2-a: 0
[2] RCA-FA-2-HA-2-b: 0
[2] RCA-carryIn-3: 0
[2] RCA-carryOut-3: 0
[2] RCA-FA-3-hsum: 0
[2] RCA-FA-3-carry1: 0
[2] RCA-FA-3-carry2: 0
[2] RCA-FA-3-HA-1-a: 0
[2] RCA-FA-3-HA-1-b: 0
[2] RCA-FA-3-HA-2-a: 0
[2] RCA-FA-3-HA-2-b: 0
[2] RCA-carryIn-4: 0
[2] RCA-carryOut-4: 0
[2] RCA-FA-4-hsum: 0
[2] RCA-FA-4-carry1: 0
[2] RCA-FA-4-carry2: 0
[2] RCA-FA-4-HA-1-a: 0
[2] RCA-FA-4-HA-1-b: 0
[2] RCA-FA-4-HA-2-a: 0
[2] RCA-FA-4-HA-2-b: 0
[2] &amp;gt;&amp;gt; Setting carryIn to 0
[2] &amp;gt;&amp;gt; Setting a to 5 = 0101 in binary
[2] a0: 1
[3] a2: 1
[205] RCA-FA-1-HA-1-b: 1
[205] RCA-FA-1-HA-2-b: 1
[205] RCA-FA-2-HA-1-b: 1
[207] RCA-FA-2-HA-2-b: 1
[207] RCA-FA-3-HA-1-b: 1
[207] RCA-FA-3-HA-2-b: 1
[207] RCA-FA-4-HA-1-b: 1
[207] RCA-FA-4-HA-2-b: 1
[505] RCA-FA-1-HA-2-a: 1
[505] RCA-FA-3-HA-2-a: 1
[810] sum0: 1
[810] sum2: 1
[1014] &amp;gt;&amp;gt; Setting b to 11 = 1011 in binary
[1015] b0: 1
[1015] b1: 1
[1016] b3: 1
[1521] RCA-FA-1-HA-1-a: 1
[1521] RCA-FA-2-HA-1-a: 1
[1521] RCA-FA-4-HA-1-a: 1
[1826] RCA-FA-1-hsum: 1
[1826] RCA-FA-2-hsum: 1
[1826] RCA-FA-4-hsum: 1
[2129] RCA-FA-1-carry2: 1
[2331] RCA-FA-2-HA-2-a: 1
[2331] RCA-FA-4-HA-2-a: 1
[2331] RCA-FA-1-HA-2-b: 0
[2633] RCA-carryOut-1: 1
[2633] sum1: 1
[2633] sum3: 1
[2633] sum0: 0
[2634] RCA-carryIn-2: 1
[2936] RCA-FA-2-carry1: 1
[3138] RCA-FA-2-HA-1-b: 0
[3440] RCA-carryOut-2: 1
[3440] RCA-FA-2-hsum: 0
[3440] RCA-carryIn-3: 1
[3946] RCA-FA-2-HA-2-a: 0
[3946] RCA-FA-3-HA-1-a: 1
[4251] sum1: 0
[4252] RCA-FA-3-hsum: 1
[4556] RCA-FA-3-carry2: 1
[4756] RCA-FA-3-HA-2-b: 0
[5059] RCA-carryOut-3: 1
[5059] sum2: 0
[5059] RCA-carryIn-4: 1
[5363] RCA-FA-4-carry1: 1
[5564] RCA-FA-4-HA-1-b: 0
[5867] RCA-carryOut-4: 1
[5867] RCA-FA-4-hsum: 0
[5867] carryOut: 1
[6370] RCA-FA-4-HA-2-a: 0
[6675] sum3: 0&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;Let me pick out the final output:&lt;/p&gt;
&lt;pre class=&quot;plain&quot;&gt;&lt;code&gt;sum0: 0
sum1: 0
sum2: 0
carryOut: 1
sum3: 0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We add &lt;code&gt;0101&lt;/code&gt; and &lt;code&gt;1011&lt;/code&gt; in binary, resulting in &lt;code&gt;10000&lt;/code&gt;, which is correct again. Everything works perfectly. With sleep, weâ€™ve now implemented all major features of &lt;span class=&quot;fancy&quot;&gt;Co&lt;/span&gt;â€”a complete concurrent language with first-class coroutines, channels, and time-based scheduling.&lt;/p&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;With the addition of sleep, weâ€™ve completed our implementation of &lt;span class=&quot;fancy&quot;&gt;Co&lt;/span&gt;â€”a small language with coroutines and channels. Over these five posts, we went from parsing source code to building a full interpreter that handles cooperative multitasking using coroutines.&lt;/p&gt;
&lt;p&gt;The key insight was realizing that coroutines are just environments plus continuations. By designing our interpreter to use continuation-passing style, we gained the ability to suspend execution at any point and resume it later. Channels built naturally on top of that, providing a way for coroutines to synchronize and pass messages. And sleep extended the scheduler to handle time-based execution, unlocking patterns like timeouts and periodic tasks.&lt;/p&gt;
&lt;p&gt;The examples we built along the wayâ€”pubsub system, actor system, and digital circuit simulationâ€”show what becomes possible once these primitives are in place. Starting with basic arithmetic and functions, we ended up with a language capable of expressing real concurrent programs.&lt;/p&gt;
&lt;p&gt;What comes next? Maybe a compiler for &lt;span class=&quot;fancy&quot;&gt;Co&lt;/span&gt;? Stay tuned by subscribing to the &lt;a href=&quot;https://abhinavsarkar.net/feed.atom?mtm_campaign=feed&quot;&gt;feed&lt;/a&gt; or the &lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#subscription&quot;&gt;email newsletter&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The full code for the &lt;span class=&quot;fancy&quot;&gt;Co&lt;/span&gt; interpreter is available &lt;a href=&quot;https://abhinavsarkar.net/code/co-interpreter.html?mtm_campaign=feed&quot;&gt;here&lt;/a&gt;.&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;The sleep implementation in &lt;span class=&quot;fancy&quot;&gt;Co&lt;/span&gt; is not interruptible. That is, if a coroutine is sleeping, it cannot be resumed before the specified duration. This is different from sleep implementations in most programming languages, where the sleep operation can be interrupted by sending a signal to the sleeping ToC.&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;Threads in GHC are &lt;em&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Green_Threads&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Green Threads&lt;/a&gt;&lt;/em&gt; and are very cheap to create and run. It is perfectly okay to fork a new one for each delayed coroutine.&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;So in a way, we cheat here by using the sleep primitive provided by the GHC runtime to implement our sleep primitive. If we write a compiler for &lt;span class=&quot;fancy&quot;&gt;Co&lt;/span&gt;, weâ€™ll have to write our own runtime where weâ€™ll have to implement our sleep function using the functionalities provided by the operating systems.&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;To learn more about how &lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span class=&quot;dt&quot;&gt;MVar&lt;/span&gt;&lt;/code&gt;s can be used to communicate between threads, read the &lt;a href=&quot;https://web.archive.org/web/20260116/https://book.realworldhaskell.org/read/concurrent-and-multicore-programming.html#id673028&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot; title=&quot;Real World Haskell Chapter 24: Concurrent and Multicore Programming&quot;&gt;chapter 24 of Real World Haskell&lt;/a&gt;.&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;/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;Implementing Co, a Small Language With Coroutines&lt;/strong&gt;.&lt;/p&gt;
  &lt;ol&gt;
    &lt;li&gt;
      
       &lt;a href=&quot;https://abhinavsarkar.net/posts/implementing-co-1/?mtm_campaign=feed&quot;&gt;The Parser&lt;/a&gt; 
    &lt;/li&gt;
    &lt;li&gt;
      
       &lt;a href=&quot;https://abhinavsarkar.net/posts/implementing-co-2/?mtm_campaign=feed&quot;&gt;The Interpreter&lt;/a&gt; 
    &lt;/li&gt;
    &lt;li&gt;
      
       &lt;a href=&quot;https://abhinavsarkar.net/posts/implementing-co-3/?mtm_campaign=feed&quot;&gt;Adding Coroutines&lt;/a&gt; 
    &lt;/li&gt;
    &lt;li&gt;
      
       &lt;a href=&quot;https://abhinavsarkar.net/posts/implementing-co-4/?mtm_campaign=feed&quot;&gt;Adding Channels&lt;/a&gt; 
    &lt;/li&gt;
    &lt;li&gt;
       &lt;strong&gt;Adding Sleep&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/implementing-co-5/?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/115905408192306242&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/taxbgk&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/1qehkip/&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//13549&quot; rel=&quot;syndication&quot; target=&quot;_blank&quot;&gt;Discourse&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;u-syndication&quot; href=&quot;https://news.ycombinator.com/item?id=46645854&quot; rel=&quot;syndication&quot; target=&quot;_blank&quot;&gt;Hacker News&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/implementing-co-5/?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>Fri, 16 Jan 2026 00:00:00 +0000</pubDate>
	<author>abhinav@abhinavsarkar.net (Abhinav Sarkar)</author>
</item>
<item>
	<title>Brent Yorgey: Disco Live!</title>
	<guid isPermaLink="true">http://byorgey.github.io/blog/posts/2026/01/09/disco-live.html</guid>
	<link>http://byorgey.github.io/blog/posts/2026/01/09/disco-live.html</link>
	<description>&lt;h1&gt;Disco Live!&lt;/h1&gt;

&lt;div class=&quot;info&quot;&gt;
  Posted on January  9, 2026
  
  
  &lt;br /&gt;
  Tagged &lt;a href=&quot;https://byorgey.github.io/tag/disco.html&quot; rel=&quot;tag&quot; title=&quot;All pages tagged 'disco'.&quot;&gt;disco&lt;/a&gt;, &lt;a href=&quot;https://byorgey.github.io/tag/web.html&quot; rel=&quot;tag&quot; title=&quot;All pages tagged 'web'.&quot;&gt;web&lt;/a&gt;, &lt;a href=&quot;https://byorgey.github.io/tag/WASM.html&quot; rel=&quot;tag&quot; title=&quot;All pages tagged 'WASM'.&quot;&gt;WASM&lt;/a&gt;, &lt;a href=&quot;https://byorgey.github.io/tag/UI.html&quot; rel=&quot;tag&quot; title=&quot;All pages tagged 'UI'.&quot;&gt;UI&lt;/a&gt;, &lt;a href=&quot;https://byorgey.github.io/tag/teaching.html&quot; rel=&quot;tag&quot; title=&quot;All pages tagged 'teaching'.&quot;&gt;teaching&lt;/a&gt;, &lt;a href=&quot;https://byorgey.github.io/tag/discrete.html&quot; rel=&quot;tag&quot; title=&quot;All pages tagged 'discrete'.&quot;&gt;discrete&lt;/a&gt;, &lt;a href=&quot;https://byorgey.github.io/tag/math.html&quot; rel=&quot;tag&quot; title=&quot;All pages tagged 'math'.&quot;&gt;math&lt;/a&gt;, &lt;a href=&quot;https://byorgey.github.io/tag/Haskell.html&quot; rel=&quot;tag&quot; title=&quot;All pages tagged 'Haskell'.&quot;&gt;Haskell&lt;/a&gt;
  
&lt;/div&gt;

&lt;a href=&quot;https://share.joinmastodon.org/#text=Disco Live! https://byorgey.github.io/blog/posts/2026/01/09/disco-live.html&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Share on &lt;/a&gt;
&lt;section&gt;
&lt;p&gt;A couple months ago, &lt;a href=&quot;https://byorgey.github.io/blog/posts/2025/11/10/disco-web-ui.html&quot;&gt;I asked for
help&lt;/a&gt;
creating a web interface for
&lt;a href=&quot;https://github.com/disco-lang/disco&quot;&gt;Disco&lt;/a&gt;, a
student-oriented programming language for teaching functional
programming and discrete mathematics. I am very happy to report that
&lt;a href=&quot;https://apfelmus.nfshost.com/&quot;&gt;Heinrich Apfelmus&lt;/a&gt; responded to the
call, and this is the result:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://disco-lang.github.io/disco-live/&quot;&gt;Disco Live!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It’s fairly bare bones at the moment, but it’s a fantastic place to
start, and far more than I would have been able to accomplish in a few
weeks. Give it a try, and let me know of any bugs you find! You are
also very welcome to contribute fixes, features, etc. on GitHub:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/disco-lang/disco-live&quot;&gt;The disco-live repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/disco-lang/disco&quot;&gt;The repo for disco itself&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you want to know more about Disco, you can &lt;a href=&quot;http://ozark.hendrix.edu/~yorgey/forest/yorgey-disco-2023/index.xml&quot;&gt;read a paper about it
here&lt;/a&gt;,
or &lt;a href=&quot;https://disco-lang.readthedocs.io/en/latest/&quot;&gt;read the language documentation&lt;/a&gt;.&lt;/p&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, 09 Jan 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Well-Typed.Com: The Haskell Debugger for GHC 9.14</title>
	<guid isPermaLink="false">http://www.well-typed.com/blog/2026/01/the-haskell-debugger-for-ghc-9</guid>
	<link>https://well-typed.com/blog/2026/01/the-haskell-debugger-for-ghc-9</link>
	<description>&lt;p&gt;&lt;strong&gt;The Haskell Debugger is ready to use with GHC-9.14!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The installation, configuration, and talks can be found in &lt;a href=&quot;https://well-typed.github.io/haskell-debugger&quot;&gt;the official website&lt;/a&gt;. The tl;dr first step is installing the debugger:&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;https://well-typed.com/blog/rss2.xml#cb1-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;$&lt;/span&gt; ghc &lt;span class=&quot;at&quot;&gt;--version&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;# MUST BE GHC 9.14&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;&lt;span class=&quot;ex&quot;&gt;The&lt;/span&gt; Glorious Glasgow Haskell Compilation System, version 9.14.1&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;&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;ex&quot;&gt;$&lt;/span&gt; cabal install haskell-debugger &lt;span class=&quot;at&quot;&gt;--allow-newer&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;=&lt;/span&gt;base,time,containers,ghc,ghc-bignum,template-haskell &lt;span class=&quot;at&quot;&gt;--enable-executable-dynamic&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;# ON WINDOWS, DO NOT PASS --enable-executable-dynamic&lt;/span&gt;&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 class=&quot;ex&quot;&gt;...&lt;/span&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&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;&lt;span class=&quot;ex&quot;&gt;$&lt;/span&gt; ~/.local/bin/hdb &lt;span class=&quot;at&quot;&gt;--version&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;# VERIFY IT'S THE LATEST!&lt;/span&gt;&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 class=&quot;ex&quot;&gt;Haskell&lt;/span&gt; Debugger, version 0.11.0.0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The second step is configuring your editor to use the debugger via the &lt;strong&gt;D&lt;/strong&gt;ebug &lt;strong&gt;A&lt;/strong&gt;dapter &lt;strong&gt;P&lt;/strong&gt;rotocol (DAP).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For VSCode, install &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=Well-Typed.haskell-debugger-extension&quot;&gt;the haskell debugger extension&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;For Neovim, install &lt;code&gt;nvim-dap&lt;/code&gt; and &lt;a href=&quot;https://codeberg.org/mfussenegger/nvim-dap/wiki/Debug-Adapter-installation#haskell-hdb&quot;&gt;configure it for haskell-debugger&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;For other editors, consult your DAP documentation and let others know how!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bug reports and discussions are welcome in the &lt;a href=&quot;https://github.com/well-typed/haskell-debugger&quot;&gt;haskell-debugger issue tracker&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;My MuniHac 2025 talk also walks through the installation, usage, and design of the debugger. Do note much has been improved since the talk was given, and much more will still improve.&lt;/p&gt;
&lt;div style=&quot;width: 560px; height: 315px; margin-bottom: 1em;&quot;&gt;

&lt;/div&gt;
&lt;h4 id=&quot;a-little-bit-more-info&quot;&gt;A little bit more info&lt;/h4&gt;

&lt;p&gt;The debugger work is sponsored by Mercury. It’s the project in which I’ve spent most of my full working days (for almost a full year now), with the invaluable help from my team at Well-Typed.&lt;/p&gt;
&lt;p&gt;The debugger is meant to work both on trivial files and on large and complex codebases.&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; It is a GHC application so &lt;em&gt;all features are supported&lt;/em&gt;. Like HLS, it also uses &lt;code&gt;hie-bios&lt;/code&gt; to automatically configure the session based on your cabal or stack project.&lt;/p&gt;
&lt;p&gt;Robustness is a main goal of the debugger. If anything doesn’t work, or if you have performance issues, or something crashes, please don’t hesitate to submit a bug. We’ve got a small but respectable testsuite, and have tested performance by debugging GHC itself, but there’s much still to be fixed and improved.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Roadmap&lt;/strong&gt;: There’s a lot to do. I’m currently working on callstacks and multi-threaded support. Do let me know what features would be most important to you, so I can also factor that into the future planning.&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;Although, for large codebases, the usability is still rough around the edges because of possibly long bytecode compilation times, and library code not being interpreted. We’ve made considerable progress to improve this with the &lt;a href=&quot;https://discourse.haskell.org/t/rfc-introduce-a-serialisable-bytecode-format-and-corresponding-bytecode-way/12678&quot;&gt;bytecode artifacts work&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;/ol&gt;
&lt;/section&gt;</description>
	<pubDate>Thu, 08 Jan 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Well-Typed.Com: The Haskell Debugger for GHC 9.14</title>
	<guid isPermaLink="false">http://www.well-typed.com/blog/2026/01/haskell-debugger</guid>
	<link>https://well-typed.com/blog/2026/01/haskell-debugger</link>
	<description>&lt;p&gt;&lt;strong&gt;The Haskell Debugger is ready to use with GHC-9.14!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The installation, configuration, and talks can be found in &lt;a href=&quot;https://well-typed.github.io/haskell-debugger&quot;&gt;the official website&lt;/a&gt;. The tl;dr first step is installing the debugger:&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;https://well-typed.com/blog/rss2.xml#cb1-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;$&lt;/span&gt; ghc &lt;span class=&quot;at&quot;&gt;--version&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;# MUST BE GHC 9.14&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;&lt;span class=&quot;ex&quot;&gt;The&lt;/span&gt; Glorious Glasgow Haskell Compilation System, version 9.14.1&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;&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;ex&quot;&gt;$&lt;/span&gt; cabal install haskell-debugger &lt;span class=&quot;at&quot;&gt;--allow-newer&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;=&lt;/span&gt;base,time,containers,ghc,ghc-bignum,template-haskell &lt;span class=&quot;at&quot;&gt;--enable-executable-dynamic&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;# ON WINDOWS, DO NOT PASS --enable-executable-dynamic&lt;/span&gt;&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 class=&quot;ex&quot;&gt;...&lt;/span&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&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;&lt;span class=&quot;ex&quot;&gt;$&lt;/span&gt; ~/.local/bin/hdb &lt;span class=&quot;at&quot;&gt;--version&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;# VERIFY IT'S THE LATEST!&lt;/span&gt;&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 class=&quot;ex&quot;&gt;Haskell&lt;/span&gt; Debugger, version 0.11.0.0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The second step is configuring your editor to use the debugger via the &lt;strong&gt;D&lt;/strong&gt;ebug &lt;strong&gt;A&lt;/strong&gt;dapter &lt;strong&gt;P&lt;/strong&gt;rotocol (DAP).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For VSCode, install &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=Well-Typed.haskell-debugger-extension&quot;&gt;the haskell debugger extension&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;For Neovim, install &lt;code&gt;nvim-dap&lt;/code&gt; and &lt;a href=&quot;https://codeberg.org/mfussenegger/nvim-dap/wiki/Debug-Adapter-installation#haskell-hdb&quot;&gt;configure it for haskell-debugger&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;For other editors, consult your DAP documentation and let others know how!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bug reports and discussions are welcome in the &lt;a href=&quot;https://github.com/well-typed/haskell-debugger&quot;&gt;haskell-debugger issue tracker&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;My MuniHac 2025 talk also walks through the installation, usage, and design of the debugger. Do note much has been improved since the talk was given, and much more will still improve.&lt;/p&gt;
&lt;div style=&quot;width: 560px; height: 315px; margin-bottom: 1em;&quot;&gt;

&lt;/div&gt;
&lt;h4 id=&quot;a-little-bit-more-info&quot;&gt;A little bit more info&lt;/h4&gt;

&lt;p&gt;The debugger work is sponsored by Mercury. It’s the project in which I’ve spent most of my full working days (for almost a full year now), with the invaluable help from my team at Well-Typed.&lt;/p&gt;
&lt;p&gt;The debugger is meant to work both on trivial files and on large and complex codebases.&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; It is a GHC application so &lt;em&gt;all features are supported&lt;/em&gt;. Like HLS, it also uses &lt;code&gt;hie-bios&lt;/code&gt; to automatically configure the session based on your cabal or stack project.&lt;/p&gt;
&lt;p&gt;Robustness is a main goal of the debugger. If anything doesn’t work, or if you have performance issues, or something crashes, please don’t hesitate to submit a bug. We’ve got a small but respectable testsuite, and have tested performance by debugging GHC itself, but there’s much still to be fixed and improved.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Roadmap&lt;/strong&gt;: There’s a lot to do. I’m currently working on callstacks and multi-threaded support. Do let me know what features would be most important to you, so I can also factor that into the future planning.&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;Although, for large codebases, the usability is still rough around the edges because of possibly long bytecode compilation times, and library code not being interpreted. We’ve made considerable progress to improve this with the &lt;a href=&quot;https://discourse.haskell.org/t/rfc-introduce-a-serialisable-bytecode-format-and-corresponding-bytecode-way/12678&quot;&gt;bytecode artifacts work&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;/ol&gt;
&lt;/section&gt;</description>
	<pubDate>Thu, 08 Jan 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Magnus Therning: Validation of data in a servant server</title>
	<guid isPermaLink="true">https://magnus.therning.org/2026-01-04-validation-of-data-in-a-servant-server.html</guid>
	<link>https://magnus.therning.org/2026-01-04-validation-of-data-in-a-servant-server.html</link>
	<description>&lt;p&gt;
I've been playing around with adding more validation of data received by an HTTP
endpoint in a &lt;a href=&quot;https://hackage.haskell.org/package/servant&quot;&gt;servant&lt;/a&gt; server. Defining a type with a &lt;code&gt;FromJSON&lt;/code&gt; instance is very
easy, just derive a &lt;code&gt;Generic&lt;/code&gt; instance and it just works. Here's a simple
example
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-haskell&quot;&gt;&lt;code&gt;&lt;span class=&quot;org-keyword&quot;&gt;data&lt;/span&gt; Person = Person
    { name :: &lt;span class=&quot;org-type&quot;&gt;Text&lt;/span&gt;
    , age :: &lt;span class=&quot;org-type&quot;&gt;Int&lt;/span&gt;
    , occupation :: &lt;span class=&quot;org-type&quot;&gt;Occupation&lt;/span&gt;
    }
    &lt;span class=&quot;org-keyword&quot;&gt;deriving&lt;/span&gt; (Generic, Show)
    &lt;span class=&quot;org-keyword&quot;&gt;deriving&lt;/span&gt; (FromJSON, ToJSON) via &lt;span class=&quot;org-type&quot;&gt;(Generically Person)&lt;/span&gt;

&lt;span class=&quot;org-keyword&quot;&gt;data&lt;/span&gt; Occupation = UnderAge | Student | Unemployed | SelfEmployed | Retired | Occupation &lt;span class=&quot;org-type&quot;&gt;Text&lt;/span&gt;
    &lt;span class=&quot;org-keyword&quot;&gt;deriving&lt;/span&gt; (Eq, Generic, Ord, Show)
    &lt;span class=&quot;org-keyword&quot;&gt;deriving&lt;/span&gt; (FromJSON, ToJSON) via &lt;span class=&quot;org-type&quot;&gt;(Generically Occupation)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
However, the validation is rather limited, basically it's just checking that
each field is present and of the correct type. For the type above I'd like to
enforce some constraints for the combination of &lt;code&gt;age&lt;/code&gt; and &lt;code&gt;occupation&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
The steps I thought of are
&lt;/p&gt;

&lt;ol class=&quot;org-ol&quot;&gt;
&lt;li&gt;Hide the default constructor and define a &lt;a href=&quot;https://wiki.haskell.org/Smart_constructors&quot;&gt;smart&lt;/a&gt; one. (This is the standard
suggestion for placing extra constraints values.)&lt;/li&gt;
&lt;li&gt;Manually define the &lt;code&gt;FromJSON&lt;/code&gt; instance using the &lt;code&gt;Generic&lt;/code&gt; instance to limit
the amount of code and the smart constructor.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-org8b6637c&quot;&gt;
&lt;h2 id=&quot;org8b6637c&quot;&gt;The smart constructor&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-org8b6637c&quot;&gt;
&lt;p&gt;
I give the constructor the result type &lt;code&gt;Either String Person&lt;/code&gt; to make sure it
can both be usable in code and when defining &lt;code&gt;parseJSON&lt;/code&gt;.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-haskell&quot;&gt;&lt;code&gt;&lt;span class=&quot;org-function-name&quot;&gt;mkPerson&lt;/span&gt; :: &lt;span class=&quot;org-type&quot;&gt;Text&lt;/span&gt; &lt;span class=&quot;org-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;org-type&quot;&gt;Int&lt;/span&gt; &lt;span class=&quot;org-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;org-type&quot;&gt;Occupation&lt;/span&gt; &lt;span class=&quot;org-operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;org-type&quot;&gt;Either String Person&lt;/span&gt;
&lt;span class=&quot;org-function-name&quot;&gt;mkPerson&lt;/span&gt; name age occupation = &lt;span class=&quot;org-keyword&quot;&gt;do&lt;/span&gt;
    guardE mustBeUnderAge
    guardE notUnderAge
    guardE tooOldToBeStudent
    guardE mustBeRetired
    pure &lt;span class=&quot;org-operator&quot;&gt;$&lt;/span&gt; Person name age occupation
  &lt;span class=&quot;org-keyword&quot;&gt;where&lt;/span&gt;
    &lt;span class=&quot;org-function-name&quot;&gt;guardE&lt;/span&gt; (pred, err) = when pred &lt;span class=&quot;org-operator&quot;&gt;$&lt;/span&gt; Left err
    &lt;span class=&quot;org-function-name&quot;&gt;mustBeUnderAge&lt;/span&gt; = (age &lt;span class=&quot;org-operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;org-number&quot;&gt;8&lt;/span&gt; &lt;span class=&quot;org-operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; occupation &lt;span class=&quot;org-operator&quot;&gt;&amp;gt;&lt;/span&gt; UnderAge, &lt;span class=&quot;org-string&quot;&gt;&quot;too young for occupation&quot;&lt;/span&gt;)
    &lt;span class=&quot;org-function-name&quot;&gt;notUnderAge&lt;/span&gt; = (age &lt;span class=&quot;org-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;org-number&quot;&gt;15&lt;/span&gt; &lt;span class=&quot;org-operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; occupation &lt;span class=&quot;org-operator&quot;&gt;==&lt;/span&gt; UnderAge, &lt;span class=&quot;org-string&quot;&gt;&quot;too old to be under age&quot;&lt;/span&gt;)
    &lt;span class=&quot;org-function-name&quot;&gt;tooOldToBeStudent&lt;/span&gt; = (age &lt;span class=&quot;org-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;org-number&quot;&gt;45&lt;/span&gt; &lt;span class=&quot;org-operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; occupation &lt;span class=&quot;org-operator&quot;&gt;==&lt;/span&gt; Student, &lt;span class=&quot;org-string&quot;&gt;&quot;too old to be a student&quot;&lt;/span&gt;)
    &lt;span class=&quot;org-function-name&quot;&gt;mustBeRetired&lt;/span&gt; = (age &lt;span class=&quot;org-operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;org-number&quot;&gt;65&lt;/span&gt; &lt;span class=&quot;org-operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; occupation &lt;span class=&quot;org-operator&quot;&gt;/=&lt;/span&gt; Retired, &lt;span class=&quot;org-string&quot;&gt;&quot;too old to not be retired&quot;&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Here I'm making use of &lt;code&gt;Either e&lt;/code&gt; being a &lt;code&gt;Monad&lt;/code&gt; and use &lt;code&gt;when&lt;/code&gt; to apply the
constraints and ensure the reason for failure is given to the caller.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-org323ebdf&quot;&gt;
&lt;h2 id=&quot;org323ebdf&quot;&gt;The &lt;code&gt;FromJSON&lt;/code&gt; instance&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-org323ebdf&quot;&gt;
&lt;p&gt;
When defining the instance I take advantage of the &lt;code&gt;Generic&lt;/code&gt; instance to make
the implementation short and simple.
&lt;/p&gt;

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-haskell&quot;&gt;&lt;code&gt;&lt;span class=&quot;org-keyword&quot;&gt;instance&lt;/span&gt; FromJSON &lt;span class=&quot;org-type&quot;&gt;Person&lt;/span&gt; &lt;span class=&quot;org-keyword&quot;&gt;where&lt;/span&gt;
    &lt;span class=&quot;org-function-name&quot;&gt;parseJSON&lt;/span&gt; v = &lt;span class=&quot;org-keyword&quot;&gt;do&lt;/span&gt;
        Person{name, age, occupation} &amp;lt;- genericParseJSON defaultOptions v
        either fail pure &lt;span class=&quot;org-operator&quot;&gt;$&lt;/span&gt; mkPerson name age occupation
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
If there are many more fields in the type I'd consider using &lt;a href=&quot;https://downloads.haskell.org/ghc/latest/docs/users_guide/exts/record_wildcards.html&quot;&gt;&lt;code&gt;RecordWildCards&lt;/code&gt;&lt;/a&gt;.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgb6bf602&quot;&gt;
&lt;h2 id=&quot;orgb6bf602&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgb6bf602&quot;&gt;
&lt;p&gt;
No, it's nothing ground-breaking but I think it's a fairly nice example of how
things can fit together in Haskell.
&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-haskell.html&quot;&gt;haskell&lt;/a&gt; &lt;a href=&quot;https://magnus.therning.org/tag-servant.html&quot;&gt;servant&lt;/a&gt; &lt;/div&gt;</description>
	<pubDate>Sun, 04 Jan 2026 09:58:00 +0000</pubDate>
</item>
<item>
	<title>Joachim Breitner: Seemingly impossible programs in Lean</title>
	<guid isPermaLink="true">https://www.joachim-breitner.de/blog/818-Seemingly_impossible_programs_in_Lean</guid>
	<link>https://www.joachim-breitner.de/blog/818-Seemingly_impossible_programs_in_Lean</link>
	<description>&lt;p&gt;In 2007, Martin Escardo wrote a often-read &lt;a href=&quot;https://math.andrej.com/2007/09/28/seemingly-impossible-functional-programs/&quot;&gt;blog post about “Seemingly impossible functional programs”&lt;/a&gt;. One such seemingly impossible function is &lt;code&gt;find&lt;/code&gt;, which takes a predicate on infinite sequences of bits, and returns an infinite sequence for which that predicate hold (unless the predicate is just always false, in which case it returns some arbitrary sequence).&lt;/p&gt;
&lt;p&gt;Inspired by conversations with and experiments by Massin Guerdi at the dinner of &lt;a href=&quot;https://leaning.in/2025/&quot;&gt;LeaningIn 2025&lt;/a&gt; in Berlin (yes, this blog post has been in my pipeline for far too long), I wanted to play around these concepts in Lean.&lt;/p&gt;
&lt;p&gt;Let’s represent infinite sequences of bits as functions from &lt;code&gt;Nat&lt;/code&gt; to &lt;code&gt;Bit&lt;/code&gt;, and give them a nice name, and some basic functionality, including a binary operator for consing an element to the front:&lt;/p&gt;
&lt;pre class=&quot;lean&quot;&gt;&lt;code&gt;import Mathlib.Data.Nat.Find

abbrev Bit := Bool

def Cantor : Type := Nat → Bit

def Cantor.head (a : Cantor) : Bit := a 0

def Cantor.tail (a : Cantor) : Cantor := fun i =&amp;gt; a (i + 1)

@[simp, grind] def Cantor.cons (x : Bit) (a : Cantor) : Cantor
  | 0 =&amp;gt; x
  | i+1 =&amp;gt; a i

infix:60 &quot; # &quot; =&amp;gt; Cantor.cons&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this in place, we can write Escardo’s function in Lean. His blog post discusses a few variants; I’ll focus on just one of them:&lt;/p&gt;
&lt;pre class=&quot;lean&quot;&gt;&lt;code&gt;mutual
  partial def forsome (p : Cantor → Bool) : Bool :=
    p (find p)

  partial def find (p : Cantor → Bool) : Cantor :=
    have b := forsome (fun a =&amp;gt; p (true # a))
    (b # find (fun a =&amp;gt; p (b # a)))
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We define &lt;code&gt;find&lt;/code&gt; together with &lt;code&gt;forsome&lt;/code&gt;, which checks if the predicate &lt;code&gt;p&lt;/code&gt; holds for any sequence. Using that &lt;code&gt;find&lt;/code&gt; sets the first element of the result to &lt;code&gt;true&lt;/code&gt; if there exists a squence starting with &lt;code&gt;true&lt;/code&gt;, else to &lt;code&gt;false&lt;/code&gt;, and then tries to find the rest of the sequence.&lt;/p&gt;
&lt;p&gt;It is a bit of a brian twiter that this code works, but it does:&lt;/p&gt;
&lt;pre class=&quot;lean&quot;&gt;&lt;code&gt;def fifth_false : Cantor → Bool := fun a =&amp;gt; not (a 5)

/-- info: [true, true, true, true, true, false, true, true, true, true] -/
#guard_msgs in
#eval List.ofFn (fun (i : Fin 10) =&amp;gt; find fifth_false i)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Of course, in Lean we don’t just want to define these functions, but we want to prove that they do what we expect them to do.&lt;/p&gt;
&lt;p&gt;Above we defined them as &lt;code&gt;partial&lt;/code&gt; functions, even though we hope that they are not actually partial: The &lt;code&gt;partial&lt;/code&gt; keyword means that we don’t have to do a termination proof, but also that we cannot prove anything about these functions.&lt;/p&gt;
&lt;p&gt;So can we convince Lean that these functions are total after all? We can, but it’s a bit of a puzzle, and we have to adjust the definitions.&lt;/p&gt;
&lt;p&gt;First of all, these “seemingly impossible functions” are only possible because we assume that the predicate we pass to it, &lt;code&gt;p&lt;/code&gt;, is computable and total. This is where the whole magic comes from, and I recommend to read Escardo’s blog posts and papers for more on this fascinating topic. In particular, you will learn that a predicate on &lt;code&gt;Cantor&lt;/code&gt; that is computable and total necessarily only looks at some initial fragment of the sequence. The length of that prefix is called the “modulus”. So if we hope to prove termination of &lt;code&gt;find&lt;/code&gt; and &lt;code&gt;forsome&lt;/code&gt;, we have to restrict their argument &lt;code&gt;p&lt;/code&gt; to only such computable predicates.&lt;/p&gt;
&lt;p&gt;To that end I introduce &lt;code&gt;HasModulus&lt;/code&gt; and the subtype of predicates on &lt;code&gt;Cantor&lt;/code&gt; that have such a modulus:&lt;/p&gt;
&lt;pre class=&quot;lean&quot;&gt;&lt;code&gt;-- Extensional (!) modulus of uniform continuity
def HasModulus (p : Cantor → α) := ∃ n, ∀ a b : Cantor, (∀ i &amp;lt; n, a i = b i) → p a = p b

@[ext] structure CantorPred where
  pred : Cantor → Bool
  hasModulus : HasModulus pred&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The modulus of such a predicate is now the least prefix lenght that determines the predicate. In particular, if the modulus is zero, the predicate is constant:&lt;/p&gt;
&lt;pre class=&quot;lean&quot;&gt;&lt;code&gt;namespace CantorPred

variable (p : CantorPred)

noncomputable def modulus : Nat :=
  open Classical in Nat.find p.hasModulus

theorem eq_of_modulus : ∀a b : Cantor, (∀ i &amp;lt; p.modulus, a i = b i) → p a = p b := by
  open Classical in
  unfold modulus
  exact Nat.find_spec p.hasModulus

theorem eq_of_modulus_eq_0 (hm : p.modulus = 0) : ∀ a b, p a = p b := by
  intro a b
  apply p.eq_of_modulus
  simp [hm]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Because we want to work with &lt;code&gt;CantorPred&lt;/code&gt; and not &lt;code&gt;Cantor → Bool&lt;/code&gt; I have to define some operations on that new type; in particular the “cons element before predicate” operation that we saw above in &lt;code&gt;find&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;lean&quot;&gt;&lt;code&gt;def comp_cons (b : Bit) : CantorPred where
  pred := fun a =&amp;gt; p (b # a)
  hasModulus := by
    obtain ⟨n, h_n⟩ := p.hasModulus
    cases n with
    | zero =&amp;gt; exists 0; grind
    | succ m =&amp;gt;
      exists m
      intro a b heq
      simp
      apply h_n
      intro i hi
      cases i
      · rfl
      · grind

@[simp, grind =] theorem comp_cons_pred (x : Bit) (a : Cantor) :
  (p.comp_cons x) a = p (x # a) := rfl&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For this operation we know that the modulus decreases (if it wasn’t already zero):&lt;/p&gt;
&lt;pre class=&quot;lean&quot;&gt;&lt;code&gt;theorem comp_cons_modulus (x : Bit) :
    (p.comp_cons x).modulus ≤ p.modulus - 1 := by
  open Classical in
  apply Nat.find_le
  intro a b hab
  apply p.eq_of_modulus
  cases hh : p.modulus
  · simp
  · intro i hi
    cases i
    · grind
    · grind
grind_pattern comp_cons_modulus =&amp;gt; (p.comp_cons x).modulus&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can rewrite the &lt;code&gt;find&lt;/code&gt; function above to use these operations:&lt;/p&gt;
&lt;pre class=&quot;lean&quot;&gt;&lt;code&gt;mutual
  partial def forsome (p : CantorPred) : Bool := p (find p)

  partial def find (p : CantorPred) : Cantor := fun i =&amp;gt;
    have b := forsome (p.comp_cons true)
    (b # find (p.comp_cons b)) i
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I have also eta-expanded the &lt;code&gt;Cantor&lt;/code&gt; function returned by &lt;code&gt;find&lt;/code&gt;; there is now a &lt;code&gt;fun i =&amp;gt; … i&lt;/code&gt; around the body. We’ll shortly see why that is needed.&lt;/p&gt;
&lt;p&gt;Now have everything in place to attempt a termination proof. Before we do that proof, we could step back and try to come up with an informal termination argument.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The recursive call from &lt;code&gt;forsome&lt;/code&gt; to &lt;code&gt;find&lt;/code&gt; doesn’t decrease any argument at all. This is ok if all calls from &lt;code&gt;find&lt;/code&gt; to &lt;code&gt;forsome&lt;/code&gt; are decreasing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The recursive call from &lt;code&gt;find&lt;/code&gt; to &lt;code&gt;find&lt;/code&gt; decreases the index &lt;code&gt;i&lt;/code&gt; as the recursive call is behind the &lt;code&gt;Cantor.cons&lt;/code&gt; operation that shifts the index. Good.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The recursive call from &lt;code&gt;find&lt;/code&gt; to &lt;code&gt;forsome&lt;/code&gt; decreases the modulus of the argument &lt;code&gt;p&lt;/code&gt;, if it wasn’t already zero.&lt;/p&gt;
&lt;p&gt;But if was zero, it does not decrease it! But if it zero, then the call from &lt;code&gt;forsome&lt;/code&gt; to &lt;code&gt;find&lt;/code&gt; doesn’t actually need to call &lt;code&gt;find&lt;/code&gt;, because then &lt;code&gt;p&lt;/code&gt; doesn’t look at its argument.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We can express all this reasoning as a termination measure in the form of a lexicographic triple. The &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;1&lt;/code&gt; in the middle component mean that for zero modulus, we can call &lt;code&gt;forsome&lt;/code&gt; from &lt;code&gt;find&lt;/code&gt; “for free”.&lt;/p&gt;
&lt;pre class=&quot;lean&quot;&gt;&lt;code&gt;mutual
  def forsome (p : CantorPred) : Bool := p (find p)
  termination_by (p.modulus, if p.modulus = 0 then 0 else 1, 0)
  decreasing_by grind

  def find (p : CantorPred) : Cantor := fun i =&amp;gt;
    have b := forsome (p.comp_cons true)
    (b # find (p.comp_cons b)) i
  termination_by i =&amp;gt; (p.modulus, if p.modulus = 0 then 1 else 0, i)
  decreasing_by all_goals grind
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The termination proof doesn’t go through just yet: Lean is not able to see that &lt;code&gt;(_ # p) i&lt;/code&gt; will call &lt;code&gt;p&lt;/code&gt; with &lt;code&gt;i - 1&lt;/code&gt;, and it does not see that &lt;code&gt;p (find p)&lt;/code&gt; only uses &lt;code&gt;find p&lt;/code&gt; if the modulus of &lt;code&gt;p&lt;/code&gt; is non-zero. We can use the &lt;a href=&quot;https://lean-lang.org/doc/reference/latest/find/?domain=Verso.Genre.Manual.section&amp;amp;name=well-founded-preprocessing&quot;&gt;&lt;code&gt;wf_preprocess&lt;/code&gt; feature&lt;/a&gt; to tell it about that:&lt;/p&gt;
&lt;p&gt;The following theorem replaces a call to &lt;code&gt;p f&lt;/code&gt;, where &lt;code&gt;p&lt;/code&gt; is a function parameter, with the slightly more complex but provably equivalent expression on the right, where the call to &lt;code&gt;f&lt;/code&gt; is no in the &lt;code&gt;else&lt;/code&gt; branch of an &lt;code&gt;if-then-else&lt;/code&gt; and thus has &lt;code&gt;¬p.modulus = 0&lt;/code&gt; in scope:&lt;/p&gt;
&lt;pre class=&quot;lean&quot;&gt;&lt;code&gt;@[wf_preprocess]
theorem coe_wf (p : CantorPred) :
    (wfParam p) f = p (if _ : p.modulus = 0 then fun _ =&amp;gt; false else f) := by
  split
  next h =&amp;gt; apply p.eq_of_modulus_eq_0 h
  next =&amp;gt; rfl&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And similarly we replace &lt;code&gt;(_ # p) i&lt;/code&gt; with a variant that extend the context with information on how &lt;code&gt;p&lt;/code&gt; is called:&lt;/p&gt;
&lt;pre class=&quot;lean&quot;&gt;&lt;code&gt;def cantor_cons' (x : Bit) (i : Nat) (a : ∀ j, j + 1 = i → Bit) : Bit :=
  match i with
  | 0 =&amp;gt; x
  | j + 1 =&amp;gt; a j (by grind)

@[wf_preprocess] theorem cantor_cons_congr (b : Bit) (a : Cantor) (i : Nat) :
  (b # a) i = cantor_cons' b i (fun j _ =&amp;gt; a j) := by cases i &amp;lt;;&amp;gt; rfl&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After these declarations, the above definition of &lt;code&gt;forsome&lt;/code&gt; and &lt;code&gt;find&lt;/code&gt; goes through!&lt;/p&gt;
&lt;p&gt;It remains to now prove that they do what they should, by a simple induction on the modulus of &lt;code&gt;p&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;lean&quot;&gt;&lt;code&gt;@[simp, grind =] theorem tail_cons_eq (a : Cantor) : (x # a).tail = a := by
  funext i; simp [Cantor.tail, Cantor.cons]

@[simp, grind =] theorem head_cons_tail_eq (a : Cantor) : a.head # a.tail = a := by
  funext i; cases i &amp;lt;;&amp;gt; rfl

theorem find_correct (p : CantorPred) (h_exists : ∃ a, p a) : p (find p) := by
  by_cases h0 : p.modulus = 0
  · obtain ⟨a, h_a⟩ := h_exists
    rw [← h_a]
    apply p.eq_of_modulus_eq_0 h0
  · rw [find.eq_unfold, forsome.eq_unfold]
    dsimp -zeta
    extract_lets b
    change p (_ # _)
    by_cases htrue : ∃ a, p (true # a)
    next =&amp;gt;
      have := find_correct (p.comp_cons true) htrue
      grind
    next =&amp;gt;
      have : b = false := by grind
      clear_value b; subst b
      have hfalse : ∃ a, p (false # a) := by
        obtain ⟨a, h_a⟩ := h_exists
        cases h : a.head
        · exists Cantor.tail a
          grind
        · exfalso
          apply htrue
          exists Cantor.tail a
          grind
      clear h_exists
      exact find_correct (p.comp_cons false) hfalse
termination_by p.modulus
decreasing_by all_goals grind

theorem forsome_correct (p : CantorPred) :
    forsome p ↔ (∃ a, p a) where
  mp hfind := by unfold forsome at hfind; exists find p
  mpr hex := by unfold forsome; exact find_correct p hex&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is pretty nice! However there is more to do. For example, Escardo has a “massively faster” variant of &lt;code&gt;find&lt;/code&gt; that we can implement as a partial function in Lean:&lt;/p&gt;
&lt;pre class=&quot;lean&quot;&gt;&lt;code&gt;def findBit (p : Bit → Bool) : Bit :=
  if p false then false else true

def branch (x : Bit) (l r : Cantor) : Cantor :=
  fun n =&amp;gt;
    if n = 0      then x
    else if 2 ∣ n then r ((n - 2) / 2)
                  else l ((n - 1) / 2)

mutual
  partial def forsome (p : Cantor -&amp;gt; Bool) : Bool :=
    p (find p)

  partial def find (p : Cantor -&amp;gt; Bool) : Cantor :=
    let x := findBit (fun x =&amp;gt; forsome (fun l =&amp;gt; forsome (fun r =&amp;gt; p (branch x l r))))
    let l := find (fun l =&amp;gt; forsome (fun r =&amp;gt; p (branch x l r)))
    let r := find (fun r =&amp;gt; p (branch x l r))
    branch x l r
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But can we get this past Lean’s termination checker? In order to prove that the modulus of &lt;code&gt;p&lt;/code&gt; is decreasing, we’d have to know that, for example, &lt;code&gt;find (fun r =&amp;gt; p (branch x l r))&lt;/code&gt; is behaving nicely. Unforunately, it is rather hard to do termination proof for a function that relies on the behaviour of the function itself.&lt;/p&gt;
&lt;p&gt;So I’ll leave this open as a future exercise.&lt;/p&gt;
&lt;p&gt;I have dumped the code for this post at &lt;a class=&quot;uri&quot; href=&quot;https://github.com/nomeata/lean-cantor&quot;&gt;https://github.com/nomeata/lean-cantor&lt;/a&gt;.&lt;/p&gt;</description>
	<pubDate>Fri, 02 Jan 2026 14:30:24 +0000</pubDate>
	<author>mail@joachim-breitner.de (Joachim Breitner)</author>
</item>
<item>
	<title>Sandy Maguire: An Algebraic Theory of Music</title>
	<guid isPermaLink="true">https://reasonablypolymorphic.com/blog/more-algebraic-music/index.html</guid>
	<link>https://reasonablypolymorphic.com/blog/more-algebraic-music/index.html</link>
	<description>&lt;p&gt;In my last post, I was &lt;a href=&quot;https://reasonablypolymorphic.com/blog/algebraic-music/&quot;&gt;struggling towards an algebraic theory of music.&lt;/a&gt; This idea has been burning in my mind ever since, and I wanted to give some updates with where I’ve landed.&lt;/p&gt;
&lt;h2 id=&quot;differentiating-voices-from-music&quot;&gt;Differentiating Voices from Music&lt;/h2&gt;
&lt;p&gt;We begin by modeling a &lt;a href=&quot;https://en.wikipedia.org/wiki/Part_(music)#Polyphony_and_part-writing&quot;&gt;musical voice&lt;/a&gt;, which is, roughly speaking, the abstract version of a human voice. The voice can be doing one thing at a time, or can choose to not be doing anything.&lt;/p&gt;
&lt;p&gt;Voices are modeled by &lt;a href=&quot;https://hackage.haskell.org/package/step-function&quot;&gt;step functions&lt;/a&gt;, which are divisions of the real line into discrete chunks. We interpret each discrete chunk as a note being played by the voice for the duration of the chunk.&lt;/p&gt;
&lt;p&gt;This gives rise to a nice applicative structure that I alluded to in my previous post:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;liftA2 f
  |---- a ----|-- b --|
  |-- x --|---- y ----|
=
  |- fax -|fay|- fby -|&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;where we take the union of the note boundaries in order to form the applicative. If either voice is resting, so too is the applicative. There is also an &lt;code&gt;Alternative&lt;/code&gt; instance here, which chooses the first non-rest.&lt;/p&gt;
&lt;p&gt;There is a similar monoidal structure here, where multiplication is given by “play these two things simultaneously,” relying on an underlying &lt;code&gt;Semigroup&lt;/code&gt; instance for the meaning of “play these two things:”&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://reasonablypolymorphic.com#cb2-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;Semigroup&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Semigroup&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Voice&lt;/span&gt; a)&lt;/span&gt;
&lt;span id=&quot;cb2-2&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-2&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;Semigroup&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Monoid&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Voice&lt;/span&gt; a)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If either voice is resting, we treat its value as &lt;code&gt;mempty&lt;/code&gt;, and can happily combine the two parts in parallel.&lt;/p&gt;
&lt;p&gt;All of this gives rise to the following rich structure:&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://reasonablypolymorphic.com#cb3-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;Voice&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Voice&lt;/span&gt; {&lt;span class=&quot;ot&quot;&gt; unVoice ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;SF&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Time&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; a) }&lt;/span&gt;
&lt;span id=&quot;cb3-2&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb3-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; stock&lt;/span&gt;
&lt;span id=&quot;cb3-3&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb3-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&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 class=&quot;dt&quot;&gt;Functor&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Foldable&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Traversable&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Generic&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Generic1&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb3-4&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb3-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;kw&quot;&gt;newtype&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-5&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb3-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;dt&quot;&gt;Semigroup&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Monoid&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb3-6&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb3-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-7&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb3-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;Applicative&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-8&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb3-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    via &lt;span class=&quot;dt&quot;&gt;Compose&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;SF&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Time&lt;/span&gt;) &lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-9&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#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://reasonablypolymorphic.com#cb3-10&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;Filterable&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Voice&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-11&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb3-11&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;Witherable&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Voice&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-12&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb3-12&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;Alternative&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Voice&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-13&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb3-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-14&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb3-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- | Delay a voice by some amount of time.&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-15&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb3-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;delayV ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Time&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Voice&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Voice&lt;/span&gt; a&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;from-voices-to-music&quot;&gt;From Voices to Music&lt;/h2&gt;
&lt;p&gt;Voices, therefore, give us our primitive notion of monophony. But real music usually has many voices doing many things, independently. This was a point in which I got stuck in my previous post.&lt;/p&gt;
&lt;p&gt;The solution here, is surprisingly easy. Assign a &lt;code&gt;Voice&lt;/code&gt; to each voice name:&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://reasonablypolymorphic.com#cb4-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;Music&lt;/span&gt; v a &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Music&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-2&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb4-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  {&lt;span class=&quot;ot&quot;&gt; getVoices ::&lt;/span&gt; v &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Voice&lt;/span&gt; a&lt;/span&gt;
&lt;span id=&quot;cb4-3&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb4-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  }&lt;/span&gt;
&lt;span id=&quot;cb4-4&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb4-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; stock&lt;/span&gt;
&lt;span id=&quot;cb4-5&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb4-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;dt&quot;&gt;Functor&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Generic&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Functor&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb4-6&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb4-6&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;newtype&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-7&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb4-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;dt&quot;&gt;Semigroup&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Monoid&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb4-8&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb4-8&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;Applicative&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Alternative&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb4-9&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb4-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    via &lt;span class=&quot;dt&quot;&gt;Compose&lt;/span&gt; ((&lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;) v) &lt;span class=&quot;dt&quot;&gt;Voice&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-10&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#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://reasonablypolymorphic.com#cb4-11&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;Profunctor&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Music&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-12&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb4-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-13&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb4-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;Finite&lt;/span&gt; v &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Foldable&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Music&lt;/span&gt; v)&lt;/span&gt;
&lt;span id=&quot;cb4-14&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb4-14&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;Finite&lt;/span&gt; v &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Traversable&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Music&lt;/span&gt; v)&lt;/span&gt;
&lt;span id=&quot;cb4-15&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb4-15&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;Filterable&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Music&lt;/span&gt; v)&lt;/span&gt;
&lt;span id=&quot;cb4-16&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb4-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;Finite&lt;/span&gt; v &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Witherable&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Music&lt;/span&gt; v)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We get an extremely rich structure here completely for free. Our monoid combines all voices in parallel; our applicative combines voices pointwise; etc. However, we also have a new &lt;code&gt;Profunctor Music&lt;/code&gt; instance, whose characteristic &lt;code&gt;lmap :: (b -&amp;gt; c) -&amp;gt; Music c a -&amp;gt; Music b a&lt;/code&gt; method allows us to trade lines between voices.&lt;/p&gt;
&lt;p&gt;In addition to the &lt;em&gt;in-parallel&lt;/em&gt; monoid instance, we can also define a &lt;a href=&quot;https://dl.acm.org/doi/10.1145/2633638.2633649&quot;&gt;tile product&lt;/a&gt; operator over &lt;code&gt;Music v a&lt;/code&gt;, which composes things sequentially&lt;a class=&quot;footnote-ref&quot; href=&quot;https://reasonablypolymorphic.com#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;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://reasonablypolymorphic.com#cb5-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;duration ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Music&lt;/span&gt; v a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Time&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-2&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#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;https://reasonablypolymorphic.com#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;dt&quot;&gt;Semigroup&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Music&lt;/span&gt; v a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Music&lt;/span&gt; v a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Music&lt;/span&gt; v a&lt;/span&gt;
&lt;span id=&quot;cb5-4&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb5-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;m&lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;(&lt;span class=&quot;dt&quot;&gt;Music&lt;/span&gt; m1) &lt;span class=&quot;op&quot;&gt;##&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Music&lt;/span&gt; m2 &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;https://reasonablypolymorphic.com#cb5-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;Music&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; liftA2 (&lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt;) m1 &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fmap&lt;/span&gt; (delayV &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; duration m) m2&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;Semigroup a&lt;/code&gt; constraint on &lt;code&gt;(##)&lt;/code&gt; arises from the fact that the pieces of music might extend off to infinity in either direction (which &lt;code&gt;pure @Voice&lt;/code&gt; must do), and we need to deal with that.&lt;/p&gt;
&lt;p&gt;There are a few other combinators we care about. First, we can lift anonymous voices (colloquially “tunes”) into multi-part &lt;code&gt;Music&lt;/code&gt;:&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://reasonablypolymorphic.com#cb6-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;voice ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt; v &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;Music&lt;/span&gt; () a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Music&lt;/span&gt; v a&lt;/span&gt;
&lt;span id=&quot;cb6-2&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb6-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;voice v (&lt;span class=&quot;dt&quot;&gt;Music&lt;/span&gt; sf) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Music&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-3&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb6-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-4&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb6-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ((&lt;span class=&quot;op&quot;&gt;==&lt;/span&gt; v) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&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; sf ()&lt;/span&gt;
&lt;span id=&quot;cb6-5&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb6-5&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;mempty&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and we can assign the same line to everyone:&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://reasonablypolymorphic.com#cb7-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;everyone ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Music&lt;/span&gt; () a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Music&lt;/span&gt; v a&lt;/span&gt;
&lt;span id=&quot;cb7-2&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb7-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;everyone (&lt;span class=&quot;dt&quot;&gt;Music&lt;/span&gt; m) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Music&lt;/span&gt; &lt;span class=&quot;op&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; m ()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;writing-lines&quot;&gt;Writing Lines&lt;/h2&gt;
&lt;p&gt;The primitives for building little tunes are&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://reasonablypolymorphic.com#cb8-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;note ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Time&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;Music&lt;/span&gt; () a&lt;/span&gt;
&lt;span id=&quot;cb8-2&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb8-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;rest ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Time&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Music&lt;/span&gt; () a&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;which you can then compose sequentially via &lt;code&gt;(##)&lt;/code&gt;, and assign to voices via &lt;code&gt;voice&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;harmonic-constraints&quot;&gt;Harmonic Constraints&lt;/h2&gt;
&lt;p&gt;One of the better responses to my last blog post was a link to &lt;a href=&quot;https://dmitri.mycpanel.princeton.edu/index.html&quot;&gt;Dmitri Tymoczko&lt;/a&gt;’s &lt;a href=&quot;https://www.youtube.com/watch?v=yp5Eys2L_04&quot;&gt;FARM 2024 talk&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There’s much more in this video than I can possibly due justice to here, but my big takeaway was that this guy is thinking about the same sorts of things that I am. So I dove into his work, and that lead to his &lt;a href=&quot;https://www.madmusicalscience.com/quadruple.mp4&quot;&gt;quadruple hierarchy&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Voices move within chords, which move within scales, which move within macro-harmonies.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Tymoczko presents a &lt;code&gt;T&lt;/code&gt; algebra which is a geometric space for reasoning about voice leadings. He’s got a lot of fun websites for exploring the ideas, but I couldn’t find an actual implementation of the idea anywhere, so I &lt;a href=&quot;https://github.com/isovector/denomusic/blob/6a313a546cc376bb22f37cec55d76518bff40acd/src/DenoMusic/Harmony.hs&quot;&gt;cooked one up&lt;/a&gt; myself.&lt;/p&gt;
&lt;p&gt;The idea here is that we have some &lt;code&gt;T :: [Nat] -&amp;gt; Type&lt;/code&gt; which describes a hierarchy of abstract scales moving with respect to one another. For example, the Western traditional of having triads move within the diatonic scale, which moves within the chromatic scale, would be represented as &lt;code&gt;T '[3, 7, 12]&lt;/code&gt;. &lt;code&gt;T&lt;/code&gt; forms a monoid, and has some simple generators that give rise to smooth voice leadings (chord changes.)&lt;/p&gt;
&lt;p&gt;Having a model for smooth harmonic transformations means we can use it constructively. I am still working out the exact details here, but the rough shape of the idea is to build an underlying field of key changes (represented as smooth voice leadings in &lt;code&gt;T '[7, 12]&lt;/code&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://reasonablypolymorphic.com#cb9-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;keyChanges ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Music&lt;/span&gt; () (&lt;span class=&quot;dt&quot;&gt;T&lt;/span&gt; '[&lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;, &lt;span class=&quot;dv&quot;&gt;12&lt;/span&gt;])&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can then make an underlying field of functional harmonic changes (chord changes), modeled as smooth voice leadings in &lt;code&gt;T '[3, 7]&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;https://reasonablypolymorphic.com#cb10-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;chordChanges ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Music&lt;/span&gt; () (&lt;span class=&quot;dt&quot;&gt;T&lt;/span&gt; '[&lt;span class=&quot;dv&quot;&gt;3&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;Our voices responsible for harmony can now be written as values of type&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://reasonablypolymorphic.com#cb11-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;harmonicVoices ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Music&lt;/span&gt; h (&lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;T&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;and we can use the applicative musical structure to combine the elements together:&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://reasonablypolymorphic.com#cb12-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE ApplicativeDo #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-2&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#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;https://reasonablypolymorphic.com#cb12-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;extend ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;T&lt;/span&gt; ns &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;T&lt;/span&gt; (ns &lt;span class=&quot;op&quot;&gt;++&lt;/span&gt; ms)&lt;/span&gt;
&lt;span id=&quot;cb12-4&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb12-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;sink   ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;T&lt;/span&gt; ns &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;T&lt;/span&gt; (n '&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; ns)&lt;/span&gt;
&lt;span id=&quot;cb12-5&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb12-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-6&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb12-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;harmony ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Music&lt;/span&gt; h (&lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;T&lt;/span&gt; '[&lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;, &lt;span class=&quot;dv&quot;&gt;12&lt;/span&gt;]))&lt;/span&gt;
&lt;span id=&quot;cb12-7&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb12-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;harmony &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;cb12-8&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb12-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  k &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; everyone keyChanges&lt;/span&gt;
&lt;span id=&quot;cb12-9&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb12-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  c &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; everyone chordChanges&lt;/span&gt;
&lt;span id=&quot;cb12-10&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb12-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  m &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; harmonicVoices&lt;/span&gt;
&lt;span id=&quot;cb12-11&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb12-11&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; extend m &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; extend c &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; sink k&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;which we can later &lt;code&gt;fmap&lt;/code&gt; out into concrete pitches. The result is that we can completely isolate the following pieces:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;key changes&lt;/li&gt;
&lt;li&gt;chord changes&lt;/li&gt;
&lt;li&gt;how voices express the current harmony&lt;/li&gt;
&lt;li&gt;the rhythms of all of the above&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;and the result is guaranteed to compose in a way that the ear can interpret as music. Not necessarily &lt;em&gt;good music,&lt;/em&gt; but undeniably as &lt;em&gt;music.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The type indices on &lt;code&gt;T&lt;/code&gt; are purely for my book-keeping, and nothing requires them to be there. Which means we could also use the applicative structure to modulate over different sorts of harmony (eg, move from triads to seventh chords.)&lt;/p&gt;
&lt;h2 id=&quot;melody-still-an-open-question&quot;&gt;Melody: Still an Open Question&lt;/h2&gt;
&lt;p&gt;I haven’t quite gotten a feel for melody yet; I think it’s probably in &lt;code&gt;T '[7, 12]&lt;/code&gt;, but it would be nice to be able to target chord tones as well. Please let me know in the comments if you have any insight here.&lt;/p&gt;
&lt;p&gt;However, I have been thinking about contouring, which is the overall “shape” of a musical line. Does it go up, and peak in the middle, and then come down again? Or maybe it smoothly descends down.&lt;/p&gt;
&lt;p&gt;We can use the discrete intervals intrinsic inside of &lt;code&gt;Voice&lt;/code&gt;s to find “reasonable” times to sample them. In essence this assigns a &lt;code&gt;Time&lt;/code&gt; to each segment:&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://reasonablypolymorphic.com#cb13-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;timed ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Music&lt;/span&gt; v a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Music&lt;/span&gt; v (&lt;span class=&quot;dt&quot;&gt;Time&lt;/span&gt;, a)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and we can then use these times to then sample a function &lt;code&gt;Time -&amp;gt; b&lt;/code&gt;. This then allows us to apply contours (given as regular &lt;code&gt;Real -&amp;gt; Real&lt;/code&gt; functions) to arbitrary rhythms. I currently have this typed as&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://reasonablypolymorphic.com#cb14-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;contour ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Group&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;Real&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Real&lt;/span&gt;) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Music&lt;/span&gt; v () &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Music&lt;/span&gt; v a&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;where &lt;code&gt;a ~ T something&lt;/code&gt;, and the outputted &lt;code&gt;Real&lt;/code&gt;s get rounded to their nearest integer values. I’m not deeply in love with this type, but the rough idea is great—turn arbitrary real-valued functions into musical lines. This generalizes contouring, as well as scale runs.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot;&gt;Next Steps?&lt;/h2&gt;
&lt;p&gt;I’m writing all of this up because I go back to work on Monday and life is going to get very busy soon. I’m afraid I won’t be able to finish all of this!&lt;/p&gt;
&lt;p&gt;The types above I’m pretty certain are relatively close to perfect. They seem to capture everything I could possibly want, and nothing I don’t want. Assuming I’m right about that, they must make up the basis of musical composition.&lt;/p&gt;
&lt;p&gt;The next step therefore is to build musical combinators on top. One particular combinator I’ve got my eye on is some sort of general &lt;code&gt;~&amp;gt;&lt;/code&gt; “get from here to there” operator:&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;https://reasonablypolymorphic.com#cb15-1&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;Semigroup&lt;/span&gt; a, &lt;span class=&quot;op&quot;&gt;???&lt;/span&gt;) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Music&lt;/span&gt; v a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Music&lt;/span&gt; v a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Music&lt;/span&gt; v a&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;which I imagine would bridge a gap between the end of one piece of music with beginning of another. I think this would be roughly as easy as moving each voice linearly in &lt;code&gt;T&lt;/code&gt; space from where it was to where it needs to be. This might need to be a ternary operation in order to also associate a rhythmic pattern to use for the bridge.&lt;/p&gt;
&lt;p&gt;But I imagine &lt;code&gt;(~&amp;gt;)&lt;/code&gt; would be great for lots of dumb little musical things. Like when applied over the chord dimension, it would generate arpeggios. Over the scale dimension, it would generate runs. And it would make chromatic moves in the chroma dimension.&lt;/p&gt;
&lt;p&gt;Choosing exactly what moves to make for &lt;code&gt;T&lt;/code&gt;s consisting of components in multiple axes might just be some bespoke order, or could do something more intelligent. I think the right approach would be to steal &lt;code&gt;diagrams&lt;/code&gt;’ idea of an &lt;code&gt;Envelope&lt;/code&gt;, and attach some relevant metadata to each &lt;code&gt;Music&lt;/code&gt;. We could then write &lt;code&gt;(~&amp;gt;)&lt;/code&gt; as a function of those envelopes, but I must admit I don’t quite know what this would look like.&lt;/p&gt;
&lt;p&gt;As usual, I’d love any insight you have! Please leave it in the comments. Although I must admit I appreciate comments of the form “have you tried $X” much more than of the form “music is sublime and you’re an idiot for even trying this.”&lt;/p&gt;
&lt;p&gt;Happy new year!&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;Strictly speaking, the tile product can also do parallel composition, as well as sychronizing composition, but that’s not super important right now.&lt;a class=&quot;footnote-back&quot; href=&quot;https://reasonablypolymorphic.com#fnref1&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
	<pubDate>Fri, 02 Jan 2026 14:27:00 +0000</pubDate>
</item>
<item>
	<title>Chung-chieh Shan: A challenge for a better community</title>
	<guid isPermaLink="true">http://conway.rutgers.edu/~ccshan/wiki/blog/posts/lambda4ada/</guid>
	<link>http://conway.rutgers.edu/~ccshan/wiki/blog/posts/lambda4ada/</link>
	<description>&lt;p&gt;&lt;a href=&quot;https://supportada.org/?campaign=lambda&quot;&gt;&lt;img alt=&quot;Donation button&quot; height=&quot;54&quot; src=&quot;https://adainitiative.org/wp-content/uploads/2014/08/donate_red_small.png&quot; width=&quot;185&quot; /&gt;&lt;br /&gt;
&lt;img alt=&quot;Donate to the Ada Initiative&quot; src=&quot;https://adainitiative.org/counters/2014counter-lambda.svg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Did you know that all ACM-sponsored conferences have an &lt;a href=&quot;http://www.acm.org/sigs/volunteer_resources/officers_manual/anti-harassment-policy&quot;&gt;
anti-harassment policy&lt;/a&gt;? I didn’t, until I chaired the Haskell
Symposium last year. The concise policy says, among other things,
that people shouldn’t use my family constitution to interfere with
my professional participation. And the policy has teeth. That’s
great.&lt;/p&gt;
&lt;p&gt;My not knowing the policy and not seeing it publicized didn’t
make me go out of my way to harass anyone. But it did make me less
sure and less comfortable that I belonged at ICFP. Briefly, it’s
because I didn’t know if it would be common ground at the
conference that my actual self was fully human. That’s not
something I can take for granted in general society. Also, it’s
because I didn’t know whether my fellow conference attendees were
aware of the policy. We could all use a reminder, and a public
signal that we mean it.&lt;/p&gt;
&lt;p&gt;For these reasons, I’m very happy that ICFP will start to
publicize ACM’s existing anti-harassment policy and make sure
everyone registered knows it. All ACM conferences should do it.
That’s why &lt;a href=&quot;http://tim.dreamwidth.org/1856739.html&quot;&gt;Tim
Chevalier&lt;/a&gt;, &lt;a href=&quot;http://blog.clement.delafargue.name/posts/2014-09-13-of-conferences-and-cocs.html&quot;&gt;
Clement Delafargue&lt;/a&gt;, &lt;a href=&quot;http://tim.dreamwidth.org/1856828.html&quot;&gt;Adam Foltzer&lt;/a&gt;, Eric
Merritt, and I are doing two things. We ask you to join us:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Donate to the Ada Initiative. Our goal is for the functional
programming community to raise $4096 by the end of Friday (Sept 19)
UTC. To count toward this goal, please use this link: &lt;a href=&quot;http://supportada.org/?campaign=lambda&quot;&gt;http://supportada.org/?campaign=lambda&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Call on the ACM and tell your friends. For example, I tweeted
this:&lt;br /&gt;
I donate to &lt;a href=&quot;http://twitter.com/AdaInitiative&quot;&gt;@AdaInitiative&lt;/a&gt; because I
want &lt;a href=&quot;http://twitter.com/TheOfficialACM&quot;&gt;@TheOfficialACM&lt;/a&gt; events to
announce their anti-harassment policy &lt;a href=&quot;http://supportada.org/?campaign=lambda&quot;&gt;http://supportada.org/?campaign=lambda&lt;/a&gt;
&lt;a href=&quot;http://twitter.com/hashtag/lambda4ada?src=hash&quot;&gt;#lambda4ada&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Thanks for improving our professional homes!&lt;/p&gt;</description>
	<pubDate>Thu, 01 Jan 2026 07:11:17 +0000</pubDate>
</item>
<item>
	<title>Chung-chieh Shan: Borderline, just semantics</title>
	<guid isPermaLink="true">http://conway.rutgers.edu/~ccshan/wiki/blog/posts/Borderline/</guid>
	<link>http://conway.rutgers.edu/~ccshan/wiki/blog/posts/Borderline/</link>
	<description>&lt;p&gt;&lt;a href=&quot;http://hyperbolic-crochet.blogspot.com/2012/08/bill-thurston-1946-2012.html&quot;&gt;
&lt;img align=&quot;right&quot; src=&quot;http://1.bp.blogspot.com/-kRjyJlu7hdo/UDT7DCy9Q3I/AAAAAAAACeE/j485hiluBF8/s1600/fig8.jpg&quot; width=&quot;40%&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I want to discuss two moral aspects of how to talk about
borderline people (e.g., whether to say “MTF” or “female”, “smart”
or “good at math”).&lt;/p&gt;
&lt;p&gt;The first aspect is what category of people we should be talking
about, never mind how we talk about it. Usually, for a given
category C, there are many ways to be borderline C: people can
be&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;borderline female due to a lack of chromosomes or a lack of
genitals;&lt;/li&gt;
&lt;li&gt;borderline smart because they keep exchanging quantifiers or
because they keep estranging family;&lt;/li&gt;
&lt;li&gt;borderline safe because they drive over the speed limit or roll
their bike past a stop sign;&lt;/li&gt;
&lt;li&gt;borderline documented because they burned their passport,
overstayed their visa, or came from an unrecognized “country”.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Of course, it is easy enough to construct a category C’ that
firmly includes or excludes particular kinds of borderline Cs
(e.g., you are female’ iff you have XX chromosomes), if only to
leave unresolved lower-dimensional borderlines (e.g., what if only
half of your cells have XX chromosomes). So let’s ask not what
categories exist (because they all do) but what categories we
should talk about.&lt;/p&gt;
&lt;p&gt;It might well be that we should talk about different versions of
C for different purposes (e.g., medicine, sports, identification,
love). It might also be that delineating categories at their edges
is not usually worth our collective cognitive trouble. Regardless,
sometimes in conversation or other collaboration I find that
multiple versions are actually relevant. For example, some people
wonder whether to call a transgender person “male” or “female”, and
I think a transgender person can &lt;em&gt;firmly&lt;/em&gt; belong to a gender
category that we should talk about. Unfortunately, when I tried to
work with others to distinguish and choose among versions of
categories, I have often been frustrated.&lt;/p&gt;
&lt;p&gt;When people in power to classify others don’t take the effort to
apply the right category version, the misclassified people can get
slighted. I empathize with the misclassified people because I have
been misclassified. For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I don’t need a passport to travel internationally, though I do
need a passport number.&lt;/li&gt;
&lt;li&gt;I am a computer scientist, though I can’t fix your
computer.&lt;/li&gt;
&lt;li&gt;I am from Taiwan, though I don’t speak Taiwanese.&lt;/li&gt;
&lt;li&gt;I am from the United States, though I’m not a United States
citizen.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Also because I have been misclassified, this discussion of
borderlines matters for me practically and personally. It’s not
just abstract theorizing.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;not-passport.jpg&quot; src=&quot;http://conway.rutgers.edu/~ccshan/wiki/blog/tags/english/../../posts/Borderline/not-passport.jpg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The second aspect is how to name a given category (version).
Even in a context where we agree intellectually that there is
exactly one gender category we should talk about (say “female”) and
a transgender person belongs to it firmly, the term “female” still
takes many people today more thought to produce and comprehend when
applied to a person known to be transgender than when applied to a
person known to be cisgender. So, it is tempting for a well-meaning
speaker to avoid gender categories altogether by terming a
transgender person “female-presenting” instead. The
“female-presenting” characterization&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;is certainly true,&lt;/li&gt;
&lt;li&gt;but may be a cop-out because it
&lt;ul&gt;
&lt;li&gt;perpetuates the implicature that the person doesn’t quite
belong&lt;/li&gt;
&lt;li&gt;and increases their work to counter misclassification,&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;yet may be justifiable (perhaps in some strain of
utilitarianism), though a justification remains to be spelled out
and applied uniformly to all instances.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Your thoughts?&lt;/p&gt;</description>
	<pubDate>Thu, 01 Jan 2026 07:11:17 +0000</pubDate>
</item>
<item>
	<title>Chung-chieh Shan: Babel-17</title>
	<guid isPermaLink="true">http://conway.rutgers.edu/~ccshan/wiki/blog/posts/Babel-17/</guid>
	<link>http://conway.rutgers.edu/~ccshan/wiki/blog/posts/Babel-17/</link>
	<description>&lt;p&gt;“Show me.”&lt;/p&gt;
&lt;p&gt;He bowed his head in mocking, semi-formal acquiescence. “Modern
warfare can be fought on so many delightfully different levels,” he
continued, walking back to her side as if no interruption of the
tour had been suggested. “One wins a battle by making sure one’s
troops have enough blunderbusses and battle axes like the ones you
saw in the first room; or by the well-placed six-inch length of
vanadium wire in a Type 27-QX communications unit. With the proper
orders delayed, the encounter never takes place. Hand-to-hand
weapons, survival kit, plus training, room, and board: three
thousand credits per enlisted stellarman over a period of two years
active duty. For a garrison of fifteen hundred men that’s an outlay
of four million, five hundred credits. That same garrison will live
in and fight from three hyperstasis battleships which, fully
equipped, run about a million and a half credits apiece—a total
outlay of nine million credits. We have spent, on occasion, perhaps
as much as a million on the preparation of a single spy or
saboteur. That is rather higher than usual. And I can’t believe a
six-inch length of vanadium wire costs a third of a cent. War is
costly. And although it has taken some time, Administrative
Alliance Headquarters is beginning to realize subtlety pays. This
way, Miss—Captain Wong.”&lt;/p&gt;
&lt;p&gt;Again they were in a room with only a single display case, but
it was seven feet high.&lt;/p&gt;
&lt;p&gt;A statue, Rydra thought. No, real flesh, with detail of muscle
and joint; no, it must be a statue because a human body, dead or in
suspended animation, doesn’t look that… alive. Only art could
produce that vibrancy.&lt;/p&gt;
&lt;p&gt;“So you see, the proper spy is very important.” Though the door
had opened automatically, the Baron held it with his hand in
vestigial politeness. “This is one of our more expensive models.
Still well under a million credits, but one of my favorites—though
in practice he has his faults. With a few minor alterations I would
like to make him a permanent part of our arsenal.”&lt;/p&gt;
&lt;p&gt;“A model of a spy?” Rydra asked. “Some sort of robot or
android?”&lt;/p&gt;
&lt;p&gt;“Not at all.” They approached the display case. “We made half a
dozen TW-55’s. It took the most exacting genetic search. Medical
science has progressed so that all sorts of hopeless human refuse
lives and reproduces at a frightening rate—inferior creatures that
would have been too weak to survive a handful of centuries ago. We
chose our parents carefully, and then with artificial insemination
we got our half dozen zygotes, three male, three female. We raised
them in, oh, such a carefully controlled nutrient environment,
speeding the growth rate by hormones and other things. But the
beauty of it was the experiential imprinting. Gorgeously healthy
creatures; you have no idea how much care they received.”&lt;/p&gt;
&lt;p&gt;“I once spent a summer on a cattle farm,” Rydra said
shortly.&lt;/p&gt;
&lt;p&gt;The Baron’s nod was brisk. “We’d used the experiential imprints
before, so we knew what we were doing. But never to synthesize
completely the life situation of, say, a sixteen-year-old human.
Sixteen was the physiological age we brought them to in six months.
Look for yourself what a splendid specimen it is. The reflexes are
fifty percent above those of a human aged normally. Human
musculature is beautifully engineered: a three-day-starved,
six-month-atrophied myasthenia gravis case, can, with the proper
stimulant drugs, overturn a ton-and-a-half automobile. It will kill
him—but that’s still remarkable efficiency. Think what the
biologically perfect body, operating at all times at point
nine-nine efficiency, could accomplish in physical strength
alone.”&lt;/p&gt;
&lt;p&gt;“I thought hormone growth incentive had been outlawed. Doesn’t
it reduce the life span some drastic amount?”&lt;/p&gt;
&lt;p&gt;“To the extent we used it, the life span reduction is
seventy-five percent and over.” He might have smiled the same way
watching some odd animal at its incomprehensible antics. “But,
Madam, we are making weapons. If TW-55 can function twenty years at
peak efficiency, then it will have outlasted the average battle
cruiser by five years. But the experiential imprinting! To find
among ordinary men someone who can function as a spy, is willing to
function as a spy, you must search the fringes of neurosis, often
psychosis. Though such deviations might mean strength in a
particular area, it always means an overall weakness in the
personality. Functioning in any but that particular area, a spy may
be dangerously inefficient. And the Invaders have psyche-indices
too, which will keep the average spy out of anyplace we might want
to put him. Captured, a good spy is a dozen times as dangerous as a
bad one. Post-hypnotic suicide suggestions and the like are easily
gotten around with drugs; and are wasteful. TW-55 here will
register perfectly normal on a psyche integration. He has about six
hours of social conversation, plot synopses of the latest novels,
political situations, music, and art criticism—l believe in the
course of an evening he is programmed to drop your name twice, an
honor you share only with Ronald Quar. He has one subject on which
he can expound with scholarly acumen for an hour and a half—this
one, I believe, is ‘haptoglobin groupings among the marsupials.’
Put him in formal wear and he will be perfectly at home at an
ambassadorial ball or a coffee break at a high-level government
conference. He is a crack assassin, expert with all the weapons you
have seen up till now, and more. TW-55 has twelve hours’ worth of
episodes in fourteen different dialects, accents, or jargons
concerning sexual conquests, gambling experiences, fisticuff
encounters, and humorous anecdotes of semi-illegal enterprises, all
of which failed miserably. Tear his shirt, smear grease on his face
and slip a pair of overalls on him, and he could be a service
mechanic on any one of a hundred spaceyards or stellarcenters on
the other side of the Snap. He can disable any space drive system,
communications components, radar works, or alarm system used by the
Invaders in the past twenty years with little more than—”&lt;/p&gt;
&lt;p&gt;“Six inches of vanadium wire?”&lt;/p&gt;
&lt;p&gt;The Baron smiled. “His fingerprints and retina pattern, he can
alter at will. A little neural surgery has made all the muscles of
his face voluntary, which means he can alter his facial structure
drastically. Chemical dyes and hormone banks beneath the scalp
enable him to color his hair in seconds, or, if necessary, shed it
completely and grow a new batch in half an hour. He’s a past master
in the psychology and physiology of coercion.”&lt;/p&gt;
&lt;p&gt;“Torture?”&lt;/p&gt;
&lt;p&gt;“If you will. He is totally obedient to the people whom he has
been conditioned to regard as his superiors; totally destructive
toward what he has been ordered to destroy. There is nothing in
that beautiful head even akin to a superego.”&lt;/p&gt;
&lt;p&gt;“He is…” and she wondered at herself speaking, “beautiful.” The
dark-lashed eyes with lids about to quiver open, the broad hands
hung at the naked thighs, fingers half-curled, about to straighten
or become a fist. The display light was misty on the tanned, yet
near-translucent skin. “You say this isn’t a model, but really
alive?”&lt;/p&gt;
&lt;p&gt;“Oh, more or less. But it’s rather firmly fixed in something
like a yoga trance, or a lizard’s hibernation. I could activate it
for you—but it’s ten to seven. We don’t want to keep the others
waiting at the table now, do we?”&lt;/p&gt;
&lt;p&gt;She looked away from the figure in glass to the dull, taut skin
of the Baron’s face. His jaw, beneath his faintly concave cheek,
was involuntarily working on its hinge.&lt;/p&gt;
&lt;p&gt;(from &lt;em&gt;Babel-17&lt;/em&gt; by Samuel R. Delany)&lt;/p&gt;</description>
	<pubDate>Thu, 01 Jan 2026 07:11:17 +0000</pubDate>
</item>
<item>
	<title>Monday Morning Haskell: Parsing with an MCAP Index</title>
	<guid isPermaLink="false">584219d403596e3099e0ee9b:58462c0e15d5db6feba171c0:68e2d55b4d325815f97c2786</guid>
	<link>https://mmhaskell.com/blog/2025/12/29/parsing-with-an-mcap-index</link>
	<description>&lt;p&gt;Welcome to the sixth and final part of our series on MCAP parsing. In the first four parts, we did all the work to parse certain topic messages from a bag file, going through the file sequentially. In the &lt;a href=&quot;https://mmhaskell.com/blog/2025/12/22/mcap-indexing&quot;&gt;fifth part&lt;/a&gt;, we set up a lot of infrastructure to allow ourselves to instead parse the file using &lt;strong&gt;indexing&lt;/strong&gt; so we can get our messages faster. In this part, we’ll finish the process and see how much faster our code is!&lt;/p&gt;
&lt;p&gt;This series has combined a lot of ideas from several of our online courses. You can learn more about complex monad structures in &lt;a href=&quot;https://academy.mondaymorninghaskell.com/p/making-sense-of-monads&quot;&gt;Making Sense of Monads&lt;/a&gt; or &lt;a href=&quot;https://academy.mondaymorninghaskell.com/p/effectful-haskell&quot;&gt;Effectful Haskell&lt;/a&gt;. You can learn more about parsing in &lt;a href=&quot;https://academy.mondaymorninghaskell.com/p/solve-hs&quot;&gt;Solve.hs&lt;/a&gt;. You can get lifetime access to all our courses buy purchasing &lt;a href=&quot;https://academy.mondaymorninghaskell.com/p/mmh-complete&quot;&gt;MMH Complete&lt;/a&gt;!&lt;/p&gt;
&lt;h2&gt;The Plan&lt;/h2&gt;
&lt;p&gt;Let’s recap the most important items from the &lt;a href=&quot;https://mmhaskell.com/blog/2025/12/22/mcap-indexing&quot;&gt;last part&lt;/a&gt; and go over our plan again. We defined a series of types to help us represent various record types, and parsers for them:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;data FooterRec = ...
parseFooter’ :: parseFooter' :: (MonadParsec Void ByteString m) =&amp;gt; m (Word64, FooterRec)

data SummaryOffsetRec = ...
parseSummaryOffset :: (MonadFail m, MonadParsec Void ByteString m) =&amp;gt; m (Word64, SummaryOffsetRec)

data ChunkIndexRec = ...
parseChunkIndex :: (MonadFail m, MonadParsec Void ByteString m) =&amp;gt; m (Word64, ChunkIndexRec)

data MessageIndexRec = ...
parseMessageIndex' :: (MonadFail m, MonadParsec Void ByteString m) =&amp;gt; m (Word64, MessageIndexRec)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We also defined a couple monad structures to capture our parser’s state:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;data TopicState = TopicState
  { tsChannels :: HM.HashMap Word16 MsgChannel
  , tsSchemas :: HM.HashMap Word16 MsgSchema
  , tsMessages :: HM.HashMap (ByteString, ByteString) [MessageData]
  , tsDesiredTopics :: HS.HashSet ByteString
  , tsDesiredChannels :: HS.HashSet Word16
  } deriving (Show)

type MCAPReader a = StateT TopicState (ReaderT Handle (ExceptT ValidationError IO)) a
type MCAPParser a = ParsecT Void ByteString (StateT TopicState (ReaderT Handle (ExceptT ValidationError IO)))  a&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, we defined a series of utility functions on these monads:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;seek :: Integer -&amp;gt; MCAPReader ()
curPos :: MCAPReader Integer
mcapGuard :: String -&amp;gt; Bool -&amp;gt; MCAPReader ()
runMCAPParser :: MCAPParser (Word64, a) -&amp;gt; ByteString -&amp;gt; MCAPReader (Word64, a)
parseNextRecord :: RecordType -&amp;gt; MCAPParser (Word64, a) -&amp;gt; MCAPReader (Word64, a)
parseNextRecord' :: RecordType -&amp;gt; (Word64 -&amp;gt; MCAPParser (Word64, a)) -&amp;gt; MCAPReader (Word64, a)
runMCAPReader :: Handle -&amp;gt; TopicState -&amp;gt; MCAPReader a -&amp;gt; IO (Either ValidationError TopicState)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our overall plan is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Parse the footer and use its data to jump to the start of the summary offset section&lt;/li&gt;
&lt;li&gt;Parse summary offsets for schemas, channels, and chunk indexes&lt;/li&gt;
&lt;li&gt;Parse summary records for schemas and channels to load them into &lt;code&gt;TopicState&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Process chunk indexes, which direct us to message index records for our desired channels&lt;/li&gt;
&lt;li&gt;Process message indexes, which point us to individual messages for our desired topics&lt;/li&gt;
&lt;li&gt;Parse the messages into our Topic State&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let’s get started!&lt;/p&gt;
&lt;h2&gt;Step 1 - Parsing the Footer&lt;/h2&gt;
&lt;p&gt;Our entrypoint for the &lt;code&gt;MCAPReader&lt;/code&gt; monad will be a function called &lt;code&gt;parseUsingIndex&lt;/code&gt; (we’ll see how to enter this function later).&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;parseUsingIndex :: MCAPReader ()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first order of business is to seek to the Footer’s location so we can parse the Footer record. The Footer has a fixed size and it is always the last record before the 8 “magic bytes” that conclude the file. This size is 29 bytes: 1 byte for the op code (record type), 8 bytes to define the content size, and 20 bytes for the 3 fields (&lt;code&gt;Word64&lt;/code&gt;, &lt;code&gt;Word64&lt;/code&gt;, &lt;code&gt;Word32&lt;/code&gt;). Combined with the magic bytes, this means we want to find the file size and seek to 37 bytes before it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;parseUsingIndex :: MCAPReader ()
parseUsingIndex = do
  footerStart &amp;lt;- seekToFooterStart
  ...
  where
    seekToFooterStart = do
      hndl &amp;lt;- ask
      sz &amp;lt;- liftIO $ hFileSize hndl
      seek (sz - 37)
      curPos&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we use &lt;code&gt;parseNextRecord&lt;/code&gt; and &lt;code&gt;parseFooter’&lt;/code&gt; to get the Footer’s data, which includes the start of the summary offset section. We unpack this value and seek to its location:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;parseUsingIndex :: MCAPReader ()
parseUsingIndex = do
  footerStart &amp;lt;- seekToFooterStart
  (_, FooterRec summStart summOffStart _) &amp;lt;- parseNextRecord FileFooter parseFooter'
  seek (fromIntegral summOffStart)
  ...
  where
    seekToFooterStart = do
      hndl &amp;lt;- ask
      sz &amp;lt;- liftIO $ hFileSize hndl
      seek (sz - 37)
      curPos&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we’re ready for step 2!&lt;/p&gt;
&lt;h2&gt;Step 2 - Parsing Summary Offsets&lt;/h2&gt;
&lt;p&gt;Recall that records in the summary section are grouped in blocks, and each summary offset record leads us to the start of the block for a particular op code. We’re interested in the summary records for schemas, channels and chunk indexes. So we want to keep parsing summary offsets until we have all three of these.&lt;/p&gt;
&lt;p&gt;So we’ll build a helper function that will construct a map from op codes to summary offset records, but also track booleans for which of our desired types we’ve seen. This function also needs to track the number of bytes remaining in the summary offset section:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;parseUsingIndex :: MCAPReader ()
parseUsingIndex = do
  footerStart &amp;lt;- seekToFooterStart
  (_, FooterRec summStart summOffStart _) &amp;lt;- parseNextRecord FileFooter parseFooter'
  seek (fromIntegral summOffStart)
  ...
  where
    parseSummaryOffsets :: Word64 -&amp;gt; Bool -&amp;gt; Bool -&amp;gt; Bool -&amp;gt; M.Map RecordType SummaryOffsetRec -&amp;gt; MCAPReader (M.Map RecordType SummaryOffsetRec)
    ...&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are two base cases. If we are out of bytes, we return our accumulated map. If all three boolean flags are true, then we can also return the map, as we have what we need.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;parseUsingIndex :: MCAPReader ()
parseUsingIndex = do
  ...
  where
    parseSummaryOffsets :: Word64 -&amp;gt; Bool -&amp;gt; Bool -&amp;gt; Bool -&amp;gt; M.Map RecordType SummaryOffsetRec -&amp;gt; MCAPReader (M.Map RecordType SummaryOffsetRec)
    parseSummaryOffsets 0 _ _ _ acc = return acc
    parseSummaryOffsets _ True True True acc = return acc
    parseSummaryOffsets remBytes hasSchema hasChannel hasChunkIndex acc =
    ...&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For the general case, we use &lt;code&gt;parseSummaryOffset&lt;/code&gt; to parse the next record. We update our boolean flags depending on the op code, and we insert the new record into our map. Then we recurse:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;parseUsingIndex :: MCAPReader ()
parseUsingIndex = do
  ...
  where
    parseSummaryOffsets :: Word64 -&amp;gt; Bool -&amp;gt; Bool -&amp;gt; Bool -&amp;gt; M.Map RecordType SummaryOffsetRec -&amp;gt; MCAPReader (M.Map RecordType SummaryOffsetRec)
    parseSummaryOffsets 0 _ _ _ acc = return acc
    parseSummaryOffsets _ True True True acc = return acc
    parseSummaryOffsets remBytes hasSchema hasChannel hasChunkIndex acc = do
      mcapGuard (&quot;Not enough bytes for summary offset: &quot; &amp;lt;&amp;gt; show remBytes) (remBytes &amp;gt;= 26)
      (_, summ@(SummaryOffsetRec op _ _)) &amp;lt;- parseNextRecord SummaryOffset parseSummaryOffset
      let hasSchema' = hasSchema || op == Schema
      let hasChannel' = hasChannel || op == Channel
      let hasChunkIndex' = hasChunkIndex || op == ChunkIndex
      let mp = M.insert op summ acc
      parseSummaryOffsets (remBytes - 26) hasSchema' hasChannel' hasChunkIndex' mp&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we’ll define a second helper. This will use the &lt;code&gt;Maybe&lt;/code&gt; monad to extract the 3 records we care about. &lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;parseUsingIndex :: MCAPReader ()
parseUsingIndex = do
  ...
  where
    ...
    find3Offsets :: M.Map RecordType SummaryOffsetRec -&amp;gt; Maybe (SummaryOffsetRec, SummaryOffsetRec, SummaryOffsetRec)
    find3Offsets mp = do
      s &amp;lt;- M.lookup Schema mp
      c &amp;lt;- M.lookup Channel mp
      ci &amp;lt;- M.lookup ChunkIndex mp
      return (s, c, ci)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now back in the main line of the function, we’ll get the size of this section (subtract the summary offset start from the footer start position) and call our two helpers. If we don’t have all three maps, we’ll throw a validation error showing what op codes we did find. Otherwise, we have the 3 offsets.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;parseUsingIndex :: MCAPReader ()
parseUsingIndex = do
  footerStart &amp;lt;- seekToFooterStart
  (_, FooterRec summStart summOffStart _) &amp;lt;- parseNextRecord FileFooter parseFooter'
  seek (fromIntegral summOffStart)
  -- Read Summary Offsets until we have Schema, Channel and ChunkIndex
  let sz = fromIntegral footerStart - summOffStart
  summOffMap &amp;lt;- parseSummaryOffsets sz False False False M.empty
  let offsets = find3Offsets summOffMap
  case offsets of
    Nothing -&amp;gt; throwError (ValidationError $ &quot;Did not find the right summary offsets: &quot; &amp;lt;&amp;gt; show (M.keys summOffMap))
    Just (schemaOffset, channelOffset, chunkIndexOffset) -&amp;gt; ...
  where
    parseSummaryOffsets :: Word64 -&amp;gt; Bool -&amp;gt; Bool -&amp;gt; Bool -&amp;gt; M.Map RecordType SummaryOffsetRec -&amp;gt; MCAPReader (M.Map RecordType SummaryOffsetRec)

    find3Offsets :: M.Map RecordType SummaryOffsetRec -&amp;gt; Maybe (SummaryOffsetRec, SummaryOffsetRec, SummaryOffsetRec)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we’ve got these summary offset records! It’s time to use them to start populating our topic state.&lt;/p&gt;
&lt;h2&gt;Step 3 - Summary Schemas and Channels&lt;/h2&gt;
&lt;p&gt;We’ll begin with the schemas and channels. These are fairly easy, since we can rely on previous code for the most part. Recall that we have the functions &lt;code&gt;parseSchema’&lt;/code&gt; and &lt;code&gt;parseChannel’&lt;/code&gt; for parsing individual schema and channel records. We need to update these type signatures to be more generic like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;parseSchema' :: (MonadParsec Void ByteString m, MS.MonadState TopicState m) =&amp;gt; m (Word64, Record)

parseChannel' :: (MonadFail m, MonadParsec Void ByteString m, MS.MonadState TopicState m) =&amp;gt; m (Word64, Record)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These will work with the &lt;code&gt;MCAPParser&lt;/code&gt; monad. They require &lt;code&gt;MonadState TopicState&lt;/code&gt; because they’ll save the schemas and channels within our &lt;code&gt;TopicState&lt;/code&gt;, rather than requiring us to do anything with the return values.&lt;/p&gt;
&lt;p&gt;So we just need to write functions that will look through &lt;strong&gt;all&lt;/strong&gt; the records in the summary block and parse them. Since the summary offset contains the start location and the byte length of all the records, we’ll seek to that location, and then use our tried and true method of parsing until we run out of bytes. Here’s a function to load all the schemas in a group:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;loadSchemasForIndex :: SummaryOffsetRec -&amp;gt; MCAPReader ()
loadSchemasForIndex (SummaryOffsetRec _ groupStart groupLen) = do
  seek (fromIntegral groupStart)
  f groupLen
  where
    f 0 = return ()
    f rem = do
      (len, _) &amp;lt;- parseNextRecord Schema parseSchema'
      mcapGuard (&quot;Summary schema is too long! &quot; &amp;lt;&amp;gt; show len &amp;lt;&amp;gt; &quot; &quot; &amp;lt;&amp;gt; show rem) (len &amp;lt;= rem)
      f (rem - len)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And here’s the function for channels:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;loadChannelsForIndex :: SummaryOffsetRec -&amp;gt; MCAPReader ()
loadChannelsForIndex (SummaryOffsetRec _ groupStart groupLen) = do
  seek (fromIntegral groupStart)
  f groupLen
  where
    f 0 = return ()
    f rem = do
      (len, _) &amp;lt;- parseNextRecord Channel parseChannel'
      mcapGuard (&quot;Summary channel is too long! &quot; &amp;lt;&amp;gt; show len &amp;lt;&amp;gt; &quot; &quot; &amp;lt;&amp;gt; show rem) (len &amp;lt;= rem)
      f (rem - len)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We simply call these from within &lt;code&gt;parseUsingIndex&lt;/code&gt; like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;parseUsingIndex :: MCAPReader ()
parseUsingIndex = do
  footerStart &amp;lt;- seekToFooterStart
  (_, FooterRec summStart summOffStart _) &amp;lt;- parseNextRecord FileFooter parseFooter'
  seek (fromIntegral summOffStart)
  -- Read Summary Offsets until we have Schema, Channel and ChunkIndex
  let sz = fromIntegral footerStart - summOffStart
  summOffMap &amp;lt;- parseSummaryOffsets sz False False False M.empty
  let offsets = find3Offsets summOffMap
  case offsets of
    Nothing -&amp;gt; throwError (ValidationError $ &quot;Did not find the right summary offsets: &quot; &amp;lt;&amp;gt; show (M.keys summOffMap))
    Just (schemaOffset, channelOffset, chunkIndexOffset) -&amp;gt; do
      loadSchemasForIndex schemaOffset
      loadChannelsForIndex channelOffset
      ...&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now our internal &lt;code&gt;TopicState&lt;/code&gt; is updated with the schemas and channels. This means we’re ready to parse messages, but we need to find where those messages are first!&lt;/p&gt;
&lt;h2&gt;Step 4 - Chunk Index Processing&lt;/h2&gt;
&lt;p&gt;Now we need to process each Chunk Index record. We’ll write a function for this, and it will be the last thing we need to call from &lt;code&gt;parseUsingIndex&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;processChunkIndexes :: SummaryOffsetRec -&amp;gt; MCAPReader ()

parseUsingIndex :: MCAPReader ()
parseUsingIndex = do
  footerStart &amp;lt;- seekToFooterStart
  (_, FooterRec summStart summOffStart _) &amp;lt;- parseNextRecord FileFooter parseFooter'
  seek (fromIntegral summOffStart)
  -- Read Summary Offsets until we have Schema, Channel and ChunkIndex
  let sz = fromIntegral footerStart - summOffStart
  summOffMap &amp;lt;- parseSummaryOffsets sz False False False M.empty
  let offsets = find3Offsets summOffMap
  case offsets of
    Nothing -&amp;gt; throwError (ValidationError $ &quot;Did not find the right summary offsets: &quot; &amp;lt;&amp;gt; show (M.keys summOffMap))
    Just (schemaOffset, channelOffset, chunkIndexOffset) -&amp;gt; do
      loadSchemasForIndex schemaOffset
      loadChannelsForIndex channelOffset
      processChunkIndexes chunkIndexOffset
  where
    ...&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To fill out this function, we follow the same general pattern to loop through these records until we’ve exhausted the bytes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;processChunkIndexes :: SummaryOffsetRec -&amp;gt; MCAPReader ()
processChunkIndexes (SummaryOffsetRec _ groupStart groupLen) = do
  seek (fromIntegral groupStart)
  f groupLen
  where
    f 0 = return ()
    f rem = do
      (len, ci) &amp;lt;- parseNextRecord ChunkIndex parseChunkIndex
      ...&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The trick is that processing each individual chunk index is more complicated after we’ve parsed it. Each chunk index refers to a single &lt;code&gt;Chunk&lt;/code&gt; record and contains its initial position (we saved this in the &lt;code&gt;cirChunkStartOffset&lt;/code&gt; field). However, the message index offsets are not absolute positions. They are &lt;strong&gt;relative&lt;/strong&gt; to the start of the data section of the chunk. So we want to calculate where this location is (and it took me a bit of debugging to get it right!).&lt;/p&gt;
&lt;p&gt;Prior to the data section in the chunk is the record header, which is 9 bytes. Then there are 32 fixed bytes, followed by the compression string. Then there are still 8 more bytes after that because the data section in the chunk is prefixed by the byte count. You can consult the &lt;a href=&quot;https://mcap.dev/spec#chunk-op0x06&quot;&gt;Chunk record specification&lt;/a&gt; to see where these numbers are coming from. So putting it all together, we take the chunk start location, add 49 bytes, and then add the length of the compression string.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;processChunkIndexes :: SummaryOffsetRec -&amp;gt; MCAPReader ()
processChunkIndexes (SummaryOffsetRec _ groupStart groupLen) = do
  seek (fromIntegral groupStart)
  f groupLen
  where
    f 0 = return ()
    f rem = do
      (len, ci) &amp;lt;- parseNextRecord ChunkIndex parseChunkIndex
      let chunkDataStart = cirChunkStartOffset ci + 49 + (fromIntegral $ BS.length (cirCompression ci))
      savedPosition &amp;lt;- curPos
      ... -- Process message index records
      seek savedPosition&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You’ll also see that we &lt;strong&gt;save the current handle position&lt;/strong&gt;. We’ll process the message index records and jump around to the messages. But we want to return to the current location (the location after parsing &lt;em&gt;this&lt;/em&gt; chunk index) so that we can process the &lt;em&gt;next&lt;/em&gt; chunk index afterward.&lt;/p&gt;
&lt;p&gt;Now we have to look through all of our desired channels and see which of them are referred to in the &lt;code&gt;cirMessageIndexOffsets&lt;/code&gt; of this chunk index:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;processChunkIndexes :: SummaryOffsetRec -&amp;gt; MCAPReader ()
processChunkIndexes (SummaryOffsetRec _ groupStart groupLen) = do
  seek (fromIntegral groupStart)
  f groupLen
  where
    f 0 = return ()
    f rem = do
      (len, ci) &amp;lt;- parseNextRecord ChunkIndex parseChunkIndex
      let chunkDataStart = cirChunkStartOffset ci + 49 + (fromIntegral $ BS.length (cirCompression ci))
      savedPosition &amp;lt;- curPos
      chans &amp;lt;- MS.gets tsDesiredChannels
      let allMIO = cirMessageIndexOffsets ci
      forM_ chans $ \chanId -&amp;gt; when (HM.member chanId allMIO) $ do
        ...
      seek savedPosition&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we get the offset for this channel in the map. This will give us the (absolute) location of the Message Index record for this channel. We’ll prepare a new function to process this message index:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;processChunkIndexes :: SummaryOffsetRec -&amp;gt; MCAPReader ()
processChunkIndexes (SummaryOffsetRec _ groupStart groupLen) = do
  seek (fromIntegral groupStart)
  f groupLen
  where
    f 0 = return ()
    f rem = do
      (len, ci) &amp;lt;- parseNextRecord ChunkIndex parseChunkIndex
      let chunkDataStart = cirChunkStartOffset ci + 49 + (fromIntegral $ BS.length (cirCompression ci))
      savedPosition &amp;lt;- curPos
      chans &amp;lt;- MS.gets tsDesiredChannels
      let allMIO = cirMessageIndexOffsets ci
      forM_ chans $ \chanId -&amp;gt; when (HM.member chanId allMIO) $ do
        let chanOffset = allMIO HM.! chanId
        loadMessagesFromMessageIndex chanId chanOffset chunkDataStart
      seek savedPosition

loadMessagesFromMessageIndex :: Word16 -&amp;gt; Word64 -&amp;gt; Word64 -&amp;gt; MCAPReader ()
loadMessagesFromMessageIndex chanId offset chunkDataStart&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is all we need for &lt;code&gt;processChunkIndexes&lt;/code&gt;. We’re getting closer to our goal! Now we need to process the message index record.&lt;/p&gt;
&lt;h2&gt;Steps 5 &amp;amp; 6 - Processing Message Indexes and Messages&lt;/h2&gt;
&lt;p&gt;You’ll note from above that we passed the channel ID, the offset of the message index, and the corresponding “chunk data start”. We begin this function by seeking the to message index location, parsing the message index, and ensuring that we are getting an index for the correct channel:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;loadMessagesFromMessageIndex :: Word16 -&amp;gt; Word64 -&amp;gt; Word64 -&amp;gt; MCAPReader ()
loadMessagesFromMessageIndex chanId offset chunkDataStart = do
  seek (fromIntegral offset)
  (_, MessageIndexRec mirChanId recs) &amp;lt;- parseNextRecord MessageIndex parseMessageIndex'
  mcapGuard (&quot;Mismatched channels for message index record: &quot; &amp;lt;&amp;gt; show chanId &amp;lt;&amp;gt; &quot; &quot; &amp;lt;&amp;gt; show mirChanId) (mirChanId == chanId)
  ...&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we loop through the record tuples in the message index record. Each of these contains a relative offset. We just need to seek to that offset, adding in the chunk data start location. Then we can use our message parser function!&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;loadMessagesFromMessageIndex :: Word16 -&amp;gt; Word64 -&amp;gt; Word64 -&amp;gt; MCAPReader ()
loadMessagesFromMessageIndex chanId offset chunkDataStart = do
  seek (fromIntegral offset)
  (_, MessageIndexRec mirChanId recs) &amp;lt;- parseNextRecord MessageIndex parseMessageIndex'
  mcapGuard (&quot;Mismatched channels for message index record: &quot; &amp;lt;&amp;gt; show chanId &amp;lt;&amp;gt; &quot; &quot; &amp;lt;&amp;gt; show mirChanId) (mirChanId == chanId)
  forM_ recs $ \(_, offset) -&amp;gt; do
    seek (fromIntegral $ chunkDataStart + offset)
    parseNextRecord' Message parseMessage'

parseMessage' :: (MonadParsec Void ByteString m, MS.MonadState TopicState m, MonadFail m) =&amp;gt; Word64 -&amp;gt; m (Word64, Record)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s all we need! Like our schema and channel parsers, &lt;code&gt;parseMessage’&lt;/code&gt; does the work of saving the messages in our &lt;code&gt;TopicState&lt;/code&gt;, so we don’t need to return or process anything. The path we started from &lt;code&gt;parseUsingIndex&lt;/code&gt; is now complete!&lt;/p&gt;
&lt;h2&gt;Compression Disclaimer&lt;/h2&gt;
&lt;p&gt;As an important note, this code takes a shortcut. The approach given will only work with &lt;strong&gt;uncompressed chunks&lt;/strong&gt;! The relative offset we used for the message index is actually the offset from the start of the uncompressed data. If the chunk’s data is compressed, we would have to grab that whole uncompressed string, decompress as much of it as we need, and then jump to particular locations within that bytestring. The code required to do this efficiently is much more intricate, as it requires us to manage counts on the streams of compressed and uncompressed data.&lt;/p&gt;
&lt;p&gt;This highlights an important tradeoff. By leaving the data uncompressed, it takes up more storage space and would take longer to send over a network if you need to download these bag files. But if the data is compressed, we might have to decompress a significant portion of it to find the few messages we care about, meaning we don’t see the same gains in bag read time. The particular needs of your application &amp;amp; systems will determine what choice makes sense.&lt;/p&gt;
&lt;h2&gt;Pulling it Together&lt;/h2&gt;
&lt;p&gt;Now we need an entrypoint to call &lt;code&gt;parseUsingIndex&lt;/code&gt;. Our function will take the filepath, open a handle to it, and create the initial topic state, looking for the &lt;code&gt;/turtle1/cmd_vel&lt;/code&gt; topic. We’ll invoke the &lt;code&gt;parseUsingIndex&lt;/code&gt; function with &lt;code&gt;runMCAPParser&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;parseRecordsFromFileWithIndex :: FilePath -&amp;gt; IO ()
parseRecordsFromFileWithIndex fp = do
  parseBareRecordsFromFile
  startTime &amp;lt;- getCurrentTime
  handle &amp;lt;- openFile fp ReadMode
  let initialTs = TopicState HM.empty HM.empty HM.empty (HS.fromList [&quot;/turtle1/cmd_vel&quot;]) HS.empty
  result &amp;lt;- runMCAPReader handle initialTs parseUsingIndex
  ...&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, in a reprisal of previous code, we’ll loop through all the messages for our topic (they use the &lt;code&gt;geometry_msgs/msg/Twist&lt;/code&gt; type from ROS2), and decode them all. (Recall that in the &lt;a href=&quot;https://mmhaskell.com/blog/2025/12/22/mcap-indexing&quot;&gt;previous part&lt;/a&gt; we wrote &lt;code&gt;parseVelMsg&lt;/code&gt; for this type).&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;parseRecordsFromFileWithIndex :: FilePath -&amp;gt; IO ()
parseRecordsFromFileWithIndex fp = do
  startTime &amp;lt;- getCurrentTime
  handle &amp;lt;- openFile fp ReadMode
  let initialTs = TopicState HM.empty HM.empty HM.empty (HS.fromList [&quot;/turtle1/cmd_vel&quot;]) HS.empty
  result &amp;lt;- runMCAPReader handle initialTs parseUsingIndex
  case result of
    Left e -&amp;gt; print e
    Right finalTs -&amp;gt; do
      let velMessages = fromMaybe [] $ HM.lookup (&quot;/turtle1/cmd_vel&quot;, &quot;geometry_msgs/msg/Twist&quot;) (tsMessages finalTs)
      forM_ velMessages $ \(MessageData t1 t2 msg) -&amp;gt; do
        parseVelResult &amp;lt;- evalStateT (runParserT parseVelMsg &quot;Velocity&quot; msg) 0
        case parseVelResult of
          Left e -&amp;gt; print e
          Right s -&amp;gt; putStrLn $ &quot;Parsed Velocity Message: &quot; &amp;lt;&amp;gt; show t1 &amp;lt;&amp;gt; &quot; &quot; &amp;lt;&amp;gt; show t2 &amp;lt;&amp;gt; &quot; &quot; &amp;lt;&amp;gt; show s
      endTime &amp;lt;- getCurrentTime
      print (diffUTCTime endTime startTime)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And now we’re done! We added some timing features, so we can compare this to our previous run. It is &lt;strong&gt;much&lt;/strong&gt; faster! The original takes around 0.075s. The new version takes about 0.001s. So it’s about &lt;strong&gt;75x faster&lt;/strong&gt;, a great speedup!&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This concludes our series on ROS2 bag parsing! Over the course of this long series, we were able to take an MCAP bag file, parse topic messages out of it, and then use the indexing features to do this even faster! We learn a ton about the MCAP format as well as CDR encoding. We saw how to compose parsers, even when they had stateful side effects like file seeking or saving message data.&lt;/p&gt;
&lt;p&gt;With so much ground to cover, there wasn’t a lot of time in this series to go over the basics. If you want to solidify your Haskell skills so that you can write advanced code like this, the &lt;strong&gt;best&lt;/strong&gt; way to do that is to take a look at some of our &lt;a href=&quot;https://academy.mondaymorninghaskell.com/courses&quot;&gt;courses&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The most immediately useful for this series would be &lt;a href=&quot;https://academy.mondaymorninghaskell.com/p/solve-hs&quot;&gt;Solve.hs&lt;/a&gt;. Module 1 teaches you valuable loop structures that form the building block for all of our complicated functions in Haskell. Then Module 4 will teach you about parsing and Megaparsec! In between, you’ll also learn about Data Structures and Algorithms in Haskell!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://academy.mondaymorninghaskell.com/p/making-sense-of-monads&quot;&gt;Making Sense of Monads&lt;/a&gt; and &lt;a href=&quot;https://academy.mondaymorninghaskell.com/p/effectful-haskell&quot;&gt;Effectful Haskell&lt;/a&gt; are also great choices if the monad structures in the second half of the series are a bit confusing to you. You can grab both of these courses for a discount by purchasing the &lt;a href=&quot;https://academy.mondaymorninghaskell.com/p/effects-bundle&quot;&gt;Effects Bundle&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;Finally, if you want access to all our course content, past, present and future, you can get the &lt;a href=&quot;https://academy.mondaymorninghaskell.com/p/mmh-complete&quot;&gt;MMH Complete bundle&lt;/a&gt;! This will include all the previous courses, as well as our other full length courses &lt;a href=&quot;https://academy.mondaymorninghaskell.com/p/haskell-from-scratch&quot;&gt;Haskell From Scratch&lt;/a&gt;, &lt;a href=&quot;https://academy.mondaymorninghaskell.com/p/practical-haskell&quot;&gt;Practical Haskell&lt;/a&gt;, plus our mini-course on machine learning, &lt;a href=&quot;https://academy.mondaymorninghaskell.com/p/haskell-brain&quot;&gt;Haskell Brain&lt;/a&gt;.&lt;/p&gt;</description>
	<pubDate>Mon, 29 Dec 2025 12:30:00 +0000</pubDate>
</item>
<item>
	<title>GHC Developer Blog: GHC 9.12.3 is now available</title>
	<guid isPermaLink="true">http://haskell.org/ghc/blog/20251227-ghc-9.12.3-released.html</guid>
	<link>http://haskell.org/ghc/blog/20251227-ghc-9.12.3-released.html</link>
	<description>&lt;h1&gt;GHC 9.12.3 is now available&lt;/h1&gt;
&lt;h4 class=&quot;text-muted&quot;&gt;zubin - 2025-12-27&lt;/h4&gt;

&lt;p&gt;The GHC developers are very pleased to announce the release of GHC 9.12.3.
Binary distributions, source distributions, and documentation are available at
&lt;a href=&quot;https://downloads.haskell.org/ghc/9.12.3&quot;&gt;downloads.haskell.org&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;GHC 9.12.3 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;Fix a number of crashes and miscompilations in the compiler frontend (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/25004&quot;&gt;#25004&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/25960&quot;&gt;#25960&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26256&quot;&gt;#26256&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Improvements to efficiency of the runtime linker (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26009&quot;&gt;#26009&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Fixes for several bugs in bytecode generation and the bytecode interpreter (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/23210&quot;&gt;#23210&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/25975&quot;&gt;#25975&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/25750&quot;&gt;#25750&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Fixes for bugs in the handling of WHITEHOLEs in the RTS (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26204&quot;&gt;#26204&lt;/a&gt;, &lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26205&quot;&gt;#26205&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Fix incorrect code generation for SSE vector operations (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/25859&quot;&gt;#25859&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Fix a use-after-free in the Windows runtime linker (&lt;a href=&quot;https://gitlab.haskell.org/ghc/ghc/issues/26613&quot;&gt;#26613&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Support for synchronous JSFFI exports for the wasm backend&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://downloads.haskell.org/~ghc/9.12.3/docs/users_guide/9.12.3-notes.html&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;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>Sat, 27 Dec 2025 00:00:00 +0000</pubDate>
</item>
<item>
	<title>in Code: Advent of Code 2025: Haskell Solution Reflections for all 12 Days</title>
	<guid isPermaLink="true">https://blog.jle.im/entry/advent-of-code-2025.html</guid>
	<link>https://blog.jle.im/entry/advent-of-code-2025.html</link>
	<description>&lt;p&gt;Merry Christmas all! This is my annual &lt;a href=&quot;http://adventofcode.com/&quot;&gt;Advent of Code&lt;/a&gt; post! Advent of Code is a
series of (this year) 12 daily Christmas-themed programming puzzles that are
meant to be fun diversions from your daily life, help you find a bit of whimsy
in your world, give you a chance to explore new ideas and program together with
your friends. I always enjoy discussing creative ways to solve these puzzles
every day, and it’s become a bit of an annual highlight for me and a lot of
others. My favorite part about these puzzles is that they are open ended enough
that there are usually many different interesting ways to solve them — it’s not
like a stressful interview question where you have to recite the obscure
incantation to pass the test. In the past I’ve leveraged &lt;a href=&quot;https://blog.jle.im/entry/alchemical-groups.html&quot;&gt;group theory&lt;/a&gt;, &lt;a href=&quot;https://blog.jle.im/entry/shifting-the-stars.html&quot;&gt;galilean
transformations and linear algebra&lt;/a&gt;, and &lt;a href=&quot;https://blog.jle.im/entry/shuffling-things-up.html&quot;&gt;more group
theory&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Haskell is especially fun for these because if you set up your abstractions
in just the right way, the puzzles seem to solve themselves. It’s a good
opportunity every year to get exposed to different parts of the Haskell
ecosystem! Last year, I moved almost all of my Haskell code to &lt;a href=&quot;https://github.com/mstksg/advent-of-code&quot;&gt;an Advent of Code Megarepo&lt;/a&gt;,
and I also write up my favorite ways to solve each one in the &lt;a href=&quot;https://github.com/mstksg/advent-of-code/wiki&quot;&gt;megarepo wiki&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;All of this year’s 12 puzzles &lt;a href=&quot;https://github.com/mstksg/advent-of-code/wiki/Reflections-2025&quot;&gt;are
here&lt;/a&gt;, but I’ve also included links to each individual one in this post. I’m
also considering expanding some of these into full on blog posts, so be on the
look out, or let me know if there are any that you might want fully expanded!
And if you haven’t, why not try these out yourself? Be sure to drop by the
libera-chat &lt;code&gt;##advent-of-code&lt;/code&gt; channel to discuss any fun ways you
solve them, or any questions! Thanks again to Eric for a great new fresh take on
the event this year!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mstksg/advent-of-code/blob/main/reflections/2025/day01.md&quot;&gt;Day
1 - Secret Entrance&lt;/a&gt; — The classic Day 1 &lt;code&gt;scanl&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mstksg/advent-of-code/blob/main/reflections/2025/day02.md&quot;&gt;Day
2 - Gift Shop&lt;/a&gt; — The super efficient &lt;code&gt;IntSet&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mstksg/advent-of-code/blob/main/reflections/2025/day03.md&quot;&gt;Day
3 - Lobby&lt;/a&gt; — &lt;code&gt;StateT&lt;/code&gt; + &lt;code&gt;[]&lt;/code&gt; = backtracking search
monad&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mstksg/advent-of-code/blob/main/reflections/2025/day04.md&quot;&gt;Day
4 - Printing Department&lt;/a&gt; — 2D cellular automata&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mstksg/advent-of-code/blob/main/reflections/2025/day05.md&quot;&gt;Day
5 - Cafeteria&lt;/a&gt; — The power of the &lt;code&gt;data-interval&lt;/code&gt; library&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mstksg/advent-of-code/blob/main/reflections/2025/day06.md&quot;&gt;Day
6 - Trash Compactor&lt;/a&gt; — &lt;code&gt;Data.List&lt;/code&gt; manipulations&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mstksg/advent-of-code/blob/main/reflections/2025/day07.md&quot;&gt;Day
7 - Laboratories&lt;/a&gt; — Tying the knot&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mstksg/advent-of-code/blob/main/reflections/2025/day08.md&quot;&gt;Day
8 - Playground&lt;/a&gt; — Iterative Clustering&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mstksg/advent-of-code/blob/main/reflections/2025/day09.md&quot;&gt;Day
9 - Movie Theater&lt;/a&gt; — &lt;code&gt;IntervalSet&lt;/code&gt; and
&lt;code&gt;IntervalMap&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mstksg/advent-of-code/blob/main/reflections/2025/day10.md&quot;&gt;Day
10 - Factory&lt;/a&gt; — Guassian Elimation, Type-safe Mutable Vectors&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mstksg/advent-of-code/blob/main/reflections/2025/day11.md&quot;&gt;Day
11 - Reactor&lt;/a&gt; — More Knot Tying and DP!&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mstksg/advent-of-code/blob/main/reflections/2025/day12.md&quot;&gt;Day
12 - Christmas Tree Farm&lt;/a&gt; — Counting&lt;/li&gt;
&lt;/ul&gt;</description>
	<pubDate>Wed, 24 Dec 2025 20:44:05 +0000</pubDate>
</item>

</channel>
</rss>
