<?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>Well-Typed.Com: Whole project loading for Haskell IDE tooling</title>
	<guid isPermaLink="false">http://www.well-typed.com/blog/2026/09/whole-project-loading-for-haskell-ide-tooling</guid>
	<link>https://well-typed.com/blog/2026/09/whole-project-loading-for-haskell-ide-tooling</link>
	<description>&lt;p&gt;From &lt;a href=&quot;https://github.com/haskell/haskell-language-server&quot;&gt;&lt;strong&gt;Haskell Language Server&lt;/strong&gt;&lt;/a&gt; &lt;code&gt;2.15.0.0&lt;/code&gt; onwards, users can opt-in to loading all
components of their current project up front, rather than as needed. Doing so
ensures information about every module is fully available from the start, and
avoids pauses to re-initialize the session when opening a file from a new
component.&lt;/p&gt;
&lt;p&gt;The feature is enabled by setting &lt;code&gt;componentsLoading&lt;/code&gt; to &lt;code&gt;&quot;multi: whole-project&quot;&lt;/code&gt; in the HLS configuration.&lt;/p&gt;
&lt;p&gt;The next release of &lt;a href=&quot;https://well-typed.github.io/haskell-debugger/&quot;&gt;&lt;strong&gt;Haskell Debugger&lt;/strong&gt;&lt;/a&gt; will load all components up front too.
Debug sessions will then be able to support breakpoints from any module in the
project, not just the entry point’s component.&lt;/p&gt;
&lt;p&gt;The feature is provided by &lt;code&gt;hie-bios &amp;gt;= 0.20&lt;/code&gt; and the cradle config (&lt;code&gt;hie.yaml&lt;/code&gt;)
can be used to fine-tune the list of components to load. The &lt;a href=&quot;https://github.com/haskell/hie-bios#selecting-which-components-to-load&quot;&gt;new
&lt;code&gt;componentsToLoad&lt;/code&gt;
field&lt;/a&gt;
lets you list the exact targets to pick, which are otherwise the &lt;code&gt;components&lt;/code&gt;
listed in the cradle or inferred from the &lt;code&gt;cabal&lt;/code&gt;/&lt;code&gt;stack&lt;/code&gt; project.&lt;/p&gt;

&lt;h3 id=&quot;multi-component-sessions&quot;&gt;Multi component sessions&lt;/h3&gt;
&lt;p&gt;Haskell Language Server has supported multi component sessions for a while, e.g.
when working on a Cabal package with both a library and an executable their files
can all be loaded together, so jumping to definition from &lt;code&gt;app/Main.hs&lt;/code&gt; can
land you in &lt;code&gt;lib/Foo.hs&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;However, so far each new component has been loaded into the session lazily, i.e.
only when files belonging to the component are opened. There are caches
involved, but each time this happens the GHC session is re-initialized from
scratch: the new set of components, and how to build them, is discovered by
querying the underlying build system, e.g. by invoking &lt;code&gt;cabal repl&lt;/code&gt;/&lt;code&gt;stack repl&lt;/code&gt;
and extracting the flags they would pass to &lt;code&gt;ghci&lt;/code&gt;. Ultimately the new component
might have to go from being pre-compiled on disk to interpreted in-memory,
forcing all its descendants to be reconfigured too, so even if we wanted to be
more clever not much work could be saved.&lt;/p&gt;
&lt;p&gt;This is not a big deal with just two components, but in a larger project it can be
surprising to have HLS behave differently in a given file according to which
other files have been opened. Also, when the session needs to be re-initialized
because of a new component, the induced pause can be a bit jarring.&lt;/p&gt;
&lt;h3 id=&quot;whole-project-loading&quot;&gt;Whole project loading&lt;/h3&gt;
&lt;p&gt;The new &lt;em&gt;whole project&lt;/em&gt; mode instead loads all project components right away,
so that everything is available from the start. The downside is doing everything
up front means memory use and initialization time are also paid up front. Also,
a misconfigured component can stop the others from loading.&lt;/p&gt;
&lt;h4 id=&quot;in-haskell-language-server&quot;&gt;In Haskell Language Server&lt;/h4&gt;
&lt;p&gt;Eventually we hope to make whole project loading the default. For the moment,
starting with &lt;code&gt;haskell-language-server-2.15&lt;/code&gt;, the new feature is enabled by
setting the new config field &lt;code&gt;componentsLoading&lt;/code&gt; to &lt;code&gt;multi: whole-project&lt;/code&gt;. The
other options are &lt;code&gt;multi: needed-only&lt;/code&gt;, which is the default, and &lt;code&gt;single&lt;/code&gt;, which
loads only a single component at once. The &lt;code&gt;componentsLoading&lt;/code&gt; field replaces the
previous &lt;code&gt;sessionLoading&lt;/code&gt; one which is now deprecated: &lt;code&gt;sessionLoading: &quot;multipleComponents&quot;&lt;/code&gt;
is now &lt;code&gt;componentsLoading: &quot;multi: needed-only&quot;&lt;/code&gt; and interpreted as such.&lt;/p&gt;
&lt;h4 id=&quot;in-haskell-debugger&quot;&gt;In Haskell Debugger&lt;/h4&gt;
&lt;p&gt;Haskell Debugger was actually the primary motivation for this work, as finding
out in the middle of a debug session that you cannot add a breakpoint in an
imported module is more dire than the issues with HLS.&lt;/p&gt;
&lt;p&gt;Prior to whole-project loading, the typical setup where a package contains both
a library and an executable that depends on it would end up with only the
modules from the executable interpreted and so available to be stopped at.
The library was installed in a temporary package database and included only as a
dependency, so trying to set a breakpoint in a module from the library would just fail.&lt;/p&gt;
&lt;p&gt;Haskell Debugger builds its session only once, as soon as it learns what the
entry point is, i.e. the module and function to start execution from. At this
point the debugger doesn’t know where the breakpoints will be, and so which
modules need to be interpreted. As new breakpoints can be set while execution
already started, waiting to know all of them to initialize the session is not an
option.&lt;/p&gt;
&lt;p&gt;Because of the above we have gone ahead and made whole-project loading the
default and only way Haskell Debugger behaves, starting from the next release.&lt;/p&gt;
&lt;h4 id=&quot;how-it-works-and-further-configuration&quot;&gt;How it works and further configuration&lt;/h4&gt;
&lt;p&gt;What “all project components” means depends on the underlying cradle, either
specified in a &lt;code&gt;hie.yaml&lt;/code&gt; file or inferred from what can be found in the root
directory. Recent enough &lt;code&gt;Cabal&lt;/code&gt; and &lt;code&gt;Stack&lt;/code&gt; are the two kinds of cradles that
actually support this: if the &lt;code&gt;hie.yaml&lt;/code&gt; file specifies components we load
those, otherwise we ask the package manager to infer them. Inferring means
asking &lt;code&gt;Cabal&lt;/code&gt; for target &lt;code&gt;all&lt;/code&gt; while enabling tests and benchmarks, or asking
&lt;code&gt;Stack&lt;/code&gt; for its default targets.&lt;/p&gt;
&lt;p&gt;The above logic, like most of this new feature, is implemented by &lt;code&gt;hie-bios&lt;/code&gt;
starting from version &lt;code&gt;0.20&lt;/code&gt;. All details on how to fine-tune your cradle can be
found in &lt;a href=&quot;https://github.com/haskell/hie-bios&quot;&gt;&lt;code&gt;hie-bios&lt;/code&gt;’s &lt;code&gt;README&lt;/code&gt;&lt;/a&gt;, including
the new &lt;a href=&quot;https://github.com/haskell/hie-bios#selecting-which-components-to-load&quot;&gt;&lt;code&gt;componentsToLoad&lt;/code&gt;
field&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Before explaining the new field let’s go through a few examples with &lt;code&gt;Cabal&lt;/code&gt; cradles to make
things more concrete. For each case we will list the &lt;code&gt;cabal repl&lt;/code&gt; invocation
that &lt;code&gt;hie-bios&lt;/code&gt; uses to fetch the correct flags.&lt;/p&gt;
&lt;p&gt;A very minimal cradle (&lt;code&gt;hie.yaml&lt;/code&gt;) will let &lt;code&gt;cabal&lt;/code&gt; infer the components by
using the target &lt;code&gt;all&lt;/code&gt;, i.e.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode yaml&quot;&gt;&lt;code class=&quot;sourceCode yaml&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;fu&quot;&gt;cradle&lt;/span&gt;&lt;span class=&quot;kw&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;at&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;cabal&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;will result in &lt;code&gt;cabal repl --enable-multi-repl --enable-tests --enable-benchmarks all&lt;/code&gt;. The &lt;code&gt;--enable-*&lt;/code&gt; flags are included so that the
session will cover everything in the project.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;--enable-*&lt;/code&gt; flags will override what specified in a &lt;code&gt;cabal.project&lt;/code&gt; file,
so if the cradle includes one we omit them, i.e.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot;&gt;&lt;pre class=&quot;sourceCode yaml&quot;&gt;&lt;code class=&quot;sourceCode yaml&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;fu&quot;&gt;cradle&lt;/span&gt;&lt;span class=&quot;kw&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;at&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;cabal&lt;/span&gt;&lt;span class=&quot;kw&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;at&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;cabalProject&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;&quot;./cabal.project&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;will result in &lt;code&gt;cabal repl --enable-multi-repl --project-file=./cabal.project all&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If &lt;code&gt;components&lt;/code&gt; are specified then those are the targets used, e.g.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb3&quot;&gt;&lt;pre class=&quot;sourceCode yaml&quot;&gt;&lt;code class=&quot;sourceCode yaml&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;fu&quot;&gt;cradle&lt;/span&gt;&lt;span class=&quot;kw&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;at&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;cabal&lt;/span&gt;&lt;span class=&quot;kw&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;at&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;components&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&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;at&quot;&gt;      &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;kw&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;&quot;path&quot;&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;&quot;./src&quot;&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;fu&quot;&gt;&quot;component&quot;&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;&quot;lib:foo&quot;&lt;/span&gt;&lt;span class=&quot;kw&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;at&quot;&gt;      &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;kw&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;&quot;path&quot;&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;&quot;./app&quot;&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;fu&quot;&gt;&quot;component&quot;&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;&quot;exe:foo&quot;&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;will result in &lt;code&gt;cabal repl --enable-multi-repl lib:foo exe:foo&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Finally, if some component doesn’t play nice with &lt;code&gt;cabal repl&lt;/code&gt; or the tooling that uses &lt;code&gt;hie-bios&lt;/code&gt;,
the field &lt;code&gt;componentsToLoad&lt;/code&gt; can be used to specify the exact list of targets to use, for example&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb4&quot;&gt;&lt;pre class=&quot;sourceCode yaml&quot;&gt;&lt;code class=&quot;sourceCode yaml&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;fu&quot;&gt;cradle&lt;/span&gt;&lt;span class=&quot;kw&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;at&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;cabal&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-3&quot;&gt;&lt;a href=&quot;https://well-typed.com/blog/rss2.xml#cb4-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;componentsToLoad&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;kw&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;lib:foo&quot;&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;lib:bar&quot;&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;will result in &lt;code&gt;cabal repl --enable-multi-repl lib:foo lib:bar&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Hopefully whole-project loading will provide a less surprising and smoother dev
experience on projects with multiple components. It’s been my new default and
working well for me since it got merged. Feedback is welcome on the &lt;a href=&quot;https://github.com/haskell/haskell-language-server/issues&quot;&gt;HLS
issue tracker&lt;/a&gt;.
&lt;a href=&quot;https://github.com/haskell/haskell-language-server/issues/5005&quot;&gt;Issue #5005&lt;/a&gt; is the
issue about the feature introduction.&lt;/p&gt;
&lt;p&gt;This work has been performed in collaboration with Mercury, who have a long-term
commitment to the scalability and robustness of the Haskell ecosystem.
Well-Typed are always interested in projects and looking for funding to improve
HLS and other Haskell tools. Please contact &lt;a href=&quot;mailto:info@well-typed.com&quot;&gt;info@well-typed.com&lt;/a&gt; if we might be
able to work with you!&lt;/p&gt;</description>
	<pubDate>Fri, 04 Sep 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Gabriella Gonzalez: Dependent if expressions without dependent types</title>
	<guid isPermaLink="true">https://haskellforall.com/2026/09/dependent-if-expressions</guid>
	<link>https://haskellforall.com/2026/09/dependent-if-expressions</link>
	<description>Folklore trick for dollar-store dependent types</description>
	<pubDate>Wed, 02 Sep 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Haskell Interlude: 85: Brent Yorgey</title>
	<guid isPermaLink="false">Buzzsprout-19705795</guid>
	<link>https://haskell.foundation/podcast/85/</link>
	<description>&lt;p&gt;In today’s episode, we’re joined by Brent Yorgey, Associate Professor of Computer Science at Hendrix College and the creator, among other things, of the Diagrams vector graphics library and Swarm, a 2D programming and resource gathering game. We talk about teaching, domain specific languages, and competitive coding.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://haskell.foundation/podcast/85/&quot;&gt;Episode links and transcript&lt;/a&gt;&lt;/p&gt;</description>
	<pubDate>Wed, 26 Aug 2026 17:00:00 +0000</pubDate>
        <enclosure url="https://www.buzzsprout.com/1817535/episodes/19705795-85-brent-yorgey.mp3" length="43061216" type="audio/mpeg"/>
</item>
<item>
	<title>Philip Wadler: The Gargantuan Lie That is Collapsing the World's Climate</title>
	<guid isPermaLink="false">tag:blogger.com,1999:blog-9757377.post-4320414745532883598</guid>
	<link>https://wadler.blogspot.com/2026/08/the-gargantuan-lie-that-is-collapsing.html</link>
	<description>&lt;p&gt;&lt;img alt=&quot;&quot; class=&quot;attachment-large size-large&quot; height=&quot;426&quot; src=&quot;https://www.carbonbrief.org/wp-content/uploads/2024/09/AMCKAY_Credit-Emma-Mcintyre-1-1024x682.jpeg&quot; width=&quot;640&quot; /&gt; &lt;/p&gt;&lt;p&gt;Adam McKay, director of &lt;i&gt;Don't Look Up, &lt;/i&gt;&lt;a href=&quot;https://www.currentaffairs.org/news/the-massive-climate-lie-that-will-destroy-human-civilization&quot;&gt;points out&lt;/a&gt; what should be obvious but is easy to ignore.&lt;/p&gt;&lt;p style=&quot;background-color: white; font-family: garamond-premier-pro, serif; font-size: 21px; line-height: 1.6 !important; margin: 0px; padding: 0px; text-indent: 2.5em;&quot;&gt;&lt;span style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span style=&quot;color: #222222; margin: 0px; padding: 0px;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p style=&quot;background-color: white; font-family: garamond-premier-pro, serif; font-size: 21px; line-height: 1.6 !important; margin: 0px; padding: 0px; text-indent: 2.5em;&quot;&gt;&lt;span style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span style=&quot;color: #222222; margin: 0px; padding: 0px;&quot;&gt;Like all grand lies, “we have more time” takes many different forms, often focus-grouped. There are the lofty-sounding promises to reach “Net-zero emissions by 2050,” as if 24 years from now was soon enough. There are the queries of “What’s your carbon footprint?,” as if individual people with plastic bags or straws were the problem and not gigantic multinational corporations. There’s the accusation that anyone who expresses urgency is a “doomer.” There are those who treat climate as an abstraction to win political campaigns, first arguing that &lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://www.currentaffairs.org/news/2022/07/can-a-boon-for-the-fossil-fuel-sector-really-be-called-a-climate-bill&quot;&gt;the Biden administration’s Inflation Reduction Act&lt;/a&gt;&lt;span style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span style=&quot;color: #222222; margin: 0px; padding: 0px;&quot;&gt; was a victory despite doing nowhere near enough to address the scale of climate collapse, and more recently that Democrats should &lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;http://v/&quot;&gt;just stop talking about climate&lt;/a&gt;&lt;span style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span style=&quot;color: #222222; margin: 0px; padding: 0px;&quot;&gt; and focus on more “winnable” issues. Most damaging and common of all, there are those who simply don’t mention it.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-color: white; font-family: garamond-premier-pro, serif; font-size: 21px; line-height: 1.6 !important; margin: 0px; padding: 0px; text-indent: 2.5em;&quot;&gt;&lt;span style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span style=&quot;color: #222222; margin: 0px; padding: 0px;&quot;&gt;All of these distortions have robbed us of the most critical element people need to understand a threat and adjust their actions accordingly: &lt;/span&gt;&lt;em style=&quot;font-family: garamond-premier-pro; margin: 0px; padding: 0px;&quot;&gt;&lt;span style=&quot;color: #222222; margin: 0px; padding: 0px;&quot;&gt;context.&lt;/span&gt;&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-color: white; font-family: garamond-premier-pro, serif; font-size: 21px; line-height: 1.6 !important; margin: 0px; padding: 0px; text-indent: 2.5em;&quot;&gt;&lt;span style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span style=&quot;color: #222222; margin: 0px; padding: 0px;&quot;&gt;And make no mistake, when it comes to how much time we have, the data and the geological record are crystal clear. &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-color: white; font-family: garamond-premier-pro, serif; font-size: 21px; line-height: 1.6 !important; margin: 0px; padding: 0px; text-indent: 2.5em;&quot;&gt;&lt;span style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-color: white; font-family: garamond-premier-pro, serif; font-size: 21px; line-height: 1.6 !important; margin: 0px; padding: 0px; text-indent: 2.5em;&quot;&gt;&lt;span style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span style=&quot;color: #222222; margin: 0px; padding: 0px;&quot;&gt;For some badly-needed context, the last three years, likely for the first time in &lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://www.aljazeera.com/news/2024/1/9/2023-shatters-record-for-worlds-warmest-year-eu-climate-agency&quot;&gt;over 100,000 years,&lt;/a&gt;&lt;span style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span style=&quot;color: #222222; margin: 0px; padding: 0px;&quot;&gt; have averaged above the Paris Accords’ “do not cross” 1.5 degrees celsius planetary warming. &lt;/span&gt;&lt;span style=&quot;color: #444746; margin: 0px; padding: 0px;&quot;&gt;Only ten years ago, that was considered catastrophic, but now mainstream news tells us it’s just a number.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-color: white; font-family: garamond-premier-pro, serif; font-size: 21px; line-height: 1.6 !important; margin: 0px; padding: 0px; text-indent: 2.5em;&quot;&gt;&lt;span style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span style=&quot;color: #444746; margin: 0px; padding: 0px;&quot;&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-color: white; font-family: garamond-premier-pro, serif; font-size: 21px; line-height: 1.6 !important; margin: 0px; padding: 0px; text-indent: 2.5em;&quot;&gt;&lt;span style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span style=&quot;color: #222222; margin: 0px; padding: 0px;&quot;&gt;Let’s do the context thing again: 2C will mean we have completely left the stable climate period known as &lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://www.thegef.org/news/goodbye-forever-friendly-holocene&quot;&gt;the Holocene&lt;/a&gt;&lt;span style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span style=&quot;color: #222222; margin: 0px; padding: 0px;&quot;&gt;. This is the 11,000-year-old era that has given us large-scale crop and livestock agriculture, which gave us cities, written language, modern science and medicine, and warm beds and showers.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-color: white; font-family: garamond-premier-pro, serif; font-size: 21px; line-height: 1.6 !important; margin: 0px; padding: 0px; text-indent: 2.5em;&quot;&gt;&lt;span style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span style=&quot;color: #222222; margin: 0px; padding: 0px;&quot;&gt;Before that, for hundreds of thousands of years in the Pleistocene era, humans (and our hominid ancestors) spent most of their time running from drought, fires, floods, extreme cold and heat, predators, and each other. &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-color: white; font-family: garamond-premier-pro, serif; font-size: 21px; line-height: 1.6 !important; margin: 0px; padding: 0px; text-indent: 2.5em;&quot;&gt;&lt;span style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span style=&quot;color: #222222; margin: 0px; padding: 0px;&quot;&gt;The population was likely no more than a few million people spread across the whole planet. At one point we may have almost gone extinct, with just 10,000 &lt;/span&gt;&lt;em style=&quot;font-family: garamond-premier-pro; margin: 0px; padding: 0px;&quot;&gt;&lt;span style=&quot;color: #222222; margin: 0px; padding: 0px;&quot;&gt;Homo sapien&lt;/span&gt;&lt;/em&gt;&lt;span style=&quot;color: #222222; margin: 0px; padding: 0px;&quot;&gt;s clinging to life. But after the advent of the Holocene and its remarkably stable climate, in only 100 centuries the world population has risen to 8 billion.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-color: white; font-family: garamond-premier-pro, serif; font-size: 21px; line-height: 1.6 !important; margin: 0px; padding: 0px; text-indent: 2.5em;&quot;&gt;&lt;span style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span style=&quot;color: #222222; margin: 0px; padding: 0px;&quot;&gt;That is what we stand to lose. In fact, if our institutions, news and elected officials continue to feed and water the oil company-conceived mega-falsehood that climate breakdown is something just “our great-grandkids need to worry about,”  human civilization as we know it will collapse and &lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://www.forbes.com/sites/roberthart/2021/11/09/1-billion-people-at-risk-from-potentially-lethal-heat-if-global-warming-passes-2c-scientists-warn/&quot;&gt;billions could die&lt;/a&gt;&lt;span style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span style=&quot;color: #222222; margin: 0px; padding: 0px;&quot;&gt;. And we’re not talking about the far distant future. We are talking about collapse within years, not centuries. For real.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style=&quot;background-color: white; font-family: garamond-premier-pro, serif; font-size: 21px; line-height: 1.6 !important; margin: 0px; padding: 0px; text-indent: 2.5em;&quot;&gt;&lt;span style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span style=&quot;color: #222222; margin: 0px; padding: 0px;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;</description>
	<pubDate>Tue, 25 Aug 2026 18:29:33 +0000</pubDate>
	<author>noreply@blogger.com (Philip Wadler)</author>
</item>
<item>
	<title>Philip Wadler: There is No AI</title>
	<guid isPermaLink="false">tag:blogger.com,1999:blog-9757377.post-7988354390333301093</guid>
	<link>https://wadler.blogspot.com/2026/08/there-is-no-ai.html</link>
	<description>&lt;p&gt; &lt;/p&gt;&lt;img height=&quot;359&quot; src=&quot;https://tse2.mm.bing.net/th/id/OIP.w5uVNkNk3bDeGq7P01w_LAHaEK?r=0&amp;amp;pid=Api&quot; width=&quot;640&quot; /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I've searched with little success for ideas about how we can handle AI so that it benefits rather than harms society. Here is a &lt;a href=&quot;https://www.newyorker.com/science/annals-of-artificial-intelligence/there-is-no-ai&quot;&gt;suggestion&lt;/a&gt; from Jaron Lanier.  It was published by the New Yorker in 2023, when GPT-4 was the latest model. Time named Lanier to its list of 100 most influential people in 2015. &lt;/div&gt;&lt;div&gt;&lt;p class=&quot;paywall&quot;&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p class=&quot;paywall&quot;&gt;A program like OpenAI’s GPT-4, which can write sentences to order, is something like a version of Wikipedia that includes much more data, mashed together using statistics. Programs that create images to order are something like a version of online image search, but with a system for combining the pictures. In both cases, it’s people who have written the text and furnished the images. The new programs mash up work &lt;a href=&quot;https://www.newyorker.com/tech/annals-of-technology/chatgpt-is-a-blurry-jpeg-of-the-web&quot;&gt;done by human minds&lt;/a&gt;. What’s innovative is that the mashup process has become guided and constrained, so that the results are usable and often striking. This is a significant achievement and worth celebrating—but it can be thought of as illuminating previously hidden concordances between human creations, rather than as the invention of a new mind.&lt;/p&gt;&lt;p class=&quot;paywall&quot;&gt;As far as I can tell, my view flatters the technology. After all, what is civilization but social collaboration? Seeing A.I. as a way of working together, rather than as a technology for creating independent, intelligent beings, may make it less mysterious—less like &lt;span class=&quot;small&quot; style=&quot;line-height: inherit;&quot;&gt;hal&lt;/span&gt; 9000 or Commander Data. But that’s good, because mystery only makes mismanagement more likely.&lt;/p&gt;&lt;p class=&quot;paywall&quot;&gt;...&lt;/p&gt;&lt;p class=&quot;paywall&quot;&gt;This concept, which I’ve &lt;a class=&quot;external-link&quot; href=&quot;https://www.amazon.com/Who-Owns-Future-Jaron-Lanier/dp/1451654979/ref=nodl_?dplnkId=da962c54-3d95-4609-a813-7471d422d110&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;contributed&lt;/a&gt; to developing, is usually called “data dignity.” It appeared, long before the rise of big-model “A.I.,” as an alternative to the familiar arrangement in which people give their data for free in exchange for free services, such as internet searches or social networking. Data dignity is sometimes known as “data as labor” or “plurality research.” The familiar arrangement has turned out to have a dark side: because of “network effects,” a few platforms take over, eliminating smaller players, like local newspapers. Worse, since the immediate online experience is supposed to be free, the only remaining business is the hawking of influence. Users experience what seems to be a communitarian paradise, but they are targeted by stealthy and addictive algorithms that make people vain, irritable, and paranoid.&lt;/p&gt;&lt;p class=&quot;paywall&quot;&gt;In a world with data dignity, digital stuff would typically be connected with the humans who want to be known for having made it. In some versions of the idea, people could get paid for what they create, even when it is filtered and recombined through big models, and tech hubs would earn fees for facilitating things that people want to do. Some people are horrified by the idea of capitalism online, but this would be a more honest capitalism. The familiar “free” arrangement has been a disaster.&lt;/p&gt;&lt;p class=&quot;paywall&quot;&gt;...&lt;/p&gt;&lt;p class=&quot;paywall&quot;&gt;&lt;span style=&quot;background-color: white;&quot;&gt;Consider what might happen if A.I.-driven tree-trimming robots are introduced. Human tree trimmers might find themselves devalued or even out of work. But the robots could eventually allow for a new type of indirect landscaping artistry. Some former workers, or others, might create inventive approaches—holographic topiary, say, that looks different from different angles—that find their way into the tree-trimming models. With data dignity, the models might create new sources of income, distributed through collective organizations. Tree trimming would become more multifunctional and interesting over time; there would be a community motivated to remain valuable. Each new successful introduction of an A.I. or robotic application could involve the inauguration of a new kind of creative work. In ways large and small, this could help ease the transition to an economy into which models are integrated.&lt;/span&gt;&lt;/p&gt;&lt;p class=&quot;paywall&quot;&gt;&lt;span style=&quot;background-color: white;&quot;&gt;...&lt;/span&gt;&lt;/p&gt;&lt;p class=&quot;paywall&quot;&gt;There are also non-altruistic reasons for A.I. companies to embrace data dignity. The models are only as good as their inputs. It’s only through a system like data dignity that we can expand the models into new frontiers. Right now, it’s much easier to get an L.L.M. to write an essay than it is to ask the program to generate an interactive virtual-reality world, because there are very few virtual worlds in existence. Why not solve that problem by giving people who add more virtual worlds a chance for prestige and income?&lt;/p&gt;&lt;/blockquote&gt;&lt;p class=&quot;paywall&quot;&gt;&lt;/p&gt;&lt;p class=&quot;paywall&quot;&gt;&lt;br class=&quot;Apple-interchange-newline&quot; /&gt;&lt;/p&gt;&lt;br class=&quot;Apple-interchange-newline&quot; /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;</description>
	<pubDate>Tue, 25 Aug 2026 17:57:53 +0000</pubDate>
	<author>noreply@blogger.com (Philip Wadler)</author>
</item>
<item>
	<title>Sandy Maguire: review2</title>
	<guid isPermaLink="true">https://reasonablypolymorphic.com/blog/reviewing-again/index.html</guid>
	<link>https://reasonablypolymorphic.com/blog/reviewing-again/index.html</link>
	<description>&lt;p&gt;Last time, we took a stroll down memory lane to review some ancient code I wrote, and see what/how I’d do things differently now. That was fun, and I have a new banger for us today.&lt;/p&gt;
&lt;p&gt;Today’s example comes from the same place — a little vim-like text editor I was working on. Vim has this “repeat” operator which just does the same thing you did last time. It’s nice. Delete a word. Running repeat deletes another word. Kinda dinky in this example, but it can also rerun “increment every number in the next four paragraphs.”&lt;/p&gt;
&lt;p&gt;Anyway, so that’s the feature I was trying to duplicate. But the action I was running might have done some IO, and I didn’t want to repeat the IO (because maybe the IO was to gather some input from the user, and repeating shouldn’t ask again.)&lt;/p&gt;
&lt;p&gt;I was still &lt;a href=&quot;https://sandymaguire.me/blog/jurisdiction-of-heaven/&quot;&gt;high on my own supply of writing monads&lt;/a&gt;, so I approached this problem with a custom monad. The gist of the API was:&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://reasonablypolymorphic.com#cb1-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- | A monad transformer adding the ability to record the results of IO actions&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-2&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb1-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- and later replay them.&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-3&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb1-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;Again&lt;/span&gt; m a&lt;/span&gt;
&lt;span id=&quot;cb1-4&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb1-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;Monad&lt;/span&gt; m &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Again&lt;/span&gt; m)&lt;/span&gt;
&lt;span id=&quot;cb1-5&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb1-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;MonadIO&lt;/span&gt; m &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MonadIO&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Again&lt;/span&gt; m)&lt;/span&gt;
&lt;span id=&quot;cb1-6&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb1-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;MonadTrans&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Again&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-7&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#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://reasonablypolymorphic.com#cb1-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- | Runs an action and records all of its sampled IO. Returns a action which&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-9&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb1-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- when invoked will use the recorded IO.&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-10&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb1-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;runAgain&lt;/span&gt;
&lt;span id=&quot;cb1-11&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb1-11&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;Monad&lt;/span&gt; m&lt;/span&gt;
&lt;span id=&quot;cb1-12&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb1-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;Again&lt;/span&gt; m a&lt;/span&gt;
&lt;span id=&quot;cb1-13&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb1-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (m a)&lt;/span&gt;
&lt;span id=&quot;cb1-14&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb1-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-15&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb1-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- | Marks an IO action to be memoized after its first invocation.&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-16&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb1-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;again&lt;/span&gt;
&lt;span id=&quot;cb1-17&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb1-17&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;MonadIO&lt;/span&gt; m&lt;/span&gt;
&lt;span id=&quot;cb1-18&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb1-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;       , &lt;span class=&quot;dt&quot;&gt;Typeable&lt;/span&gt; r&lt;/span&gt;
&lt;span id=&quot;cb1-19&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb1-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;       )&lt;/span&gt;
&lt;span id=&quot;cb1-20&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb1-20&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;IO&lt;/span&gt; r&lt;/span&gt;
&lt;span id=&quot;cb1-21&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb1-21&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;Again&lt;/span&gt; m r&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I’m actually pretty impressed with past-me on this one. That’s a clean API, and the implementation was pretty cute.&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;newtype&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Again&lt;/span&gt; m a &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Again&lt;/span&gt;&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;ot&quot;&gt; runAgain' ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RWST&lt;/span&gt; () [&lt;span class=&quot;dt&quot;&gt;Dynamic&lt;/span&gt;] [&lt;span class=&quot;dt&quot;&gt;Dynamic&lt;/span&gt;] m a&lt;/span&gt;
&lt;span id=&quot;cb2-3&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#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://reasonablypolymorphic.com#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://reasonablypolymorphic.com#cb2-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;once&lt;/span&gt;
&lt;span id=&quot;cb2-6&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;    ::&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;forall&lt;/span&gt; m r&lt;/span&gt;
&lt;span id=&quot;cb2-7&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;     &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; ( &lt;span class=&quot;dt&quot;&gt;MonadIO&lt;/span&gt; m&lt;/span&gt;
&lt;span id=&quot;cb2-8&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;       , &lt;span class=&quot;dt&quot;&gt;Typeable&lt;/span&gt; r&lt;/span&gt;
&lt;span id=&quot;cb2-9&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;)&lt;/span&gt;
&lt;span id=&quot;cb2-10&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-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;IO&lt;/span&gt; r&lt;/span&gt;
&lt;span id=&quot;cb2-11&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-11&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;Again&lt;/span&gt; m r&lt;/span&gt;
&lt;span id=&quot;cb2-12&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;once action &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-13&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    a &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&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;cb2-14&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; x  &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; fromJust &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; fromDynamic x&lt;/span&gt;
&lt;span id=&quot;cb2-15&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-15&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; liftIO action&lt;/span&gt;
&lt;span id=&quot;cb2-16&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    tell [toDyn a]&lt;/span&gt;
&lt;span id=&quot;cb2-17&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;return&lt;/span&gt; a&lt;/span&gt;
&lt;span id=&quot;cb2-18&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-18&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;cb2-19&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-19&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;MonadState&lt;/span&gt; [r] m &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; r)&lt;/span&gt;
&lt;span id=&quot;cb2-20&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    dequeue &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-21&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        get &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;cb2-22&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-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;fu&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-23&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-23&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;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;cb2-24&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                put xs&lt;/span&gt;
&lt;span id=&quot;cb2-25&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-25&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;Just&lt;/span&gt; x&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The trick here is to keep &lt;code&gt;MonadState [Dynamic]&lt;/code&gt; and a &lt;code&gt;MonadWriter [Dynamic]&lt;/code&gt; instances around. This code uses the &lt;code&gt;MonadState&lt;/code&gt; to pop off IO actions it’s already run, and the &lt;code&gt;MonadWriter&lt;/code&gt; to keep track of new IO actions it needs to cache. The “magic” happens in &lt;code&gt;runAgain&lt;/code&gt;, which runs it through once with an empty state, and then returns a new action with the MonadWriter results moved into the state for the next time around:&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;runAgain&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;ot&quot;&gt;    ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; m&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;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Again&lt;/span&gt; m a&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;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (m a)&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;runAgain action &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-6&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb3-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (a, w) &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; evalRWST (runAgain' action) () []&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;fu&quot;&gt;return&lt;/span&gt; &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;cb3-8&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb3-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        evalRWST (runAgain' action) () w&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 class=&quot;fu&quot;&gt;return&lt;/span&gt; a&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Simple. Clean. Elegant. Too bad it doesn’t actually work.&lt;/p&gt;
&lt;p&gt;The following program crashes with an error coming from the unsafe use of &lt;code&gt;fromJust&lt;/code&gt; in &lt;code&gt;once&lt;/code&gt;:&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;ot&quot;&gt;oops ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Again&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;StateT&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Bool&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&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;oops &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&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 class=&quot;co&quot;&gt;-- Branch on the StateT&lt;/span&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;  lift get &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;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;co&quot;&gt;-- The first time around...&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;dt&quot;&gt;False&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;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;co&quot;&gt;-- Cache a unit value&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;      once &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;print&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;      &lt;span class=&quot;co&quot;&gt;-- Change the state value&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;      lift &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; put &lt;span class=&quot;dt&quot;&gt;True&lt;/span&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&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 class=&quot;co&quot;&gt;-- Since the state changed at the end of the first branch, we will take this&lt;/span&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;co&quot;&gt;-- branch the second time around...&lt;/span&gt;&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;dt&quot;&gt;True&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;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;co&quot;&gt;-- Calling 'once' the second time around gets its value from the cache,&lt;/span&gt;&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;co&quot;&gt;-- which has type @()@. But at this callsite, it ought to have type&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-17&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb4-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;co&quot;&gt;-- @Bool -&amp;gt; Bool@. Uh oh!&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-18&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb4-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      f &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; once &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;not&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-19&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb4-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      lift &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;st&quot;&gt;&quot;uh oh!&quot;&lt;/span&gt;, f &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb4-20&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb4-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-21&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb4-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-22&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb4-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;ohNo ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; ((), &lt;span class=&quot;dt&quot;&gt;Bool&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb4-23&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb4-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ohNo &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;flip&lt;/span&gt; runStateT &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt; &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;cb4-24&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb4-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  m &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; runAgain oops&lt;/span&gt;
&lt;span id=&quot;cb4-25&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb4-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  m&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The attack here comes from the fact that we can force the &lt;code&gt;Again&lt;/code&gt; program down a different code path its second time around. And that second time, it encounters a call to &lt;code&gt;once&lt;/code&gt; which has a different type than the one it cached. Thus, trying to reuse the cache leads to what is effectively a type error at runtime.&lt;/p&gt;
&lt;p&gt;What actually went wrong here? The problem is that &lt;a href=&quot;https://chrispenner.ca/posts/expressiveness-spectrum&quot;&gt;monads are too powerful&lt;/a&gt;. Since the only way to compose monads is via bind (&lt;code&gt;m a -&amp;gt; (a -&amp;gt; m b) -&amp;gt; m b&lt;/code&gt;), we are forced to extend a monadic value of type &lt;code&gt;m a&lt;/code&gt; by a &lt;em&gt;function&lt;/em&gt; of type &lt;code&gt;a -&amp;gt; m b&lt;/code&gt;. Which is to say that the “next thing to do” in a monadic computation is always going to be a function. And functions are completely opaque. So, once we’re given a monad, there’s simply no way to know what it’s going to do without actually running the continuation.&lt;/p&gt;
&lt;p&gt;The problem arises from the fact that that continuation can invisibly branch. My &lt;code&gt;Again&lt;/code&gt; monad was attempting to &lt;em&gt;statically analyze&lt;/em&gt; the monadic computation, and cache the IO results in a queue. But as &lt;code&gt;oops&lt;/code&gt; shows, it’s trivial to break this sort of static analysis. Because the branch is hidden inside of a function, and there’s no way to determine which branches a function &lt;em&gt;didn’t take.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;But I didn’t know that eleven years ago, so I give myself a pass on this one. Nevertheless, let’s tackle this problem with the wisdom of ages.&lt;/p&gt;
&lt;h2 id=&quot;no-more-monads&quot;&gt;No More Monads&lt;/h2&gt;
&lt;p&gt;So if the problem with my previous implementation of &lt;code&gt;Again&lt;/code&gt; is that it’s a monad, what options do we have? As it happens, there are two very nice options available to us here: &lt;em&gt;arrows&lt;/em&gt; and &lt;em&gt;selective applicative functors.&lt;/em&gt; We’ll discuss arrows for now, and come back to selectives.&lt;/p&gt;
&lt;p&gt;Long time readers might remember a &lt;a href=&quot;https://reasonablypolymorphic.com/tags/yampa.html&quot;&gt;series on arrows from a few years back.&lt;/a&gt; But if you don’t, that’s OK; you’re still welcome here. A quick recap:&lt;/p&gt;
&lt;p&gt;Arrows are a generalization of functions. Like functions, they take two type parameters (an input and an output). Like functions, they come with an identity arrow. They compose “end to end” just like functions do. These three properties are expressed as a &lt;code&gt;Category&lt;/code&gt; superclass, which we usually call &lt;code&gt;c&lt;/code&gt; and write infix:&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;kw&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Category&lt;/span&gt; (&lt;span class=&quot;ot&quot;&gt;c ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Type&lt;/span&gt;) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-2&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb5-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;  id  ::&lt;/span&gt; x &lt;span class=&quot;ot&quot;&gt;`c`&lt;/span&gt; x&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; (y &lt;span class=&quot;ot&quot;&gt;`c`&lt;/span&gt; z) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; (x &lt;span class=&quot;ot&quot;&gt;`c`&lt;/span&gt; y) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; (x &lt;span class=&quot;ot&quot;&gt;`c`&lt;/span&gt; z)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In addition to being categories, arrows also come with a means of transforming regular functions into arrows, and of mapping arrows over pairs:&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;kw&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Category&lt;/span&gt; c &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Arrow&lt;/span&gt; c &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://reasonablypolymorphic.com#cb6-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;  arr ::&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; (x &lt;span class=&quot;ot&quot;&gt;`c`&lt;/span&gt; y)&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;ot&quot;&gt;  (***) ::&lt;/span&gt; (x &lt;span class=&quot;ot&quot;&gt;`c`&lt;/span&gt; x') &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; (y &lt;span class=&quot;ot&quot;&gt;`c`&lt;/span&gt; y') &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; ((x, y) &lt;span class=&quot;ot&quot;&gt;`c`&lt;/span&gt; (x', y'))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What’s neat about arrows is that their values are function-like things, rather than being &lt;em&gt;actually functions.&lt;/em&gt; That means when we compose arrows, we compose values whose internals we get to choose. Which in turn, means that static analysis is possible again!&lt;/p&gt;
&lt;p&gt;Attentive readers will notice that there isn’t actually any way for arrows-as-such to be able to branch. To gain that capability, they require an additional &lt;code&gt;ArrowChoice&lt;/code&gt;, which equips them with the ability to lift arrows over &lt;code&gt;Either&lt;/code&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;https://reasonablypolymorphic.com#cb7-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;Arrow&lt;/span&gt; c &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ArrowChoice&lt;/span&gt; c &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://reasonablypolymorphic.com#cb7-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;  (+++) ::&lt;/span&gt; (x &lt;span class=&quot;ot&quot;&gt;`c`&lt;/span&gt; x') &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; (y &lt;span class=&quot;ot&quot;&gt;`c`&lt;/span&gt; y') &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Either&lt;/span&gt; x y &lt;span class=&quot;ot&quot;&gt;`c`&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Either&lt;/span&gt; x' y')&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To wet our whistle, let’s write a little helper &lt;code&gt;Arrow&lt;/code&gt; that shows that the composition of an applicative functor with an arrow is itself an arrow:&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;kw&quot;&gt;newtype&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Static&lt;/span&gt; m c x y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Static&lt;/span&gt;&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; unStatic ::&lt;/span&gt; m (c x y)&lt;/span&gt;
&lt;span id=&quot;cb8-3&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb8-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;The arrow instances for &lt;code&gt;(Applicative m, Arrow c) =&amp;gt; Static m c&lt;/code&gt; are the usual trick of using applicative functions to lift operations into the right place. For example, identity is just &lt;code&gt;pure id, and composition is&lt;/code&gt;liftA2` of composition:&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;kw&quot;&gt;instance&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Category&lt;/span&gt; c, &lt;span class=&quot;dt&quot;&gt;Applicative&lt;/span&gt; m) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Category&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Static&lt;/span&gt; m c) &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://reasonablypolymorphic.com#cb9-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Static&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 class=&quot;fu&quot;&gt;id&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-3&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb9-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Static&lt;/span&gt; g &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Static&lt;/span&gt; f &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Static&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; liftA2 (&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;) g f&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can do the same trick for &lt;code&gt;arr&lt;/code&gt; and &lt;code&gt;(***)&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;kw&quot;&gt;instance&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Arrow&lt;/span&gt; c, &lt;span class=&quot;dt&quot;&gt;Applicative&lt;/span&gt; m) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Arrow&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Static&lt;/span&gt; m c) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-2&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb10-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  arr &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Static&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 class=&quot;op&quot;&gt;.&lt;/span&gt; arr&lt;/span&gt;
&lt;span id=&quot;cb10-3&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb10-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Static&lt;/span&gt; f &lt;span class=&quot;op&quot;&gt;***&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Static&lt;/span&gt; g &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Static&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; liftA2 (&lt;span class=&quot;op&quot;&gt;***&lt;/span&gt;) f g&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;as well as for &lt;code&gt;(+++)&lt;/code&gt;:&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;kw&quot;&gt;instance&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;ArrowChoice&lt;/span&gt; c, &lt;span class=&quot;dt&quot;&gt;Applicative&lt;/span&gt; m) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ArrowChoice&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Static&lt;/span&gt; m c) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-2&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb11-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Static&lt;/span&gt; f &lt;span class=&quot;op&quot;&gt;+++&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Static&lt;/span&gt; g &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Static&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; liftA2 (&lt;span class=&quot;op&quot;&gt;+++&lt;/span&gt;) f g&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What’s nice about this &lt;code&gt;Static&lt;/code&gt; construct we’ve built is that it gives us two degrees of freedom. We’re free to choose an arrow whose structure we’re going to reuse, and an underlying applicative functor (which can give us “static” effects as we’re &lt;em&gt;building&lt;/em&gt; the underlying arrow.)&lt;/p&gt;
&lt;p&gt;The idea here is that we can put the cache-&lt;em&gt;building&lt;/em&gt; machinery inside of the applicative functor, but the cache-&lt;em&gt;reading&lt;/em&gt; machinery inside of the underlying arrow.&lt;/p&gt;
&lt;h3 id=&quot;constructing-again-again&quot;&gt;Constructing Again, Again&lt;/h3&gt;
&lt;p&gt;It’s worth knowing about the Kleisli arrow:&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;kw&quot;&gt;newtype&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Kleisli&lt;/span&gt; m a b &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Kleisli&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 class=&quot;ot&quot;&gt; runKleisli ::&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m b&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&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&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 class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; m &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Category&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Kleisli&lt;/span&gt; m)&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;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; m &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Arrow&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Kleisli&lt;/span&gt; m)&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;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; m &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ArrowChoice&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Kleisli&lt;/span&gt; m)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;which says that any monadic bind function is itself an arrow. Implementing the instances yourself is a fun exercise if you’re new to this stuff. We can reuse &lt;code&gt;Kleisli&lt;/code&gt; as our underlying arrow, which when you expand everything out, we get:&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;kw&quot;&gt;newtype&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Again&lt;/span&gt; m a b &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Again&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-2&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb13-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  {&lt;span class=&quot;ot&quot;&gt; unAgain ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Static&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;Kleisli&lt;/span&gt; m) a b&lt;/span&gt;
&lt;span id=&quot;cb13-3&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb13-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  }&lt;/span&gt;
&lt;span id=&quot;cb13-4&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb13-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 class=&quot;dt&quot;&gt;Category&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Arrow&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;ArrowChoice&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb13-5&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb13-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-6&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb13-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;runAgain ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; m &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Again&lt;/span&gt; m a b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m b)&lt;/span&gt;
&lt;span id=&quot;cb13-7&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb13-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;runAgain &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fmap&lt;/span&gt; runKleisli &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; unStatic &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; unAgain&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What I think is particularly cool about this is that &lt;code&gt;runAgain&lt;/code&gt; is just the composition of the newtype unwrappers, and yet its type is extremely reminiscent of my ten-year-ago implementation:&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;runAgain  &lt;span class=&quot;co&quot;&gt;-- the original&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-2&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb14-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;Monad&lt;/span&gt; m&lt;/span&gt;
&lt;span id=&quot;cb14-3&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb14-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Again&lt;/span&gt; m a&lt;/span&gt;
&lt;span id=&quot;cb14-4&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb14-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (m a)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is an instance of a more general principle, which is that the final “observation” you want to make of your type is always a good &lt;em&gt;representation&lt;/em&gt; of that type. It’s not the only representation, but it’s always a reasonable choice. Appropriately enough, this is known as a &lt;em&gt;final encoding.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Anyway. How can we implement &lt;code&gt;once&lt;/code&gt;? By way of &lt;code&gt;onceF&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;https://reasonablypolymorphic.com#cb15-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;onceF ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;MonadIO&lt;/span&gt; m, &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;IO&lt;/span&gt; b) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Again&lt;/span&gt; m a b&lt;/span&gt;
&lt;span id=&quot;cb15-2&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb15-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;onceF m &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Again&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Static&lt;/span&gt; &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;cb15-3&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb15-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  cache &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; liftIO &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; newIORef &lt;span class=&quot;fu&quot;&gt;mempty&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb15-4&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb15-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;dt&quot;&gt;Kleisli&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; \a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; liftIO &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;cb15-5&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb15-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    cacheMap &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; readIORef cache&lt;/span&gt;
&lt;span id=&quot;cb15-6&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb15-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; M.lookup a cacheMap &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb15-7&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb15-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; b&lt;/span&gt;
&lt;span id=&quot;cb15-8&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb15-8&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;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb15-9&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb15-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        b &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; m a&lt;/span&gt;
&lt;span id=&quot;cb15-10&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb15-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        modifyIORef' cache &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; M.insert a b&lt;/span&gt;
&lt;span id=&quot;cb15-11&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb15-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; b&lt;/span&gt;
&lt;span id=&quot;cb15-12&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#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://reasonablypolymorphic.com#cb15-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;once ::&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; &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;Again&lt;/span&gt; m a b&lt;/span&gt;
&lt;span id=&quot;cb15-14&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb15-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;once m &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; arr (&lt;span class=&quot;fu&quot;&gt;const&lt;/span&gt; ()) &lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; onceF (&lt;span class=&quot;fu&quot;&gt;const&lt;/span&gt; m)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;onceF&lt;/code&gt; works by constructing a &lt;code&gt;cache :: IORef (Map a b)&lt;/code&gt; at the &lt;code&gt;Static&lt;/code&gt; level. Each call to &lt;code&gt;onceF&lt;/code&gt; gets a unique cache. Then we drop into the implementation of the &lt;code&gt;Kleisli&lt;/code&gt; arrow (which recall happens at &lt;em&gt;runtime&lt;/em&gt;.) Inside the &lt;code&gt;Kleisli&lt;/code&gt;, we check to see if the map has a value at the requested &lt;code&gt;a&lt;/code&gt;, and if so, return the cached &lt;code&gt;b&lt;/code&gt;. If not, we run our function and cache it.&lt;/p&gt;
&lt;p&gt;Since there’s no &lt;code&gt;Dynamic&lt;/code&gt; tomfoolery here that is existentializing away our types, we don’t need to worry about the &lt;code&gt;oops&lt;/code&gt; attack; Haskell’s type system guarantees we can’t construct such a thing.&lt;/p&gt;
&lt;p&gt;Because &lt;code&gt;Again&lt;/code&gt; isn’t a &lt;code&gt;Monad&lt;/code&gt;, it can’t be a &lt;code&gt;MonadIO&lt;/code&gt; either. But it’s nice to be able to provide the equivalent of &lt;code&gt;liftIO&lt;/code&gt;:&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://reasonablypolymorphic.com#cb16-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;againF ::&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; (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;Again&lt;/span&gt; m a b&lt;/span&gt;
&lt;span id=&quot;cb16-2&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;againF &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Again&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Static&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 class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Kleisli&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fmap&lt;/span&gt; liftIO&lt;/span&gt;
&lt;span id=&quot;cb16-3&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#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://reasonablypolymorphic.com#cb16-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;again ::&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; &lt;span class=&quot;dt&quot;&gt;IO&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Again&lt;/span&gt; m x a&lt;/span&gt;
&lt;span id=&quot;cb16-5&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;again m &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; arr (&lt;span class=&quot;fu&quot;&gt;const&lt;/span&gt; ()) &lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; againF (&lt;span class=&quot;fu&quot;&gt;const&lt;/span&gt; m)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So that completes our arrow-based implementation of &lt;code&gt;Again&lt;/code&gt;. But there’s still something left undone.&lt;/p&gt;
&lt;h3 id=&quot;circling-back-to-selectives&quot;&gt;Circling Back to Selectives&lt;/h3&gt;
&lt;p&gt;I said earlier that selective applicative functors would be an alternative approach to implementing &lt;code&gt;Again&lt;/code&gt;. Selectives rightfully sit between &lt;code&gt;Applicative&lt;/code&gt; and &lt;code&gt;Monad&lt;/code&gt; in the functor hierarchy, but were &lt;a href=&quot;https://dl.acm.org/doi/10.1145/3341694&quot;&gt;discovered too late&lt;/a&gt;, and everyone was still kind of annoyed about having had just stuck &lt;code&gt;Applicative&lt;/code&gt; into the hierarchy.&lt;/p&gt;
&lt;p&gt;What, precisely is a selective functor? It’s a different solution to the problem of “monads are too powerful” which gives us a branching primitive to play with. Behold:&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://reasonablypolymorphic.com#cb17-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;Applicative&lt;/span&gt; f &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Selective&lt;/span&gt; f &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://reasonablypolymorphic.com#cb17-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;  select ::&lt;/span&gt; f (&lt;span class=&quot;dt&quot;&gt;Either&lt;/span&gt; a b) &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; b) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; f b&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;select&lt;/code&gt; says that you might have an &lt;code&gt;a&lt;/code&gt;, in which case you must run the provided &lt;code&gt;f (a -&amp;gt; b)&lt;/code&gt;. But maybe you have a &lt;code&gt;b&lt;/code&gt;, in which case you &lt;em&gt;may&lt;/em&gt; run the effects of the &lt;code&gt;f (a -&amp;gt; b)&lt;/code&gt;. But nobody’s forcing you to.&lt;/p&gt;
&lt;p&gt;Since there are still no raw function continuations to be seen here, we can use &lt;code&gt;select&lt;/code&gt; to provide branching to our programs. But all of the branches can be identified statically, since we’re only operating on &lt;code&gt;f&lt;/code&gt; values, again, whose internals we can control.&lt;/p&gt;
&lt;p&gt;In fact, by aggressively nesting &lt;code&gt;select&lt;/code&gt; calls, you can get back a version of monadic bind — so long as you have a finite number of select calls you’d need to make:&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://reasonablypolymorphic.com#cb18-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;bindS&lt;/span&gt;
&lt;span id=&quot;cb18-2&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb18-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;Selective&lt;/span&gt; f, &lt;span class=&quot;dt&quot;&gt;Enum&lt;/span&gt; a, &lt;span class=&quot;dt&quot;&gt;Bounded&lt;/span&gt; a, &lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt; a)&lt;/span&gt;
&lt;span id=&quot;cb18-3&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb18-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; f a&lt;/span&gt;
&lt;span id=&quot;cb18-4&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb18-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&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; f b)&lt;/span&gt;
&lt;span id=&quot;cb18-5&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb18-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; f b&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(the implementation of which is fun if you’re looking for a challenge)&lt;/p&gt;
&lt;p&gt;Anyway, all of this is to say that we could have equally structured our &lt;code&gt;Again&lt;/code&gt; as a selective functor rather than as an arrow! But &lt;code&gt;ArrowChoice&lt;/code&gt; is at least as powerful as &lt;code&gt;Selective&lt;/code&gt;, so given all of our hard work already, we can pull out a &lt;code&gt;Selective&lt;/code&gt; instance for free.&lt;/p&gt;
&lt;p&gt;What do I mean when I say “at least as powerful?” It means we can derive it for free, given an &lt;code&gt;ArrowChoice&lt;/code&gt; instance. Behold, the &lt;code&gt;GenericArrow&lt;/code&gt; newtype, which exists only for us to have something to attach some instances to.&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://reasonablypolymorphic.com#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;GenericArrow&lt;/span&gt; c x a &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;GenericArrow&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-2&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb19-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  {&lt;span class=&quot;ot&quot;&gt; unGenericArrow ::&lt;/span&gt; c x a&lt;/span&gt;
&lt;span id=&quot;cb19-3&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#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://reasonablypolymorphic.com#cb19-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 class=&quot;dt&quot;&gt;Category&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Arrow&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;ArrowChoice&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here we use newtype deriving to say that if &lt;code&gt;c&lt;/code&gt; is a category/arrow/arrowchoice, then &lt;code&gt;GenericArrow c&lt;/code&gt; is too. But now we can show that having &lt;code&gt;Arrow&lt;/code&gt; is enough to get &lt;code&gt;Functor&lt;/code&gt; and &lt;code&gt;Applicative&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://reasonablypolymorphic.com#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;Arrow&lt;/span&gt; c &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Functor&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;GenericArrow&lt;/span&gt; c x) &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://reasonablypolymorphic.com#cb20-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;fmap&lt;/span&gt; f c &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; arr f &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; c&lt;/span&gt;
&lt;span id=&quot;cb20-3&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb20-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-4&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb20-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;Arrow&lt;/span&gt; c &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;GenericArrow&lt;/span&gt; c x) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-5&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb20-5&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; arr &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;const&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-6&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb20-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  liftA2 f x y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; (x &lt;span class=&quot;op&quot;&gt;&amp;amp;&amp;amp;&amp;amp;&lt;/span&gt; y) &lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; arr (&lt;span class=&quot;fu&quot;&gt;uncurry&lt;/span&gt; f)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then, given an &lt;code&gt;ArrowChoice&lt;/code&gt;, we can get an implementation of &lt;code&gt;select&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb21&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb21-1&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#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;ArrowChoice&lt;/span&gt; c &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Selective&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;GenericArrow&lt;/span&gt; c x) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-2&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb21-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  select te tk &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; proc b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-3&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb21-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    e &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; te &lt;span class=&quot;op&quot;&gt;-&amp;lt;&lt;/span&gt; b&lt;/span&gt;
&lt;span id=&quot;cb21-4&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb21-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; e &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;https://reasonablypolymorphic.com#cb21-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;Left&lt;/span&gt; x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-6&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb21-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        k &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; tk &lt;span class=&quot;op&quot;&gt;-&amp;lt;&lt;/span&gt; b&lt;/span&gt;
&lt;span id=&quot;cb21-7&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb21-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        returnA &lt;span class=&quot;op&quot;&gt;-&amp;lt;&lt;/span&gt; k x&lt;/span&gt;
&lt;span id=&quot;cb21-8&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb21-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;Right&lt;/span&gt; y &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; returnA &lt;span class=&quot;op&quot;&gt;-&amp;lt;&lt;/span&gt; y&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here we don’t have the option of choosing to invoke &lt;code&gt;tk&lt;/code&gt; in the &lt;code&gt;Right&lt;/code&gt; case. But that’s OK, because in &lt;code&gt;Again&lt;/code&gt;, doing so would correspond to creating caches for branches that don’t need it.&lt;/p&gt;
&lt;p&gt;Given all of this, we can now derive &lt;code&gt;Functor&lt;/code&gt; up to &lt;code&gt;Selective&lt;/code&gt; for &lt;code&gt;Again&lt;/code&gt;:&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://reasonablypolymorphic.com#cb22-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;Again&lt;/span&gt; m a b &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Again&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb22-2&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb22-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  {&lt;span class=&quot;ot&quot;&gt; unAgain ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Static&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;Kleisli&lt;/span&gt; m) a b&lt;/span&gt;
&lt;span id=&quot;cb22-3&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#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://reasonablypolymorphic.com#cb22-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 class=&quot;dt&quot;&gt;Category&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Arrow&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;ArrowChoice&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb22-5&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb22-5&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;Functor&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Applicative&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Selective&lt;/span&gt;) via &lt;span class=&quot;dt&quot;&gt;GenericArrow&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Again&lt;/span&gt; m) a&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;which means that users can now choose between the arrow hierarchy and the functor hierarchy for how they’d like to think about building &lt;code&gt;Again&lt;/code&gt; actions. And to nudge them even a little further, we can introduce something that looks like a monad transformer, removing the input parameter:&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://reasonablypolymorphic.com#cb23-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;AgainT&lt;/span&gt; m &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Again&lt;/span&gt; m ()&lt;/span&gt;
&lt;span id=&quot;cb23-2&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#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;https://reasonablypolymorphic.com#cb23-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;runAgainT ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; m &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;AgainT&lt;/span&gt; m a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (m a)&lt;/span&gt;
&lt;span id=&quot;cb23-4&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb23-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;runAgainT &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fmap&lt;/span&gt; (&lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; ()) &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; runAgain&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Clean. Tidy. Actually works this time around.&lt;/p&gt;</description>
	<pubDate>Mon, 24 Aug 2026 23:26:00 +0000</pubDate>
</item>
<item>
	<title>Chris Smith 2: How to (Almost) Trisect an Angle</title>
	<guid isPermaLink="false">https://medium.com/p/c5c6aaf40620</guid>
	<link>https://cdsmithus.medium.com/how-to-almost-trisect-an-angle-c5c6aaf40620?source=rss-18bd5acaea78------2</link>
	<description>&lt;p&gt;In 1837 Pierre Wantzel proved that no compass-and-straightedge construction can trisect every angle. The counterexample is 60°: trisecting it would mean constructing cos 20°, which is a root of an irreducible cubic, while a compass and straightedge can only build stacks of square roots: objects of degree 2, 4, 8, never 3. And since 60° is easy to construct, any general method for trisection would have to trisect that one, too.&lt;/p&gt;&lt;p&gt;None of this has stopped people trying. For well over a century, mathematics departments have received a steady stream of constructions from amateurs convinced they’d done the impossible, enough of them that Underwood Dudley filled a whole book, &lt;em&gt;The Trisectors&lt;/em&gt;, with them.&lt;/p&gt;&lt;p&gt;I used to be one of those amateurs. Well, I was twelve, and my construction never made it into any mathematician’s inbox. But I had the essentials: a method, a compass and straightedge, a very exasperated geometry teacher, and a conviction that the experts had given up too soon.&lt;/p&gt;&lt;h4&gt;What you can trisect&lt;/h4&gt;&lt;p&gt;So you can’t trisect an angle, but there are things you can trisect. Say the angle is AVB, with vertex V and measure θ, and mark A and B the same distance out from V. Draw the arc centered at V from A to B. Cutting that arc into three equal pieces is the same as cutting the angle into three, so the whole problem comes down to trisecting that one arc, and that arc is the one Wantzel showed is off limits. But it belongs to a whole family of arcs from A to B, some fatter, some flatter, and other members of the family can be trisected exactly.&lt;/p&gt;&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;https://cdn-images-1.medium.com/max/1024/1*MiNrmJbppGEwmtZ1L6vM4g.png&quot; /&gt;&lt;/figure&gt;&lt;p&gt;Pick one, trisect it, and read the result back as an approximate trisection of the angle. How wrong you are depends on how far apart the two arcs sit.&lt;/p&gt;&lt;h4&gt;Idea #1: Trisect the chord instead&lt;/h4&gt;&lt;p&gt;Start with the flattest member of the family. Push the arc’s center infinitely far back and the arc straightens into the segment AB itself. Segments can be trisected exactly, by a standard similar-triangles construction, or more slickly through the centroid of a triangle. Either way, trisect AB, draw rays through the two division points, and you have approximate trisectors. Call this &lt;strong&gt;chord trisection&lt;/strong&gt;.&lt;/p&gt;&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;https://cdn-images-1.medium.com/max/1024/1*Ttp7_wErMGaBfKmbDndLpA.png&quot; /&gt;&lt;/figure&gt;&lt;p&gt;For narrow angles, chord trisection works remarkably well. As the angle shrinks the arc flattens toward its chord, and the error vanishes like θ³/81 (in radians, plus higher-order terms). That cubic is fast: a 4° angle gets trisected to within a few ten-thousandths of a degree. Wide angles are another story. The arc bulges away from the chord, the chord’s trisection points crowd toward the sides of the angle, and as θ approaches 180° the middle third of the trisection swallows the whole angle.&lt;/p&gt;&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;https://cdn-images-1.medium.com/max/1024/1*SlV2iKbxEuP0VXx0Y9Mm5g.png&quot; /&gt;&lt;/figure&gt;&lt;p&gt;So chord trisection is wonderful for narrow angles and hopeless for wide ones.&lt;/p&gt;&lt;h4&gt;Idea #2: Trisect a semicircle instead&lt;/h4&gt;&lt;p&gt;This is the method I found that year in geometry class. Slide the arc’s center the other way, up from V as far as it will go, to the midpoint of AB. The arc swells into the semicircle on AB, pointing away from V. A semicircle is easy to trisect, because its thirds are 60° arcs, and you mark those off by stepping the radius along the arc with your compass. Rays from V through the two marks are your approximate trisectors. Call this &lt;strong&gt;semicircle trisection&lt;/strong&gt;.&lt;/p&gt;&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;https://cdn-images-1.medium.com/max/1024/1*ra4-y4Jqc_rBjLpIabobWg.png&quot; /&gt;&lt;/figure&gt;&lt;p&gt;You’d expect semicircle trisection to do well at wide angles, and it does. At θ = 180° the semicircle stops being a stand-in altogether: V lands at the midpoint of AB, the semicircle coincides with the angle’s own arc, and the trisection is exact. Narrow the angle from there and the true arc pulls away from the semicircle, so the error grows…&lt;/p&gt;&lt;p&gt;Then it does something surprising: it turns around, comes back to exactly zero at θ = 90°, then rises and falls once more on the way down to zero at θ = 0, never getting more than 1.226° from the true trisector anywhere along the way. The worst cases sit at arcsin(1/√3) ≈ 35° and its supplement near 145°.&lt;/p&gt;&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;https://cdn-images-1.medium.com/max/1024/1*p2kj376RuHWcb8UBWmSfQw.png&quot; /&gt;&lt;/figure&gt;&lt;p&gt;The zero at 0° is just collapse. A and B merge, the whole angle closes onto a single ray, and the constructed trisectors converge onto it along with everything else. The zero at 90° is the interesting one, and it turns out to be the inscribed angle theorem. A right angle inscribed in a circle subtends a diameter, so a 90° vertex V lies on the very circle the trisection marks were drawn on, and each 60° arc of that circle subtends exactly 30° at V.&lt;/p&gt;&lt;p&gt;You can see how I fell for this. The three cases I knew how to check — 0°, 90°, 180° — were all exact, and an error under 1.226° passes the eyeball test everywhere else. The weakness hides at small angles, which are the hardest to check on paper. As θ approaches 0, semicircle trisection hands back a ray a quarter of the way across the angle instead of a third. Less than a degree off, sure, but when the whole angle is a few degrees, that’s a low bar. The error remains a substantial fraction of the answer no matter how small θ gets.&lt;/p&gt;&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;https://cdn-images-1.medium.com/max/1024/1*m8LjrHAUy4ldOqV76X-yTA.png&quot; /&gt;&lt;/figure&gt;&lt;p&gt;We have two approximations, then, with opposite strengths. Chord trisection converges cubically for small angles but blows up for large ones. Semicircle trisection stays within about a degree everywhere but converges to the wrong ray as the angle shrinks. It would be nice to get the best of both worlds, wouldn’t it?&lt;/p&gt;&lt;h4&gt;Bridge: The exact residual trick&lt;/h4&gt;&lt;p&gt;Draw the arc centered at V through A and B, and suppose someone hands you a guess: a point G on the arc, with VG claimed to be a trisector. Set your compass to the chord distance from A to G. Starting at B, step backwards that distance twice along the arc toward A, and call the landing point H.&lt;/p&gt;&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;https://cdn-images-1.medium.com/max/1024/1*MTtE06mJVAYuOwSS0co2hg.png&quot; /&gt;&lt;/figure&gt;&lt;p&gt;Claim: the trisector of the (probably small) angle GVH adjacent to VG is exactly the trisector of AVB adjacent to VA.&lt;/p&gt;&lt;p&gt;Proof: Write the guess as arc(A→G) = θ/3 + ε, where ε is its unknown error. Each compass step from B moves an arc of θ/3 + ε, so after two steps H sits at θ − 2(θ/3 + ε) = θ/3 − 2ε from A. The residual arc from H to G is therefore exactly 3ε, and a third of the way from G toward H lands at θ/3 + ε − ε = θ/3, for either sign of ε.&lt;/p&gt;&lt;p&gt;The residual angle GVH is exactly three times the guess’s error, and nothing in the reduction is approximate. Trisecting AVB has been converted, exactly, into trisecting a much smaller angle.&lt;/p&gt;&lt;h4&gt;Putting the pieces together&lt;/h4&gt;&lt;p&gt;So here’s the plan. Feed any angle at all, 5° or 175°, to semicircle trisection, and it hands back a guess within 1.226° of the true trisector. The residual trick then turns that guarantee into a fresh problem: an angle of at most 3.68° whose trisector is exactly the ray we’re after. And 3.68° is chord territory, small enough for the cubic convergence to bite, handing us a remarkable 0.674 arcseconds of error: roughly the angle spanned by a penny viewed from three and a half miles away.&lt;/p&gt;&lt;figure&gt;&lt;img alt=&quot;&quot; src=&quot;https://cdn-images-1.medium.com/max/1024/1*XSWCXuC9io-wwd1FVn2eNw.png&quot; /&gt;&lt;/figure&gt;&lt;p&gt;Nothing stops you from running the residual trick again on the improved answer; each round cubes the error. But one pass already lands within an arcsecond, and iterating would be polishing a quantity that stopped mattering a step ago.&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=c5c6aaf40620&quot; width=&quot;1&quot; /&gt;</description>
	<pubDate>Sun, 23 Aug 2026 14:46:19 +0000</pubDate>
</item>
<item>
	<title>Mark Jason Dominus: The road to epsilon-zero: Shortlex order also orders sequences of numbers</title>
	<guid isPermaLink="false">tag:,2026:/math/ordinals/06-nim-shortlex</guid>
	<link>https://blog.plover.com/math/ordinals/06-nim-shortlex.html</link>
	<description>&lt;p&gt;Previously:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.plover.com/math/epsilon-zero.html&quot;&gt;Ordinal numbers and basic set theory &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.plover.com/math/ordinals/01-nim.html&quot;&gt;Ordinals as nim-heaps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.plover.com/math/ordinals/02-wellfoundedness.html&quot;&gt;Nim always ends, even with infinite ordinals&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.plover.com/math/ordinals/03-track-tokens.html&quot;&gt;Infinite Nim as a coin-moving game&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.plover.com/math/ordinals/04-coordinates.html&quot;&gt;Coin-moving games with no coins&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.plover.com/math/ordinals/05-shortlex.html&quot;&gt;Productive programs and well-founded orders&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In part 4, &lt;a href=&quot;https://blog.plover.com/math/ordinals/03-track-tokens.html&quot;&gt;Infinite Nim as a coin-moving game&lt;/a&gt;, we saw how to
reinterpret infinite Nim into an equivalent game: instead of heaps of
beans and various special tokens, we interpreted it as a game about
moving coins first on a track, then on a grid, and then in a rather
difficult-to-visualize infinite-dimensional space.&lt;/p&gt;

&lt;p&gt;In part 5, &lt;a href=&quot;https://blog.plover.com/math/ordinals/04-coordinates.html&quot;&gt;Coin-moving games with no coins&lt;/a&gt;, we stopped
thinking about the coins and their locations in space, and just wrote
down the coordinates of each coin. Each coin has an infinite sequence
of coordinates, each of which is a non-negative number.  But
crucially, only a &lt;em&gt;finite&lt;/em&gt; number of the coordinates are greater than
zero, so every coin's list of coordinates can be written down as a
&lt;em&gt;finite&lt;/em&gt; sequence, with the infinite tail of zeroes left implicit.&lt;/p&gt;

&lt;p&gt;The rule for the original game of Nim was: take as many beans as you
want from any &lt;em&gt;one&lt;/em&gt; pile.&lt;/p&gt;

&lt;p&gt;The rule for the reinterpreted form is: reduce any &lt;em&gt;one&lt;/em&gt; sequence of
coordinates, as follows:&lt;/p&gt;

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

&lt;p&gt;For example, we can move from &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%e2%9f%a82%2c%203%e2%9f%a9%24&quot; /&gt; to &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%e2%9f%a817%2c%202%e2%9f%a9%24&quot; /&gt; (the &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%243%24&quot; /&gt; has
decreased), or to &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%e2%9f%a81%2c%203%e2%9f%a9%24&quot; /&gt; (the &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%242%24&quot; /&gt; has decreased).  We can
move from &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%e2%9f%a89%2c%203%2c%207%e2%9f%a9%24&quot; /&gt; to &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%e2%9f%a81000%2c%2023%2c%205%e2%9f%a9%24&quot; /&gt; (the &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%247%24&quot; /&gt; has
decreased), or to &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%e2%9f%a886%2c%2019%2c%200%e2%9f%a9%24&quot; /&gt;, which
we can also write as &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%e2%9f%a886%2c%2019%e2%9f%a9%24&quot; /&gt;.&lt;/p&gt;

&lt;p&gt;Now that we've learned about shortlex order, we can state the game
rule more simply:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Replace any &lt;em&gt;one&lt;/em&gt; sequence of coordinates with one that is earlier
  &lt;em&gt;in shortlex order&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There's one minor wrinkle.  We had defined shortlex order as:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If the sequences  are different lengths, the &lt;strong&gt;shorter one&lt;/strong&gt; comes first.&lt;/li&gt;
&lt;li&gt;If they're the &lt;strong&gt;same length&lt;/strong&gt;, compare them lexicographically.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None of that has changed, but we need to be a bit careful about
“lexicographically”.&lt;/p&gt;

&lt;p&gt;When we write ordinary numerals, like &lt;code&gt;239&lt;/code&gt;, we write the most
significant part on the left.  In this case it's the &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%242%24&quot; /&gt;, which represents
&lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24200%24&quot; /&gt;. And when we compare numerals of the same length
lexicographically, we compare these most significant parts first,
moving rightward only if the leftmost parts are tied.&lt;/p&gt;



&lt;p&gt;To lexicographically compare sequences of coordinates or the same
length, we still need to begin with the most significant part as
before.  But because of how we are writing the sequences, the most
significant part is the &lt;em&gt;rightmost&lt;/em&gt; component.  A sequence like &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%e2%9f%a89%2c%0a3%2c%202%e2%9f%a9%24&quot; /&gt; represents a nim-heap of &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%249%20%2b%20%cf%89%c2%b73%20%2b%cf%89%5e2%c2%b72%24&quot; /&gt;  beans, and the
&lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%242%24&quot; /&gt;  is the most significant component, because &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%5e2%c2%b72%24&quot; /&gt; is vastly
more than &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%249%2b%cf%89%c2%b73%24&quot; /&gt;  beans.&lt;/p&gt;



&lt;p&gt;I said at some point that &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%5e%cf%89%24&quot; /&gt; was where the ordinals start to get
scary. But &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%5e%cf%89%24&quot; /&gt;  is now not scary at all.
It's just the family of of nim-heaps where:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Instead of beans, we think of a heap as a finite sequence of finite numbers&lt;/li&gt;
&lt;li&gt;Instead of imagining the player removing beans from a heap, we
imagine them replacing the sequence with a sequence that is earlier
in shortlex order&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And to play Nim with ⸢heaps⸣ of this sort, the winning rule is, as
always, that the winner is the player who reduces the last ⸢heap⸣ to
to zero.&lt;/p&gt;

&lt;p&gt;We can completely forget about beans, about infinite piles, about
infinite varieties of colored tokens, about coins moving around in
infinite-dimensional spaces, and so on.  &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%5e%cf%89%24&quot; /&gt;-Nim is just finite
sequences of ordinary numbers, and you can move from one sequence to
any earlier one.&lt;/p&gt;

&lt;p&gt;I think &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%ce%b5_0%24&quot; /&gt; is going to arrive in the next article.&lt;/p&gt;

&lt;p&gt;Claude was on vacation this week, and took all the
em-dashes with it, so I not only had to write the whole thing myself,
I couldn't even put in any em-dashes.&lt;/p&gt;</description>
	<pubDate>Sat, 22 Aug 2026 00:26:00 +0000</pubDate>
	<author>mjd@plover.com (Mark Dominus)</author>
</item>
<item>
	<title>Sandy Maguire: Code-Reviewing My First Monad Implementation</title>
	<guid isPermaLink="true">https://reasonablypolymorphic.com/blog/reviewing-my-first-monad/index.html</guid>
	<link>https://reasonablypolymorphic.com/blog/reviewing-my-first-monad/index.html</link>
	<description>&lt;p&gt;I’ve been wanting to get back into the habit of blogging, and thought a fun project would be to go back through my old code and review it as the programmer I am now. So let’s do that.&lt;/p&gt;
&lt;p&gt;Eleven years ago, I was so proud to written my first monad that I typed up a big ol&lt;a href=&quot;https://sandymaguire.me/blog/jurisdiction-of-heaven/&quot;&gt;blog post about it.&lt;/a&gt; This seems like a fun thing to revisit, so let’s do it.&lt;/p&gt;
&lt;p&gt;To save you the trouble of reading that ancient-ass blog post, here’s the gist. Given a big piece of state, that has many smaller stateful subcomponents, for example, a &lt;code&gt;World&lt;/code&gt; is full of &lt;code&gt;Buffer&lt;/code&gt;s:&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://reasonablypolymorphic.com#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;World&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;World&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-2&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb1-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  {&lt;span class=&quot;ot&quot;&gt; wBuffers ::&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;Buffer&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb1-3&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb1-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ,&lt;span class=&quot;ot&quot;&gt; wCurrent ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-4&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb1-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ,&lt;span class=&quot;ot&quot;&gt; wMode    ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Mode&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-5&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#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://reasonablypolymorphic.com#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://reasonablypolymorphic.com#cb1-7&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;Buffer&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Buffer&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-8&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb1-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  {&lt;span class=&quot;ot&quot;&gt; bFilename ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;FilePath&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-9&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb1-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ,&lt;span class=&quot;ot&quot;&gt; bContent  ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-10&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb1-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;my monad acted like &lt;code&gt;StateT&lt;/code&gt; except that you can restrict the piece of the state you’re allowed to manipulate &lt;em&gt;without losing the ability to look at the rest of the state.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In the blog post, this monad is called &lt;code&gt;Jurisdiction&lt;/code&gt;, but at some point in the &lt;a href=&quot;https://github.com/isovector/eden&quot;&gt;source code&lt;/a&gt; it got renamed to &lt;a href=&quot;https://github.com/isovector/eden/blob/master/src/Control/Monad/Jail.hs&quot;&gt;&lt;code&gt;JailT&lt;/code&gt;&lt;/a&gt;. Cool name. Furthermore, the implementation changed rather dramatically from the blog post, so let’s chase the implementation as given. I’ll reproduce it 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://reasonablypolymorphic.com#cb2-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;RLens&lt;/span&gt; r s &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Lens&lt;/span&gt; s s r r&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&gt;
&lt;span id=&quot;cb2-3&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-3&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;JailT&lt;/span&gt; s r m a &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-4&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-5&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    {&lt;span class=&quot;ot&quot;&gt; runJailT' ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Bool&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-6&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-6&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;RLens&lt;/span&gt; r s&lt;/span&gt;
&lt;span id=&quot;cb2-7&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; s&lt;/span&gt;
&lt;span id=&quot;cb2-8&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (a, s, &lt;span class=&quot;dt&quot;&gt;RLens&lt;/span&gt; r s, &lt;span class=&quot;dt&quot;&gt;Bool&lt;/span&gt;) }&lt;/span&gt;
&lt;span id=&quot;cb2-9&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-9&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;Functor&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Typeable&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb2-10&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-11&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-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;Applicative&lt;/span&gt; m, &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; m) &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;JailT&lt;/span&gt; s r m) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-12&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; x &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; \v l s &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (x, s, l, v)&lt;/span&gt;
&lt;span id=&quot;cb2-13&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;op&quot;&gt;&amp;lt;*&amp;gt;&lt;/span&gt;)  &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ap&lt;/span&gt;
&lt;span id=&quot;cb2-14&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-15&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-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;Applicative&lt;/span&gt; m, &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; m) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; s r m) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-16&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;return&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&gt;
&lt;span id=&quot;cb2-17&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ac &lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; k &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; \v l s &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-18&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;kw&quot;&gt;if&lt;/span&gt; v&lt;/span&gt;
&lt;span id=&quot;cb2-19&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;kw&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-20&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                (x, st', l', v') &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; runJailT' ac v l s&lt;/span&gt;
&lt;span id=&quot;cb2-21&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                runJailT' (k x) v' l' st'&lt;/span&gt;
&lt;span id=&quot;cb2-22&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb2-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;kw&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;return&lt;/span&gt; (&lt;span class=&quot;fu&quot;&gt;undefined&lt;/span&gt;, s, l, v)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Already there’s a lot to look at. The most immediate thing that strikes me is the formatting; now I’m very much a “use two spaces for indent” kind of guy — Haskell doesn’t provide many opportunities for natural linebreaks, and our horizontal space is much more limited than our vertical space. So don’t throw away your horizontal budget on initial spacing. It’s minor, but being an artisan means caring about the minor details.&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;JailT&lt;/span&gt; s r m a &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt;&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;  { runJailT'&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;ot&quot;&gt;      ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Bool&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;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RLens&lt;/span&gt; r s&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;ot&quot;&gt;-&amp;gt;&lt;/span&gt; s&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;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (a, s, &lt;span class=&quot;dt&quot;&gt;RLens&lt;/span&gt; r s, &lt;span class=&quot;dt&quot;&gt;Bool&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&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;  &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Functor&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Typeable&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Much nicer.&lt;/p&gt;
&lt;p&gt;The other exciting thing to see in the earlier snippet is that this code comes from before the Functor-Applicative-Monad transition. Which is to say that it’s from the long long ago before &lt;code&gt;Applicative&lt;/code&gt; was a superclass on &lt;code&gt;Monad&lt;/code&gt;. There’s some history for you.&lt;/p&gt;
&lt;p&gt;And then there is the elephant in the room. Whatever this &lt;code&gt;Bool&lt;/code&gt; is being passed around by &lt;code&gt;runJailT'&lt;/code&gt;, the &lt;code&gt;Monad&lt;/code&gt; instance branches on it and returns &lt;code&gt;undefined&lt;/code&gt; when it’s &lt;code&gt;False&lt;/code&gt;. What the hell is that???? Digging into the &lt;code&gt;MonadPlus&lt;/code&gt; instance provides some insight:&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;instance&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Applicative&lt;/span&gt; m, &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; m) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MonadPlus&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; s r m) &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://reasonablypolymorphic.com#cb4-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    mplus x y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; \v l s &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;cb4-3&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb4-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        x'&lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;(xa, xs, xl, v') &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; runJailT' x v l s&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;if&lt;/span&gt; v'&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;kw&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;return&lt;/span&gt; x'&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;else&lt;/span&gt; runJailT' y v l s&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;    mzero &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; \v l s &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;return&lt;/span&gt; (&lt;span class=&quot;fu&quot;&gt;undefined&lt;/span&gt;, s, l, &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So &lt;code&gt;mzero&lt;/code&gt; returns &lt;code&gt;undefined&lt;/code&gt; and some &lt;code&gt;False&lt;/code&gt; value, presumably which is there to try to warn someone that there’s an &lt;code&gt;undefined&lt;/code&gt; floating around.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This is a stupid design.&lt;/em&gt; If you’re ever in the business of needing to store data-which-might-not-be-valid and a separate tag stating whether or not it’s valid, a much better design here would be to just use &lt;code&gt;Maybe a&lt;/code&gt; instead of &lt;code&gt;(a, Bool)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In fact, perhaps I realized this later on, because &lt;code&gt;runJailT&lt;/code&gt; does exactly this logic:&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;runJailT ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Functor&lt;/span&gt; m)&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 class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; s s m a&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;-&amp;gt;&lt;/span&gt; s&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;         &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; (a, s))&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;runJailT ac &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fmap&lt;/span&gt; (\(a, s, _, v) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-6&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb5-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                            &lt;span class=&quot;kw&quot;&gt;if&lt;/span&gt; v &lt;span class=&quot;kw&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; (a, s) &lt;span class=&quot;kw&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb5-7&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb5-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                    &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; runJailT' ac &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; &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;Let’s roll back a bit. The pivotal primitive of &lt;code&gt;JailT&lt;/code&gt; is the aptly-named &lt;code&gt;jail&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;jail ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; m)&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;     &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RLens&lt;/span&gt; r' r&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;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; s r' m a&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;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; s r m a&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;jail l' m &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; \v l s &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-6&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb6-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (a, s', _, v') &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; runJailT' m v (l &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; l') s&lt;/span&gt;
&lt;span id=&quot;cb6-7&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb6-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;return&lt;/span&gt; (a, s', l, v')&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Pretty reasonable definition here. I’m not sure what the idea behind &lt;code&gt;RLens&lt;/code&gt; being a flipped version of &lt;code&gt;Lens'&lt;/code&gt; was for. The only odd choice here is that in the big tuple returned in &lt;code&gt;jail&lt;/code&gt;, &lt;code&gt;l&lt;/code&gt; gets passed along unchanged. We can tell from looking at it that &lt;code&gt;l&lt;/code&gt; here is the current lens we’re looking at. But &lt;code&gt;jail&lt;/code&gt; is the only primitive that changes the lens, and it takes a &lt;code&gt;JailT&lt;/code&gt; as an argument. Which is all to say that there isn’t anything actually stateful going on with the &lt;code&gt;RLens&lt;/code&gt;. So without looking any further, I’d bet dollars to donuts that this &lt;code&gt;l&lt;/code&gt; getting returned is purely vestigial and serves absolutely no purpose. Which in turn means we should be able to chop it out of the definition of &lt;code&gt;JailT&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Speaking of stupid anti-patterns, here’s another one:&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;into ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RLens&lt;/span&gt; a (&lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; 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;into &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; lens fromJust (&lt;span class=&quot;fu&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb7-3&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#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://reasonablypolymorphic.com#cb7-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;jailMaybe ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Applicative&lt;/span&gt; m, &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; m)&lt;/span&gt;
&lt;span id=&quot;cb7-5&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb7-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;RLens&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; r') r&lt;/span&gt;
&lt;span id=&quot;cb7-6&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb7-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; a&lt;/span&gt;
&lt;span id=&quot;cb7-7&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb7-7&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;JailT&lt;/span&gt; s r' m a&lt;/span&gt;
&lt;span id=&quot;cb7-8&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb7-8&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;JailT&lt;/span&gt; s r m a&lt;/span&gt;
&lt;span id=&quot;cb7-9&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb7-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;jailMaybe l d m &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-10&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb7-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (gets &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; view l) &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;cb7-11&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb7-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; _  &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; jail (l &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; into) m&lt;/span&gt;
&lt;span id=&quot;cb7-12&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb7-12&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;return&lt;/span&gt; d&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is horrendous for a few reasons. &lt;code&gt;into&lt;/code&gt; is an unsafe lens that will crash if you try to read out of a &lt;code&gt;Nothing&lt;/code&gt;. But then that behavior is guarded in &lt;code&gt;jailMaybe&lt;/code&gt; by checking that it isn’t already nothing. Stupid.&lt;/p&gt;
&lt;p&gt;The last function I want to point out is &lt;code&gt;parole&lt;/code&gt;:&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;parole ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Applicative&lt;/span&gt; m, &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; m)&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;=&amp;gt;&lt;/span&gt; a&lt;/span&gt;
&lt;span id=&quot;cb8-3&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb8-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;       &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; s r m (&lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; a)&lt;/span&gt;
&lt;span id=&quot;cb8-4&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb8-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;       &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; s r m a&lt;/span&gt;
&lt;span id=&quot;cb8-5&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb8-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;parole d m &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-6&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb8-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    this &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; get&lt;/span&gt;
&lt;span id=&quot;cb8-7&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb8-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    m &lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-8&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb8-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; a  &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;return&lt;/span&gt; a&lt;/span&gt;
&lt;span id=&quot;cb8-9&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb8-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; put this &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; d&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;which… does… something. I guess it attempts to run a &lt;code&gt;Maybe&lt;/code&gt;-valued &lt;code&gt;JailT&lt;/code&gt;, and if it fails, unwinds the state and returns some default &lt;code&gt;a&lt;/code&gt;. Rearing its ugly head here, however, is the ghost of the &lt;code&gt;undefined&lt;/code&gt; nonsense from &lt;code&gt;mzero&lt;/code&gt;. Note that if we invoke &lt;code&gt;parole a mzero&lt;/code&gt; we will get a &lt;em&gt;crash&lt;/em&gt; rather than the roll-back-and-default behavior that it promises on the tin.&lt;/p&gt;
&lt;p&gt;So, all in all, I am not particularly impressed with my first monad. Here’s how I’d write it today.&lt;/p&gt;
&lt;p&gt;First, I don’t think I’ve written a “control”-y sort of monad from scratch in the last five years. Whatever behavior you want is almost always just the composition of a few monad transformers. In this case, we have a &lt;code&gt;Reader&lt;/code&gt; for the current lens, a &lt;code&gt;State&lt;/code&gt; for the original state, and a &lt;code&gt;Maybe&lt;/code&gt; to give us &lt;code&gt;mzero&lt;/code&gt; semantics.&lt;/p&gt;
&lt;p&gt;Since we want our state to roll-back when we take an alternative path, we must put &lt;code&gt;MaybeT&lt;/code&gt; &lt;em&gt;underneath&lt;/em&gt; our &lt;code&gt;StateT&lt;/code&gt;.&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; This gives us the nice formulation of a &lt;code&gt;JailT&lt;/code&gt; as:&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;kw&quot;&gt;newtype&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; s r m a &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-2&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb9-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  {&lt;span class=&quot;ot&quot;&gt; unJailT ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ReaderT&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;ALens'&lt;/span&gt; s r) (&lt;span class=&quot;dt&quot;&gt;StateT&lt;/span&gt; s (&lt;span class=&quot;dt&quot;&gt;MaybeT&lt;/span&gt; m)) a&lt;/span&gt;
&lt;span id=&quot;cb9-3&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb9-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;(we use &lt;code&gt;ALens' s r&lt;/code&gt; here instead of &lt;code&gt;Lens' s r&lt;/code&gt; since the latter requires &lt;code&gt;-XImpredicativeTypes&lt;/code&gt;. Which happens to be turned on in the original implementation!)&lt;/p&gt;
&lt;p&gt;Once nice thing about defining our monad as a &lt;code&gt;newtype&lt;/code&gt; over a series of monad transformers, is that it allows us to newtype-derive all of the relevant instances:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  deriving newtype (Functor, Applicative, Monad, MonadIO, Alternative)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No implementation for such things is required, and therefore we know that the derived instances must be correct. Which means we have many fewer things to worry about.&lt;/p&gt;
&lt;p&gt;I prefer to use &lt;code&gt;unWhatever&lt;/code&gt; as my naming scheme for these newtypes, so that I can provide &lt;code&gt;runWhatever&lt;/code&gt; as a more user-friendly function.&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;runJailT ::&lt;/span&gt; s &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Lens'&lt;/span&gt; s t &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; s t m a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; (a, s))&lt;/span&gt;
&lt;span id=&quot;cb11-2&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb11-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;runJailT s l &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; runMaybeT &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;flip&lt;/span&gt; runStateT s &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;flip&lt;/span&gt; runReaderT l &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; unJailT&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What’s also nice about using standard monad transformers for your implementation is that you can reuse all of their existing combinators. For example, to implement &lt;code&gt;jail&lt;/code&gt; all we need to do is invoke &lt;code&gt;withReaderT :: (r' -&amp;gt; r) -&amp;gt; ReaderT r m a -&amp;gt; ReaderT r' m a&lt;/code&gt;, which lets us change the type of the reader.&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;jail ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Lens'&lt;/span&gt; t u &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; s u m a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; s t m a&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;jail ltu &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; withReaderT (\lst &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; cloneLens lst &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; ltu) &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; unJailT&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Notice here that I like to minimize my points without going point-free; &lt;code&gt;jail&lt;/code&gt; as written is very legible, but writing it entirely pointfree is a crime against humanity:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-- don't do this!
jail = (JailT .) . (. unJailT) . withReaderT . flip ((.) . cloneLens)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Rather than implementing &lt;code&gt;parole&lt;/code&gt; directly, we can note that it is the composition of two pieces — (1) attempt something, (2) return a default if it failed. Whenever you notice de-composition opportunities like this, take them!&lt;/p&gt;
&lt;p&gt;We can write &lt;code&gt;attempt&lt;/code&gt;, which is wildly general and doesn’t care one fig about jails or the legal system:&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;attempt ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Alternative&lt;/span&gt; m, &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; m) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; a) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m a&lt;/span&gt;
&lt;span id=&quot;cb14-2&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb14-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;attempt m &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;maybe&lt;/span&gt; empty &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&amp;lt;&amp;lt;&lt;/span&gt; m&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and then &lt;code&gt;parole&lt;/code&gt; is merely&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;parole ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; m &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;JailT&lt;/span&gt; s t m (&lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; a) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; s t m a&lt;/span&gt;
&lt;span id=&quot;cb15-2&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb15-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;parole a0 j &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb15-3&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb15-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  asum&lt;/span&gt;
&lt;span id=&quot;cb15-4&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb15-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    [ attempt j&lt;/span&gt;
&lt;span id=&quot;cb15-5&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb15-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    , &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; a0&lt;/span&gt;
&lt;span id=&quot;cb15-6&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb15-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;All in all, significantly nicer if you ask me. &lt;a href=&quot;https://www.youtube.com/watch?v=NgUGvZkQd0M&quot;&gt;But I’m just a TV. Don’t take my word for it.&lt;/a&gt; Compare for yourself!&lt;/p&gt;
&lt;details&gt;

Original Implementation

&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://reasonablypolymorphic.com#cb16-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE GeneralizedNewtypeDeriving,&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-2&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;             FlexibleInstances, MultiParamTypeClasses,&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-3&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;             DeriveFunctor, ImpredicativeTypes, LambdaCase,&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-4&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;             DeriveDataTypeable #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-5&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#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://reasonablypolymorphic.com#cb16-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;Control.Applicative&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Alternative&lt;/span&gt;(..))&lt;/span&gt;
&lt;span id=&quot;cb16-7&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-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;Control.Monad&lt;/span&gt; (ap, &lt;span class=&quot;dt&quot;&gt;MonadPlus&lt;/span&gt;(..))&lt;/span&gt;
&lt;span id=&quot;cb16-8&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-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;Control.Monad.State&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-9&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-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;Control.Lens&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-10&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-10&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; (fromJust)&lt;/span&gt;
&lt;span id=&quot;cb16-11&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-11&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.Typeable&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-12&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-13&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-14&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-14&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;RLens&lt;/span&gt; r s &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Lens&lt;/span&gt; s s r r&lt;/span&gt;
&lt;span id=&quot;cb16-15&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-16&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-16&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;JailT&lt;/span&gt; s r m a &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-17&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-18&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    {&lt;span class=&quot;ot&quot;&gt; runJailT' ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Bool&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-19&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-19&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;RLens&lt;/span&gt; r s&lt;/span&gt;
&lt;span id=&quot;cb16-20&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; s&lt;/span&gt;
&lt;span id=&quot;cb16-21&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (a, s, &lt;span class=&quot;dt&quot;&gt;RLens&lt;/span&gt; r s, &lt;span class=&quot;dt&quot;&gt;Bool&lt;/span&gt;) }&lt;/span&gt;
&lt;span id=&quot;cb16-22&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-22&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;Functor&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Typeable&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb16-23&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-24&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-24&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; m, &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; m) &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;JailT&lt;/span&gt; s r m) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-25&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; x &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; \v l s &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (x, s, l, v)&lt;/span&gt;
&lt;span id=&quot;cb16-26&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-26&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;op&quot;&gt;&amp;lt;*&amp;gt;&lt;/span&gt;)  &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ap&lt;/span&gt;
&lt;span id=&quot;cb16-27&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-27&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-28&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-28&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; m, &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; m) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; s r m) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-29&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-29&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;return&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&gt;
&lt;span id=&quot;cb16-30&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-30&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ac &lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; k &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; \v l s &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-31&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-31&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;kw&quot;&gt;if&lt;/span&gt; v&lt;/span&gt;
&lt;span id=&quot;cb16-32&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-32&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;kw&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-33&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-33&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                (x, st', l', v') &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; runJailT' ac v l s&lt;/span&gt;
&lt;span id=&quot;cb16-34&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-34&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                runJailT' (k x) v' l' st'&lt;/span&gt;
&lt;span id=&quot;cb16-35&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-35&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;kw&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;return&lt;/span&gt; (&lt;span class=&quot;fu&quot;&gt;undefined&lt;/span&gt;, s, l, v)&lt;/span&gt;
&lt;span id=&quot;cb16-36&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-36&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-37&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-37&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; m, &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; m) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MonadState&lt;/span&gt; r (&lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; s r m) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-38&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-38&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    get   &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; \v l s &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;return&lt;/span&gt; (view l s, s, l, v)&lt;/span&gt;
&lt;span id=&quot;cb16-39&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-39&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    put x &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; \v l s &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;return&lt;/span&gt; ((), set l x s, l, v)&lt;/span&gt;
&lt;span id=&quot;cb16-40&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-40&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-41&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-41&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;MonadTrans&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; s r) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-42&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-42&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    lift x &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; \v l s &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; x &lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; (\a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;return&lt;/span&gt; (a, s, l, v))&lt;/span&gt;
&lt;span id=&quot;cb16-43&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-43&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-44&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-44&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; m, &lt;span class=&quot;dt&quot;&gt;MonadIO&lt;/span&gt; m) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MonadIO&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; s r m) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-45&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-45&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    liftIO &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; lift &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; liftIO&lt;/span&gt;
&lt;span id=&quot;cb16-46&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-46&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-47&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-47&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; m, &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; m) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MonadPlus&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; s r m) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-48&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-48&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    mplus x y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; \v l s &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;cb16-49&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-49&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        x'&lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;(xa, xs, xl, v') &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; runJailT' x v l s&lt;/span&gt;
&lt;span id=&quot;cb16-50&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-50&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;kw&quot;&gt;if&lt;/span&gt; v'&lt;/span&gt;
&lt;span id=&quot;cb16-51&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-51&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;           &lt;span class=&quot;kw&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;return&lt;/span&gt; x'&lt;/span&gt;
&lt;span id=&quot;cb16-52&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-52&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;           &lt;span class=&quot;kw&quot;&gt;else&lt;/span&gt; runJailT' y v l s&lt;/span&gt;
&lt;span id=&quot;cb16-53&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-53&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    mzero &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; \v l s &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;return&lt;/span&gt; (&lt;span class=&quot;fu&quot;&gt;undefined&lt;/span&gt;, s, l, &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb16-54&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-54&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-55&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-55&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; m, &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; m) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Alternative&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; s r m) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-56&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-56&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;op&quot;&gt;&amp;lt;|&amp;gt;&lt;/span&gt;) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; mplus&lt;/span&gt;
&lt;span id=&quot;cb16-57&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-57&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    empty &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; mzero&lt;/span&gt;
&lt;span id=&quot;cb16-58&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-58&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-59&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-59&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;runJailT ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Functor&lt;/span&gt; m)&lt;/span&gt;
&lt;span id=&quot;cb16-60&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-60&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;JailT&lt;/span&gt; s s m a&lt;/span&gt;
&lt;span id=&quot;cb16-61&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-61&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;         &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; s&lt;/span&gt;
&lt;span id=&quot;cb16-62&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-62&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;         &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; (a, s))&lt;/span&gt;
&lt;span id=&quot;cb16-63&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-63&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;runJailT ac &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;fmap&lt;/span&gt; (\(a, s, _, v) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-64&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-64&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                            &lt;span class=&quot;kw&quot;&gt;if&lt;/span&gt; v &lt;span class=&quot;kw&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; (a, s) &lt;span class=&quot;kw&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb16-65&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-65&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                    &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; runJailT' ac &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;id&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-66&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-66&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-67&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-67&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;Jail&lt;/span&gt; s r &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; s r &lt;span class=&quot;dt&quot;&gt;Identity&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-68&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-68&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;runJail ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Jail&lt;/span&gt; s s a&lt;/span&gt;
&lt;span id=&quot;cb16-69&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-69&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; s&lt;/span&gt;
&lt;span id=&quot;cb16-70&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-70&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;Maybe&lt;/span&gt; (a, s)&lt;/span&gt;
&lt;span id=&quot;cb16-71&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-71&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;runJail ac &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; runIdentity &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; runJailT ac&lt;/span&gt;
&lt;span id=&quot;cb16-72&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-72&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-73&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-73&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;jail ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; m)&lt;/span&gt;
&lt;span id=&quot;cb16-74&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-74&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;RLens&lt;/span&gt; r' r&lt;/span&gt;
&lt;span id=&quot;cb16-75&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-75&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;JailT&lt;/span&gt; s r' m a&lt;/span&gt;
&lt;span id=&quot;cb16-76&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-76&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;JailT&lt;/span&gt; s r m a&lt;/span&gt;
&lt;span id=&quot;cb16-77&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-77&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;jail l' m &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; \v l s &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;cb16-78&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-78&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (a, s', _, v') &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; runJailT' m v (l &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; l') s&lt;/span&gt;
&lt;span id=&quot;cb16-79&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-79&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;return&lt;/span&gt; (a, s', l, v')&lt;/span&gt;
&lt;span id=&quot;cb16-80&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-80&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-81&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-81&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;into ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RLens&lt;/span&gt; a (&lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; a)&lt;/span&gt;
&lt;span id=&quot;cb16-82&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-82&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;into &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; lens fromJust (&lt;span class=&quot;fu&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb16-83&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-83&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-84&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-84&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;jailMaybe ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Applicative&lt;/span&gt; m, &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; m)&lt;/span&gt;
&lt;span id=&quot;cb16-85&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-85&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;RLens&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; r') r&lt;/span&gt;
&lt;span id=&quot;cb16-86&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-86&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; a&lt;/span&gt;
&lt;span id=&quot;cb16-87&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-87&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;JailT&lt;/span&gt; s r' m a&lt;/span&gt;
&lt;span id=&quot;cb16-88&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-88&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;JailT&lt;/span&gt; s r m a&lt;/span&gt;
&lt;span id=&quot;cb16-89&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-89&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;jailMaybe l d m &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-90&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-90&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (gets &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; view l) &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;cb16-91&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-91&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; _  &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; jail (l &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; into) m&lt;/span&gt;
&lt;span id=&quot;cb16-92&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-92&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;return&lt;/span&gt; d&lt;/span&gt;
&lt;span id=&quot;cb16-93&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-93&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-94&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-94&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;escape ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Applicative&lt;/span&gt; m, &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; m)&lt;/span&gt;
&lt;span id=&quot;cb16-95&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-95&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;JailT&lt;/span&gt; s s m a&lt;/span&gt;
&lt;span id=&quot;cb16-96&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-96&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;JailT&lt;/span&gt; s r m a&lt;/span&gt;
&lt;span id=&quot;cb16-97&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-97&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;escape m &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; \v l s &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;cb16-98&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-98&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (a, s', _, v') &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; runJailT' m v &lt;span class=&quot;fu&quot;&gt;id&lt;/span&gt; s&lt;/span&gt;
&lt;span id=&quot;cb16-99&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-99&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;return&lt;/span&gt; (a, s', l, v')&lt;/span&gt;
&lt;span id=&quot;cb16-100&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-100&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-101&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-101&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;freedom ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Applicative&lt;/span&gt; m, &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; m) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; s r m s&lt;/span&gt;
&lt;span id=&quot;cb16-102&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-102&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;freedom &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; \v l s &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;return&lt;/span&gt; (s, s, l, v)&lt;/span&gt;
&lt;span id=&quot;cb16-103&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-103&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-104&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-104&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- happens to be unused, because it's kinda insane??&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-105&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-105&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;overwrite ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Applicative&lt;/span&gt; m, &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; m)&lt;/span&gt;
&lt;span id=&quot;cb16-106&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-106&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;RLens&lt;/span&gt; r' r&lt;/span&gt;
&lt;span id=&quot;cb16-107&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-107&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;JailT&lt;/span&gt; r r' m a&lt;/span&gt;
&lt;span id=&quot;cb16-108&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-108&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;JailT&lt;/span&gt; s r m a&lt;/span&gt;
&lt;span id=&quot;cb16-109&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-109&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;overwrite l' m &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; \v l s &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;cb16-110&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-110&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (a, s', _, v') &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; runJailT' m v l' &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; view l s&lt;/span&gt;
&lt;span id=&quot;cb16-111&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-111&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;return&lt;/span&gt; (a, set l s' s, l, v')&lt;/span&gt;
&lt;span id=&quot;cb16-112&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-112&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-113&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-113&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;parole ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Applicative&lt;/span&gt; m, &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; m)&lt;/span&gt;
&lt;span id=&quot;cb16-114&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-114&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;       &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; a&lt;/span&gt;
&lt;span id=&quot;cb16-115&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-115&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;JailT&lt;/span&gt; s r m (&lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; a)&lt;/span&gt;
&lt;span id=&quot;cb16-116&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-116&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;JailT&lt;/span&gt; s r m a&lt;/span&gt;
&lt;span id=&quot;cb16-117&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-117&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;parole d m &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;cb16-118&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-118&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    this &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; get&lt;/span&gt;
&lt;span id=&quot;cb16-119&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-119&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    m &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;cb16-120&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-120&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; a  &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;return&lt;/span&gt; a&lt;/span&gt;
&lt;span id=&quot;cb16-121&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-121&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; put this &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; d&lt;/span&gt;
&lt;span id=&quot;cb16-122&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-122&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-123&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-123&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;inspect ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Applicative&lt;/span&gt; m, &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; m)&lt;/span&gt;
&lt;span id=&quot;cb16-124&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-124&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;RLens&lt;/span&gt; i r&lt;/span&gt;
&lt;span id=&quot;cb16-125&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-125&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;JailT&lt;/span&gt; s r m i&lt;/span&gt;
&lt;span id=&quot;cb16-126&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-126&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;inspect l &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; gets &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; view l&lt;/span&gt;
&lt;span id=&quot;cb16-127&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-127&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-128&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-128&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;inquire ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Applicative&lt;/span&gt; m, &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; m)&lt;/span&gt;
&lt;span id=&quot;cb16-129&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-129&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;RLens&lt;/span&gt; i s&lt;/span&gt;
&lt;span id=&quot;cb16-130&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-130&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;JailT&lt;/span&gt; s r m i&lt;/span&gt;
&lt;span id=&quot;cb16-131&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-131&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;inquire l &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; view l &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; freedom&lt;/span&gt;
&lt;span id=&quot;cb16-132&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-132&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-133&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-133&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;arrest ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Applicative&lt;/span&gt; m, &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; m)&lt;/span&gt;
&lt;span id=&quot;cb16-134&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-134&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;RLens&lt;/span&gt; r' r&lt;/span&gt;
&lt;span id=&quot;cb16-135&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-135&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;       &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; r'&lt;/span&gt;
&lt;span id=&quot;cb16-136&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-136&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;JailT&lt;/span&gt; s r m ()&lt;/span&gt;
&lt;span id=&quot;cb16-137&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-137&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;arrest l v &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;cb16-138&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-138&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    state &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; get&lt;/span&gt;
&lt;span id=&quot;cb16-139&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-139&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    put &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; set l v state&lt;/span&gt;
&lt;span id=&quot;cb16-140&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-140&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-141&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-141&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;arrests ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Applicative&lt;/span&gt; m, &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; m)&lt;/span&gt;
&lt;span id=&quot;cb16-142&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-142&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;RLens&lt;/span&gt; r' r&lt;/span&gt;
&lt;span id=&quot;cb16-143&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-143&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; (r' &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; r')&lt;/span&gt;
&lt;span id=&quot;cb16-144&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-144&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;JailT&lt;/span&gt; s r m ()&lt;/span&gt;
&lt;span id=&quot;cb16-145&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-145&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;arrests l f &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;cb16-146&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-146&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    state &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; get&lt;/span&gt;
&lt;span id=&quot;cb16-147&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb16-147&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    put &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; set l (f &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; view l state) state&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/details&gt;
&lt;p&gt;vs the&lt;/p&gt;
&lt;details&gt;

New Implementation

&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://reasonablypolymorphic.com#cb17-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE DerivingStrategies         #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-2&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE FlexibleInstances          #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-3&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE GeneralizedNewtypeDeriving #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-4&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;{-# LANGUAGE MultiParamTypeClasses      #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-5&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-5&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;cb17-6&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-7&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-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;Control.Applicative&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-8&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-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;Control.Lens&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-9&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-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;Control.Monad.State&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-10&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-10&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.Monad.Reader&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-11&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-11&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.Monad.Trans.Maybe&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-12&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-13&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-14&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-14&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;JailT&lt;/span&gt; s r m a &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-15&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  {&lt;span class=&quot;ot&quot;&gt; unJailT ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ReaderT&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;ALens'&lt;/span&gt; s r) (&lt;span class=&quot;dt&quot;&gt;StateT&lt;/span&gt; s (&lt;span class=&quot;dt&quot;&gt;MaybeT&lt;/span&gt; m)) a&lt;/span&gt;
&lt;span id=&quot;cb17-16&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  }&lt;/span&gt;
&lt;span id=&quot;cb17-17&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-17&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 class=&quot;dt&quot;&gt;Functor&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Applicative&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;MonadIO&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Alternative&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb17-18&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-19&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-19&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;Monad&lt;/span&gt; m &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;MonadState&lt;/span&gt; r (&lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; s r m) &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-20&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  get &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; &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;cb17-21&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    l &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; asks cloneLens&lt;/span&gt;
&lt;span id=&quot;cb17-22&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    gets &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; view l&lt;/span&gt;
&lt;span id=&quot;cb17-23&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  put r &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; &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;cb17-24&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    l &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; asks cloneLens&lt;/span&gt;
&lt;span id=&quot;cb17-25&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    modify &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; set l r&lt;/span&gt;
&lt;span id=&quot;cb17-26&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-26&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-27&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-27&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;runJailT ::&lt;/span&gt; s &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Lens'&lt;/span&gt; s t &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; s t m a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; (a, s))&lt;/span&gt;
&lt;span id=&quot;cb17-28&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-28&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;runJailT s l &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; runMaybeT &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;flip&lt;/span&gt; runStateT s &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;flip&lt;/span&gt; runReaderT l &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; unJailT&lt;/span&gt;
&lt;span id=&quot;cb17-29&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-29&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-30&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-30&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;jail ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Lens'&lt;/span&gt; t u &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; s u m a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; s t m a&lt;/span&gt;
&lt;span id=&quot;cb17-31&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-31&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;jail ltu &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; withReaderT (\lst &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; cloneLens lst &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; ltu) &lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; unJailT&lt;/span&gt;
&lt;span id=&quot;cb17-32&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-32&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-33&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-33&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;escape ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; s s m a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; s t m a&lt;/span&gt;
&lt;span id=&quot;cb17-34&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-34&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;escape (&lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; j) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; withReaderT (&lt;span class=&quot;fu&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;id&lt;/span&gt;) j&lt;/span&gt;
&lt;span id=&quot;cb17-35&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-35&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-36&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-36&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;freedom ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; m &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; s t m s&lt;/span&gt;
&lt;span id=&quot;cb17-37&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-37&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;freedom &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; get&lt;/span&gt;
&lt;span id=&quot;cb17-38&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-38&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-39&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-39&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;attempt ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Alternative&lt;/span&gt; m, &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; m) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; a) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m a&lt;/span&gt;
&lt;span id=&quot;cb17-40&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-40&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;attempt m &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;maybe&lt;/span&gt; empty &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&amp;lt;&amp;lt;&lt;/span&gt; m&lt;/span&gt;
&lt;span id=&quot;cb17-41&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-41&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-42&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-42&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;parole ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; m &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;JailT&lt;/span&gt; s t m (&lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; a) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; s t m a&lt;/span&gt;
&lt;span id=&quot;cb17-43&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-43&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;parole a0 j &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-44&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-44&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  asum&lt;/span&gt;
&lt;span id=&quot;cb17-45&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-45&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    [ attempt j&lt;/span&gt;
&lt;span id=&quot;cb17-46&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-46&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    , &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; a0&lt;/span&gt;
&lt;span id=&quot;cb17-47&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-47&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ]&lt;/span&gt;
&lt;span id=&quot;cb17-48&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-48&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-49&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-49&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;arrest ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Monad&lt;/span&gt; m &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Lens'&lt;/span&gt; t u &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; u &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;JailT&lt;/span&gt; s t m ()&lt;/span&gt;
&lt;span id=&quot;cb17-50&quot;&gt;&lt;a href=&quot;https://reasonablypolymorphic.com#cb17-50&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;arrest l u &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; modify &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; set l u&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/details&gt;
&lt;p&gt;Maybe this was interesting to you. It certainly was fun for me, because I like tearing apart bad code, and I don’t get to see much of it now that I have very talented colleagues. Thankfully I have a huge amount of crap code from my past, including an even more egregious monad that we’ll tackle next time around.&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;Unwrap the definitions of &lt;code&gt;StateT s Maybe a&lt;/code&gt; and &lt;code&gt;MaybeT (State s) a&lt;/code&gt; to see why.&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, 21 Aug 2026 23:50:00 +0000</pubDate>
</item>
<item>
	<title>Mark Jason Dominus: The road to epsilon-zero: Productive programs and well-founded orders</title>
	<guid isPermaLink="false">tag:,2026:/math/ordinals/05-shortlex</guid>
	<link>https://blog.plover.com/math/ordinals/05-shortlex.html</link>
	<description>&lt;p&gt;Previously:&lt;/p&gt;

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

&lt;p&gt;&lt;a href=&quot;https://blog.plover.com/math/ordinals/04-coordinates.html&quot;&gt;Previously&lt;/a&gt; we saw how to interpret the difficult-seeming ordinal
&lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%cf%89%5e%cf%89%24&quot; /&gt; as a particular ordering of the set of finite sequences of
numbers, revealing what seemed like a scary monster as gentle and
straightforward.&lt;/p&gt;

&lt;p&gt;Now we're going to take a sidetrack into one of my favorite topics,
computation with infinite lists.  I wrote about this for &lt;a href=&quot;https://perl.plover.com/Stream/stream.html&quot;&gt;&lt;em&gt;The
Perl Journal&lt;/em&gt; in 1997&lt;/a&gt; and then it turned into &lt;a href=&quot;https://hop.perl.plover.com/book/pdf/06InfiniteStreams.pdf&quot;&gt;chapter 6 of
&lt;em&gt;Higher-Order Perl&lt;/em&gt;&lt;/a&gt; and here we are again. Gosh! it just keeps
coming back.  Like John the Baptist.  &lt;/p&gt;

&lt;h2&gt;Infinite lists&lt;/h2&gt;

&lt;p&gt;Suppose you have an infinite set of strings — we'll call this set
&lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24S%24&quot; /&gt; for the rest of the article — and you want a program to
print them all out.  Of course the program can't exactly print them
&lt;em&gt;all&lt;/em&gt; out, because it will only run for a finite amount of time.  But
there are more and less useful ways for the program to try.&lt;/p&gt;

&lt;p&gt;For each string that the program is supposed to print,
we should at least be able to guarantee that the the program &lt;em&gt;will&lt;/em&gt;
print it, eventually, if we just wait long enough.  If this is true then we'll say
that the program is “productive”.&lt;/p&gt;

&lt;p&gt;Here's a productive program to print the base-10 numerals for all the
positive integers:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    # Python

    i = 1
    while True:
      print(i)
      i += 1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What would a non-productive program look like?  Here's an example of a
non-productive program to print the base-10 numerals for all the
positive integers:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    # Python, silly

    i = 1
    while True:   # print all the odd numbers
      print(i)
      i += 2

    i = 2
    while True:   # then print all the even numbers
      print(i)
      i += 2
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This one tries to print all the odd numbers first, and then all the
even numbers.  Obviously that doesn't work because it never finishes
with the odd numbers.  If you were to sit around waiting for the
number &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%2414%24&quot; /&gt;, you'd wait forever.  Whereas with the first program,
whatever number you are waiting for, even if it is very very big, it
will come out eventually.&lt;/p&gt;

&lt;p&gt;That's what I meant when I said there are more and less useful ways
for a program to try to print an infinite set.  The first one never
finishes, true, but the way in which it never finishes is much more
useful than the way in which the second one never finishes.&lt;/p&gt;

&lt;p&gt;Okay, that was a silly example.  But there are less silly examples.&lt;/p&gt;

&lt;h2&gt;Printing strings in sorted order&lt;/h2&gt;

&lt;p&gt;A productive program is always &lt;em&gt;semidecidable&lt;/em&gt;: if a user wants to
know if some particular string &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24s%24&quot; /&gt; is in &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24S%24&quot; /&gt;, and they wait long
enough, &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24s%24&quot; /&gt; will come out and they have the answer. But if &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24s%24&quot; /&gt;
isn't in &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24S%24&quot; /&gt;, they never find that out!  They just wait and wait,
wondering if it will come out, and never getting a definitive answer.&lt;/p&gt;

&lt;p&gt;If we can get a productive program to produce its strings in sorted
order, we can make a better guarantee. The program will be
&lt;em&gt;decidable&lt;/em&gt;: the user will eventually get an answer, one way
or the other.  If &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24s%5cin%20S%24&quot; /&gt; the productive program will eventually
produce &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24s%24&quot; /&gt;, and the user can stop watching.  But if &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24s%5cnotin%20S%24&quot; /&gt;,
the program must eventually produce a string that comes after &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24s%24&quot; /&gt; in
sorted order, and they can quit then.  And the program must
eventually produce &lt;em&gt;some&lt;/em&gt; string that comes after &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24s%24&quot; /&gt;, because,
being productive, it eventually produces every string in &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24S%24&quot; /&gt;.&lt;/p&gt;

&lt;p&gt;(What if there is no string in &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24S%24&quot; /&gt; that comes after &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24s%24&quot; /&gt; in sorted
order?  Then the productive program will first produce all the strings
that precede &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24s%24&quot; /&gt;, then it will produce &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24s%24&quot; /&gt;, and 
then it will halt.  When it does that user has their
answer, whatever it is.)&lt;/p&gt;

&lt;h3&gt;Not every program is productive&lt;/h3&gt;

&lt;p&gt;The non-productive program I showed above is silly, but productivity
isn't something you can always guarantee, if you want the data in
sorted order.  Some orders work, and some don't.&lt;/p&gt;

&lt;p&gt;The conventional order for strings, implemented by Python's
&lt;code&gt;&amp;lt;&lt;/code&gt; operator or C's &lt;code&gt;strcmp&lt;/code&gt;, is called &lt;em&gt;lexicographic&lt;/em&gt;, which means
“dictionary-style”.  There are some sets of strings for which
no productive program can print all the strings in lexicographic order.&lt;/p&gt;

&lt;p&gt;For example, consider the set of all strings that are made up of
either all &lt;code&gt;a&lt;/code&gt;s or all &lt;code&gt;b&lt;/code&gt;s:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    a
    b
    aa
    bb
    aaa
    bbb
    aaaa
    bbbb
    …
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Notice that this list is &lt;em&gt;not&lt;/em&gt; in lexicographic order, because in
lexicographic order, the string &lt;code&gt;aa&lt;/code&gt; should come out before &lt;code&gt;b&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There is no productive program to print this set in lexicographic
order.  Why not? Because in lexicographic order the list begins like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    a
    aa
    aaa
    aaaa
    aaaaa
    …
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and the program never gets around to printing any of the strings with
&lt;code&gt;b&lt;/code&gt;s.  This is analogous to how the non-productive example earlier waited to
print even numbers until after it was finished with the odd numbers.
To print these strings in lexicographic order would meansto print the
strings beginning with &lt;code&gt;b&lt;/code&gt; after printing the strings
beginning with &lt;code&gt;a&lt;/code&gt;. But the program never does finish with the strings
beginning with &lt;code&gt;a&lt;/code&gt;.  The program is supposed to produce &lt;code&gt;bbb&lt;/code&gt;, but it
never does, no matter how the user waits.  And it's supposed to reach
a point where the user can be sure that &lt;code&gt;banana&lt;/code&gt; will &lt;em&gt;not&lt;/em&gt; come out,
but it never does that either, it keeps printing &lt;code&gt;a&lt;/code&gt;s and never prints
a string like &lt;code&gt;bbb&lt;/code&gt; that comes after &lt;code&gt;banana&lt;/code&gt; in lexicographic order.&lt;/p&gt;

&lt;p&gt;The problems with lexicographic order are even worse than this example shows.
Consider this set of strings:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    b
    ab
    aab
    aaab
    aaaab
    aaaaab
    …
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Notice again: not lexicographic order, because &lt;code&gt;b&lt;/code&gt; should come out last, not first.
But what should come first? A program to print these strings in lexicographic order
can't even get started, because in lexicographic order, this list of strings doesn't have
a &lt;em&gt;first&lt;/em&gt; element!  The program can't print out &lt;code&gt;b&lt;/code&gt; first because all
the &lt;code&gt;a&lt;/code&gt; strings were supposed to come out before that.  And it can't
print out &lt;code&gt;ab&lt;/code&gt; first because &lt;code&gt;aab&lt;/code&gt; was supposed to come out before
that.  And it can't print out &lt;code&gt;aaaaaaaaab&lt;/code&gt; because &lt;code&gt;aaaaaaaaaaaaaaab&lt;/code&gt;
was supposed to come out before that.  Whatever string the program
tries to print out first, it will have made a mistake!&lt;/p&gt;

&lt;p&gt;If you're trying to print out an ordered, infinite list of strings,
lexicographic order just won't do.&lt;/p&gt;

&lt;h3&gt;Lexicographic order isn't well-founded&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://blog.plover.com/math/ordinals/02-wellfoundedness.html&quot;&gt;In an earlier article in this series&lt;/a&gt; we talked about
“well-founded” orders.  In a well-founded order, every set of items
has a &lt;em&gt;first&lt;/em&gt; item, if it has any at all.  Writing a productive
program for a well-founded order is easy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repeat forever: &lt;br /&gt;
&lt;strong&gt;Question&lt;/strong&gt;: Are there any items left to print? &lt;br /&gt;
&lt;strong&gt;No&lt;/strong&gt;: Halt &lt;br /&gt;
&lt;strong&gt;Yes&lt;/strong&gt;: 
&lt;ul&gt;
&lt;li&gt;Let &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24P%24&quot; /&gt; be the set of unprinted items  &lt;/li&gt;
&lt;li&gt;Let &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24s%24&quot; /&gt; be the &lt;em&gt;first&lt;/em&gt; item in &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24P%24&quot; /&gt; &lt;br /&gt;
(There must be one, because we're printing the items in a
well-founded order)  &lt;/li&gt;
&lt;li&gt;Print &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24s%24&quot; /&gt;  &lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As we saw, the conventional lexicographic order is &lt;em&gt;not&lt;/em&gt; well-founded
for strings.  Some sets simply don't have a lexicographically first
element.&lt;/p&gt;

&lt;p&gt;So in circumstances where we might be handling infinite data streams,
we often prefer a different string ordering, almost as simple and
considerably better-behaved.&lt;/p&gt;

&lt;h2&gt;Shortlex order&lt;/h2&gt;

&lt;p&gt;You already know this one, although perhaps not by that name.  It's
nothing more than the order we use for regular numerals like &lt;code&gt;723&lt;/code&gt;.
It's &lt;em&gt;not&lt;/em&gt; lexicographic, because as you've probably noticed, in
lexicographic order, &lt;code&gt;10&lt;/code&gt; comes before &lt;code&gt;2&lt;/code&gt;.  Here's the track listing
of my copy of &lt;a href=&quot;https://en.wikipedia.org/wiki/Quadrophenia&quot;&gt;&lt;em&gt;Quadrophenia&lt;/em&gt;&lt;/a&gt;, as listed by the Unix &lt;code&gt;ls&lt;/code&gt; program:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    1 I am the sea.mp3
    10 I've had enough.mp3
    11 515.mp3
    12 Sea And Sand.mp3
    13 Drowned.mp3
    14 Bell Boy.mp3
    15 Doctor Jimmy.mp3
    16 The Rock.mp3
    17 Love Reign O'er Me.mp3
    2 The real me.mp3
    3 Quadrophenia.mp3
    4 Cut my hair.mp3
    5 The punk and the godfather.mp3
    6 I'm one.mp3
    7 The dirty jobs.mp3
    8 Helpless dancer.mp3
    9 Is it in my head.mp3
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Hey, wait, why did &lt;code&gt;ls&lt;/code&gt; put track 17 ahead of track 2?  Because &lt;code&gt;ls&lt;/code&gt;
lists files in lexicographic order, and in lexicographic order, &lt;code&gt;17&lt;/code&gt; comes
ahead of &lt;code&gt;2&lt;/code&gt; for the same reason that &lt;code&gt;agony&lt;/code&gt; and the other &lt;code&gt;ag-&lt;/code&gt;
words come before &lt;code&gt;bony&lt;/code&gt; and the other &lt;code&gt;b-&lt;/code&gt; words in the dictionary:
&lt;code&gt;1&lt;/code&gt; comes before &lt;code&gt;2&lt;/code&gt; just as &lt;code&gt;a&lt;/code&gt; comes before &lt;code&gt;b&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you name your files after numbers, then when the computer lists
them in lexicographic order, they won't be in numeric order.  Numeric order isn't
lexicographic.  But numerals, in shortlex order &lt;em&gt;are&lt;/em&gt; in numeric order, and of
course it's trivial to print all possible numerals in numeric order.&lt;/p&gt;

&lt;p&gt;The rule to compare two strings in shortlex order is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If the strings are different lengths, the &lt;strong&gt;shorter one&lt;/strong&gt; comes first.&lt;/li&gt;
&lt;li&gt;If they're the &lt;strong&gt;same length&lt;/strong&gt;, compare them lexicographically.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Compare the shortness first, and use lexicographic comparison as a
tiebreaker. Hence “short” + “lex”.&lt;/p&gt;

&lt;p&gt;Consider what this means for numerals.  Here's a list of binary numerals
from &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%240%24&quot; /&gt; to &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%2415%24&quot; /&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;        0
        1
        10
        100
        1000
        1001
        101
        1010
        1011
        11
        110
        1100
        1101
        111
        1110
        1111
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It looks strange because it's in lexicographic order — all the numerals that begin with &lt;code&gt;10&lt;/code&gt;
appear before all those beginning with &lt;code&gt;11&lt;/code&gt;, which means that &lt;code&gt;1000&lt;/code&gt;
comes before &lt;code&gt;11&lt;/code&gt;, even though (checking my notes) &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%243%20%5clt%208%24&quot; /&gt;.&lt;/p&gt;

&lt;p&gt;If we want to print &lt;em&gt;all&lt;/em&gt; binary numerals
in lexicographic order, we're out of luck.  The list starts like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;        0
        1
        10
        100
        1000
        …
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and we never get to printing &lt;em&gt;any&lt;/em&gt; of the numerals starting with &lt;code&gt;11&lt;/code&gt;,
including &lt;code&gt;11&lt;/code&gt; itself.&lt;/p&gt;

&lt;p&gt;In shortlex order, it's what we expect.  We get the numeral for every
number, and in numeric order:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    0
    1
    10
    11
    100
    101
    110
    111
    1000
    1001
    1010
    1011
    1100
    1101
    1110
    1111
    …
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Unlike lexicographic order, the shortlex order is well-founded.  Remember that “well-founded” means
that &lt;em&gt;every&lt;/em&gt; set of strings has a first element.  But in lexicographic order, this set
of binary numerals has no first element:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    11
    101
    1001
    10001
    100001
    …
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In shortlex order there's no problem.  There can't be, because shortlex order is numeric order, and if numeric order
wasn't well-founded there wouldn't be a productive program to print
all the numerals in order, which of course there is.&lt;/p&gt;

&lt;p&gt;The infinite lists that we couldn't put into lexicographic order
before give us no trouble in shortlex order.  In fact, I listed both
in shortlex order already:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    a             b
    b             ab
    aa            aab
    bb            aaab
    aaa           aaaab
    bbb           aaaaab
    …             …
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For strings, shortlex order is well-founded, which means that every
set of strings contains a first element.  Here's why: Consider some
set &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24S%24&quot; /&gt; and some string &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24s%5cin%20S%24&quot; /&gt;.  The string &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24s%24&quot; /&gt; has a length
&lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%5cell%24&quot; /&gt;. Consider the set &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24E%24&quot; /&gt; of strings that come before &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24s%24&quot; /&gt;.
The set &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24E%24&quot; /&gt; must be finite because every  string that comes before
&lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24s%24&quot; /&gt; in shortlex order has length less than or equal to &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%5cell%24&quot; /&gt;, and there are
only a finite number of such strings.&lt;/p&gt;

&lt;p&gt;If &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24E%24&quot; /&gt; is empty, then &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24s%24&quot; /&gt; itself is the first string in &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24S%24&quot; /&gt;.  If
&lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24E%24&quot; /&gt; is not empty, then, being finite, it must have a first element.
(Just sort &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24E%24&quot; /&gt;.)  This first element is the first string in &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24S%24&quot; /&gt;.
Done.&lt;/p&gt;

&lt;p&gt;Wait, why are there are only a finite number of strings with length
less than or equal to &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%5cell%24&quot; /&gt;?  Well, there are only a finite number
of strings of length &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%240%24&quot; /&gt;.  (There's only one.)  And there are only a
finite number of strings of length &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%241%24&quot; /&gt;: If the character set
contains &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24n%24&quot; /&gt; symbols, there are only &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24n%24&quot; /&gt; with length &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%241%24&quot; /&gt;.
Similarly there are only &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24n%5e2%24&quot; /&gt; strings of length &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%242%24&quot; /&gt;, and so on.
Since there are only a finite number with each length up to &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%5cell%24&quot; /&gt;,
we just add up this finite list of finite numbers and the sum is
finite.  And since every string in &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24E%24&quot; /&gt; has length no more than
&lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%5cell%24&quot; /&gt;, the number of strings in &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24E%24&quot; /&gt; is at most this finite
number.&lt;/p&gt;

&lt;p&gt;Coming next:
&lt;a href=&quot;https://blog.plover.com/math/ordinals/06-nim-shortlex.html&quot;&gt;Shortlex order also orders sequences of numbers&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I made Claude sit in a chair in the corner and watch
silently while I wrote this.&lt;/p&gt;</description>
	<pubDate>Thu, 13 Aug 2026 23:30:00 +0000</pubDate>
	<author>mjd@plover.com (Mark Dominus)</author>
</item>
<item>
	<title>Magnus Therning: Emacs salmagundi, 2026-08-13</title>
	<guid isPermaLink="true">https://magnus.therning.org/2026-08-13-emacs-salmagundi,-2026-08-13.html</guid>
	<link>https://magnus.therning.org/2026-08-13-emacs-salmagundi,-2026-08-13.html</link>
	<description>&lt;p&gt;
Here's a few minor tweaks I've made to my Emacs setup recently.
&lt;/p&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgcff92e2&quot;&gt;
&lt;h2 id=&quot;orgcff92e2&quot;&gt;Limiting enabled tree-sitter modes&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgcff92e2&quot;&gt;
&lt;p&gt;
After reading Rahul's post &lt;a href=&quot;https://www.rahuljuliato.com/posts/emacs-31-around-the-corner&quot;&gt;Emacs 31 Is Around the Corner: The Changes I'm
Already Daily Driving&lt;/a&gt; I simplified my setup and turned on all the tree-sitter
modes
&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;treesit-enabled-modes 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;
I regretted that as soon as I opened a YAML file though. It turns out the
&lt;code&gt;yaml-ts-mode&lt;/code&gt; is rather unusable.&lt;sup&gt;&lt;a class=&quot;footref&quot; href=&quot;https://magnus.therning.org/feed.xml#fn.1&quot; id=&quot;fnr.1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; I switched back to &lt;a href=&quot;https://github.com/yoshiki/yaml-mode&quot;&gt;&lt;code&gt;yaml-mode&lt;/code&gt;&lt;/a&gt; and
adjusted the value of &lt;code&gt;treesit-enabled-modes&lt;/code&gt; to include what I have use for
(&lt;a href=&quot;https://gitlab.com/magus/mes/-/commit/f31d0551ff7cd16ce5c498d1a24aab042f736ade&quot;&gt;the change&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;treesit-enabled-modes '&lt;span class=&quot;org-rainbow-delimiters-depth-2&quot;&gt;(&lt;/span&gt;bash-ts-mode
                         c++-ts-mode
                         c-or-c++-ts-mode
                         c-ts-mode
                         dockerfile-ts-mode
                         go-mod-ts-mode
                         go-ts-mode
                         go-work-ts-mode
                         json-ts-mode
                         python-ts-mode
                         rust-ts-mode
                         typescript-ts-mode&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 customization of &lt;code&gt;treesit-enabled-modes&lt;/code&gt; contains a list of all the
supported modes.
&lt;/p&gt;

&lt;p&gt;
I hope someone will take pity on &lt;code&gt;yaml-ts-mode&lt;/code&gt; and make it usable soon.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-org0283871&quot;&gt;
&lt;h2 id=&quot;org0283871&quot;&gt;Tree-sitter grammar for Cabal files&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-org0283871&quot;&gt;
&lt;p&gt;
When I began tinkering with my own &lt;a href=&quot;https://gitlab.com/magus/haskell-ng-mode&quot;&gt;treesitter-based mode for Haskell&lt;/a&gt; I failed to
find a tree-sitter grammar for &lt;a href=&quot;https://cabal.readthedocs.io/en/stable/index.html&quot;&gt;Cabal files&lt;/a&gt; so I wrote a rather rough one myself.
My hope was that it could serve as a base, or motivation, for someone else to
write a proper one. It took more than 2 years, but now &lt;a href=&quot;https://crtschin.com/posts/how-to-not-write-parsers&quot;&gt;it's finally happened&lt;/a&gt;!
&lt;/p&gt;

&lt;p&gt;
I've switched my mode to use Curtis's grammar and I'll be archiving mine. (&lt;a href=&quot;https://gitlab.com/magus/haskell-ng-mode/-/commit/557b1db98128f14400603e77c1cf18486b4c9bb2&quot;&gt;The
change&lt;/a&gt;.)
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-org7fa14ad&quot;&gt;
&lt;h2 id=&quot;org7fa14ad&quot;&gt;Hello editable &lt;code&gt;xref&lt;/code&gt;, good bye &lt;code&gt;wgrep&lt;/code&gt;&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-org7fa14ad&quot;&gt;
&lt;p&gt;
&lt;a href=&quot;https://www.rahuljuliato.com/posts/emacs-31-around-the-corner&quot;&gt;Rahul's post&lt;/a&gt; also mentions that editable &lt;code&gt;xref&lt;/code&gt; buffers. I had the same itch to
have editable &lt;code&gt;xref&lt;/code&gt; buffers, and I'd added a function to turn them into &lt;code&gt;grep&lt;/code&gt;
buffers to be able to edit them. I've now &lt;a href=&quot;https://gitlab.com/magus/mes/-/commit/5c4dcd17c85f39fa768d302eeace635ff4c1da86&quot;&gt;switched to using the built-in
support&lt;/a&gt;, and removed the function.
&lt;/p&gt;

&lt;p&gt;
At the same time I also decided to remove &lt;code&gt;wgrep&lt;/code&gt; and instead &lt;a href=&quot;https://gitlab.com/magus/mes/-/commit/6fb854b238b7a27f489da9d88a185ba4cd158052&quot;&gt;use the builtin
function for editing &lt;code&gt;grep&lt;/code&gt; buffers&lt;/a&gt;.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;footnotes&quot;&gt;
&lt;h2 class=&quot;footnotes&quot;&gt;Footnotes: &lt;/h2&gt;
&lt;div id=&quot;text-footnotes&quot;&gt;

&lt;div class=&quot;footdef&quot;&gt;&lt;sup&gt;&lt;a class=&quot;footnum&quot; href=&quot;https://magnus.therning.org/feed.xml#fnr.1&quot; id=&quot;fn.1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; &lt;div class=&quot;footpara&quot;&gt;&lt;p class=&quot;footpara&quot;&gt;
A mode for an indentation-sensitive language really ought to at least handle
indentation!
&lt;/p&gt;&lt;/div&gt;&lt;/div&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;&lt;span class=&quot;tag-label&quot;&gt;Tags&lt;/span&gt;&lt;/a&gt;&lt;span class=&quot;tag-separator&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;taglist__tags&quot;&gt;&lt;a class=&quot;tag&quot; href=&quot;https://magnus.therning.org/tag-emacs.html&quot;&gt;emacs&lt;/a&gt; &lt;a class=&quot;tag&quot; href=&quot;https://magnus.therning.org/tag-haskell.html&quot;&gt;haskell&lt;/a&gt; &lt;/span&gt;&lt;/div&gt;</description>
	<pubDate>Thu, 13 Aug 2026 19:44:00 +0000</pubDate>
</item>
<item>
	<title>Mark Jason Dominus: There are two kinds of theorems</title>
	<guid isPermaLink="false">tag:,2026:/math/two-kinds-of-theorems</guid>
	<link>https://blog.plover.com/math/two-kinds-of-theorems.html</link>
	<description>&lt;p&gt;In mathematical study there are two kinds of theorems, which serve
very different purposes.  Math instruction follows the same pattern.
Students are often very puzzled by this, and rightly so, because it's
never explained, or at least I've never seen it explained.  There is
this crucial, critical piece of mathematical methodology which is
never made explicit, students just have to figure it out on their own,
and many of them never do.&lt;/p&gt;

&lt;p&gt;When we do mathematics, we construct a simplified model of some
phenomenon. For example, Euclidean geometry is a simplified model of
how shapes and lines actually work.&lt;/p&gt;

&lt;p&gt;In formal geometry, things are simple: lines have no thickness, and
three or more lines might all intersect at the exact same point. There
are perfect circles, where every point is the exact same distance from
the center, and there are perfect rectangles with perfectly straight
sides and perfectly equal angles.&lt;/p&gt;

&lt;p&gt;Real shapes aren't like this.  Nobody can draw an infinitely thin
line.  Nobody has ever seen a geometrically perfect circle or
rectangle.  Three lines, however carefully drawn, will always
intersect in three different places.  That's okay!  The point of
geometry is to construct a simplified model that is easier to deal
with.&lt;/p&gt;

&lt;p&gt;When we're setting up a mathematical model, we start by describing its
basic objects, like points and lines, and with axioms and postulates,
what properties we intend the objects to have.  For example, Euclid has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A line is breadthless length.&lt;/li&gt;
&lt;li&gt;A circle is a plane figure contained by one (curved) line with a
point inside, the center, so that the segments from the center to the
boundary of the circle are always of equal length&lt;/li&gt;
&lt;li&gt;All right angles are equal.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Having done that, we state and prove the theorems of the first kind.
We're not studying the actual phenomenon yet.  We're not yet trying to
learn anything new about shapes and circles.  Instead, we're
investigating &lt;em&gt;the model itself&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Is the model accurate?  Does it seem to lead to wrong conclusions?  What
happens if we try to prove things that we know are are false?  The
proofs should fail!  If they don't, something is wrong with the
model, and we need to fix it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Is the model powerful enough to prove at least simple things about
the actual phenomenon?  If it can't encompass the simple aspects of
the phenomenon, we haven't much hope of using it to understand more
complex aspects.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So for example Euclid starts by proving extremely simple theorems.
For example, propositions 4 and 5:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Proposition 4&lt;/strong&gt;: If in triangles &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24ABC%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=%24A%27B%27C%27%24&quot; /&gt; we have
&lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24AT%3dA%27B%27%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=%24AC%3dA%27C%27%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%5cangle%20A%20%3d%20%5cangle%20A%27%24&quot; /&gt;, then the two
triangles are congruent.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img class=&quot;center&quot; src=&quot;https://pic.blog.plover.com/math/two-kinds-of-theorems/euclid-4.svg&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Proposition 5&lt;/strong&gt;: If two straight lines cut one another, then they
make the vertical angles equal to one another.&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;center&quot; src=&quot;https://pic.blog.plover.com/math/two-kinds-of-theorems/euclid-5.svg&quot; /&gt;&lt;/p&gt;

&lt;p&gt;(That is, &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%5cangle%20CEB%20%3d%20%5cangle%20AED%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%5cangle%20CEA%20%3d%20%5cangle%20BED%24&quot; /&gt;.)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Obviously, yes, anyone can see that!  We didn't need to develop a
whole mathematical theory in order to discover that vertical angles
were equal.  Everyone already knew that, long before Euclid.  The
point of proving this theorem, the real discovery, is: &lt;em&gt;our simple
model is strong enough to demonstrate&lt;/em&gt; that vertical angles are
equal. The theory didn't explicitly include anything about vertical
angles, but the vertical angle theorem was latent in the model
anyway.&lt;/p&gt;

&lt;p&gt;Consider the opposite situation, where we &lt;em&gt;couldn't&lt;/em&gt; prove that
vertical angles were equal.  Or worse, what if the model allowed us to
construct a pair of unequal vertical angles?  Would this tell us
something about vertical angles?  Obviously not.  Vertical angles are
equal, regardless of what the theory does or doesn't prove.  It would,
though, tell us something about the theory, namely that it wasn't fit
for purpose, and we'd better try a different model.&lt;/p&gt;

&lt;p&gt;This is a common pattern in all mathematics education and indeed in
all mathematics, but I've rarely seen it called out as such, not even
with a passing remark like “here's why we're doing this”. In nearly
every undergraduate class I've ever been in, someone was puzzled about
why we were doing this.  Why is Euclid proving all these theorems that
are obvious?&lt;/p&gt;

&lt;p&gt;In Euclid the mode goes back and forth: Euclid will do some
model-verifying theorems, then move on to interesting-result theorems,
then back for a while to introduce something new to the model, then
forward again to prove interesting theorems about the thing he
introduced.  The first transition happens around proposition 32 or 36
or so.  Up until that point there were a lot of proposition like this:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Proposition 20&lt;/strong&gt; In any triangle the sum of any two sides is greater than the
  remaining one. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;and this:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Proposition 25&lt;/strong&gt; If two triangles have two sides equal to two
  sides respectively, but have the base greater than the base, then
  they also have the one of the angles contained by the equal straight
  lines greater than the other.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But then very soon after, the theorems start to have a different flavor:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Proposition 36&lt;/strong&gt;: Parallelograms which are on equal bases and in
  the same parallels equal one another.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is:&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;center&quot; src=&quot;https://pic.blog.plover.com/math/two-kinds-of-theorems/euclid-36.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This is actually an interesting fact about parallelograms, and not
intuitively obvious.  Even though the two parallelograms are not at
all the same shape, they have equal areas, since they lie between the
same parallels and &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24AB%3dCD%24&quot; /&gt;.
(&lt;a href=&quot;https://www.desmos.com/geometry/bzsigqhgos&quot;&gt;Interactive version&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;The same issue comes up in many different contexts.  We develop the
theory of the Peano numbers, define addition, and prove that addition
is commutative, Was that because we didn't know how to do addition?
No. We already knew that addition was commutative.  The point of the
theorem is to show that &lt;em&gt;Peano arithmetic knows that addition is
commutative&lt;/em&gt;.  But I have more than once seen instructors demonstrate
the proof, via a double induction, and then finish with a remark like
“therefore, addition is commutative!”  The students, to their credit,
were suspicious of this.  They knew something wasn't quite right, even
if they weren't sure what.  The right announcement would have been
something like “therefore, the Peano axioms aren't complete rubbish!”&lt;/p&gt;

&lt;p&gt;Or: We explore Dedekind cuts, we define a model for the real numbers
as cuts of rationals, and a construction that we claim characterizes
addition.  And then we prove a batch of theorems that are intended to
show things we already know about addition, not because we want to
know whether addition is commutative (news flash: it is) but to show
that it's plausible that our construction really &lt;em&gt;does&lt;/em&gt; characterize
addition.  One of these, that the addition operation we defined on
cuts, which looks nothing like the addition we defined on rational
numbers, actually agrees with it when the cuts themselves correspond
to rationals.  Another, that if &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24a%20%26lt%3b%20b%24&quot; /&gt; then &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24a%2bc%20%26lt%3b%20b%2bc%24&quot; /&gt;.&lt;/p&gt;

&lt;p&gt;Taking a look at Rudin &lt;em&gt;Principles of Mathematical Analysis&lt;/em&gt;, I see
that the first fifteen or so pages are like this, theorems like
&lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%5clvert%20z%5crvert%20%3d%20%5clvert%20%5cbar%20z%20%5crvert%24&quot; /&gt;, which is a basic property
of the fundamental notions &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%5clvert%20z%5crvert%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%5cbar%20z%24&quot; /&gt;.  And
then the mode starts to shift, first a little bit, with&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Let &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24z%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=%24w%24&quot; /&gt; be complex numbers.  Then &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%5clvert%20z%2bw%5crvert%20%e2%89%a4%0a%3e%20%5clvert%20z%5crvert%20%2b%20%5clvert%20w%5crvert%20%24&quot; /&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Okay, that's a triangle inequality again…  and suddenly, seemingly out
of nowhere, something not at all obvious: Theorem 1.35, the
Cauchy-Schwartz inequality for &lt;img src=&quot;https://chart.apis.google.com/chart?chf=bg,s,00000000&amp;amp;cht=tx&amp;amp;chl=%24%5c%5cBbb%20C%5e1%24&quot; /&gt;:&lt;/p&gt;

&lt;p&gt;$$
\left\lvert\sum_{j=1}^n  a_j\bar b_j\right\rvert ^2
 ≤ 
 \sum_{j=1}^n\lvert a_j\rvert^2
 \sum_{j=1}^n\lvert b_j\rvert^2 
$$&lt;/p&gt;

&lt;p&gt;A completely different kind of theorem, not a &lt;em&gt;basic&lt;/em&gt; property of
anything.&lt;/p&gt;

&lt;p&gt;Remember the whole point of the process: We wanted to model some
object of study, we built a model, we proved a lot of theorems to lend
plausibility to our model, to verify that the model wasn't broken, to
confirm that the model captures the properties of interest.  And then
came time to use the model, and we started to prove theorems
that told us new things about the original object of study.&lt;/p&gt;

&lt;p&gt;Does Rudin announce this shift?  Of course not, Rudin never announces
anything.  (Usually he mutters, and sometimes if you are especially
unlucky he fixes you with a glare that dares you to question the
remark he throws away in an undertone.)  But Rudin is Rudin, and
nobody else seems to announce this shift either.  Almost always, it's
passed over, usually without remark, even in gentler textbooks that
give more attention to pedagogical matters.  Sometimes the shift is
sudden, sometimes gradual, but it's almost never pointed out.&lt;/p&gt;

&lt;p&gt;In advanced study, that's okay, because advanced students should be
expected to recognize the pattern.  But why do we expect high
schoolers and undergraduates to understand this without explanation?&lt;/p&gt;

&lt;p&gt;In summary:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;There are two kinds of theorems.&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;The purpose of the first kind is to validate the model we've built, to check it
for power and correctness.&lt;/li&gt;
&lt;li&gt;But the second kind is the kind we're really after, to apply the model
to the problem we want to study.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;This pattern, of building a model, validating it, and then using
it, is a fundamental and universal methodology in all mathematical
study. &lt;/li&gt;
&lt;li&gt;Secondary and tertiary mathematical education should explain this
methodology, but rarely acknowledges it at all.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I asked Claude to do the diagram with the triangles,
but I didn't like the result and changed it all around in Inkscape.
Then I gave it the changed around version and asked it to do the
diagram with vertical angles in the same style, but 
I didn't like the result and changed it all around in Inkscape.
&lt;/p&gt;

&lt;p&gt;
The diagram with the parallelograms is a screencap from
&lt;a href=&quot;https://desmos.com&quot;&gt;Desmos&lt;/a&gt;. I couldn't figure out the Desmos geometry
tool, so I had Claude walk me through how to make the diagram,
then tinkered with the result.
&lt;/p&gt;</description>
	<pubDate>Tue, 11 Aug 2026 21:22:00 +0000</pubDate>
	<author>mjd@plover.com (Mark Dominus)</author>
</item>
<item>
	<title>Abhinav Sarkar: Fast Haskell Scripts on GitHub Actions</title>
	<guid isPermaLink="false">https://abhinavsarkar.net/posts/fast-haskell-scripts-on-github-actions/</guid>
	<link>https://abhinavsarkar.net/posts/fast-haskell-scripts-on-github-actions/?mtm_campaign=feed</link>
	<description>&lt;p&gt;Magix is a neat tool that lets us run &lt;a href=&quot;https://haskell.org&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Haskell&lt;/a&gt; programs as scripts&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;. We put a shebang on top mentioning Magix, list the Haskell packages we need, and &lt;code&gt;./script.hs&lt;/code&gt; just works. This post is about running such a script fast(er) on &lt;a href=&quot;https://github.com/features/actions&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;GitHub Actions&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This post was originally published on &lt;a href=&quot;https://abhinavsarkar.net/posts/fast-haskell-scripts-on-github-actions/?mtm_campaign=feed&quot;&gt;abhinavsarkar.net&lt;/a&gt;.&lt;/p&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#the-setup&quot;&gt;The Setup&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#the-problem&quot;&gt;The Problem&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#the-idea&quot;&gt;The Idea&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#the-bundle&quot;&gt;The Bundle&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#the-github-actions-workflow&quot;&gt;The GitHub Actions Workflow&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#the-payoff&quot;&gt;The Payoff&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#the-conclusion&quot;&gt;The Conclusion&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/nav&gt;
&lt;h2 id=&quot;the-setup&quot;&gt;The Setup&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#the-setup&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As our example, we’ll take the &lt;a href=&quot;https://en.wikipedia.org/wiki/static_site_generator&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;static site generator&lt;/a&gt; (SSG) I wrote some time ago: &lt;a href=&quot;https://abhin4v.github.io/shake-blog/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;BlogShake&lt;/a&gt;. It is written as a single Haskell file. It uses &lt;a href=&quot;https://shakebuild.com/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Shake&lt;/a&gt; to build the website, &lt;a href=&quot;https://pandoc.org/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Pandoc&lt;/a&gt; to render posts, and &lt;a href=&quot;https://hackage.haskell.org/package/mustache&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Mustache&lt;/a&gt; for templates. The script starts with these Magix directives&lt;a class=&quot;footnote-ref&quot; href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#fn2&quot; id=&quot;fnref2&quot;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode numberSource bash&quot;&gt;&lt;code class=&quot;sourceCode bash&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;co&quot;&gt;#!/usr/bin/env magix&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;co&quot;&gt;#!magix haskell&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;co&quot;&gt;#!haskellPackages mustache pandoc shake feed yaml&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;co&quot;&gt;#!ghcFlags -threaded -O2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Running the script is as simple as:&lt;/p&gt;
&lt;pre class=&quot;plain&quot;&gt;&lt;code&gt;./blog.hs&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/dschrempf/magix&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Magix&lt;/a&gt; compiles the script into an executable and runs it. Nothing else to install, no &lt;code&gt;cabal&lt;/code&gt;, or &lt;code&gt;nix-shell&lt;/code&gt; required.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://nixos.org&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Nix&lt;/a&gt; and &lt;a href=&quot;https://www.haskell.org/cabal/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Cabal&lt;/a&gt; can also run scripts by providing shebang directives&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;, so why reach for Magix instead? The &lt;code&gt;nix-shell&lt;/code&gt; shebang reinterprets the script with &lt;code&gt;runhaskell&lt;/code&gt; on every run, which is slow. Cabal compiles the script, but it fetches dependencies from Hackage and builds them from source, leading to very slow first build and rebuilds. Magix compiles the script once into a binary executable and caches it for the next runs. It also fetches dependencies from the prebuilt Nix cache. So running via Magix is faster than either case. But when running on GitHub Actions, we have a problem.&lt;/p&gt;
&lt;h2 id=&quot;the-problem&quot;&gt;The Problem&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#the-problem&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/features/actions&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;GitHub Actions&lt;/a&gt; gives us a fresh runner for every build, with no Nix store and no Magix cache. So every run, we have to install Nix and Magix, download all the dependencies, and compile the script. In one instance, the build from scratch took 105 seconds, with installation, dependency download, and compilation taking 92 seconds.&lt;/p&gt;
&lt;p&gt;That is a lot of wasted work because the script and its dependencies change rarely. The actual run itself takes only a few seconds once the executable exists.&lt;/p&gt;
&lt;h2 id=&quot;the-idea&quot;&gt;The Idea&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#the-idea&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;What if we could persist the compiled executable across runs? Magix’s build is deterministic: the same script and the same nixpkgs revision produces the same executable. If we could stash that executable somewhere durable, a cache hit could skip Nix and Magix installation, as well as the script compilation entirely, and just run the executable.&lt;/p&gt;
&lt;p&gt;Magix creates a Nix derivation for compiling the Haskell script with GHC and builds it. The resultant executable lives in Magix’s cache, as a symlink with a path like:&lt;/p&gt;
&lt;pre class=&quot;plain&quot;&gt;&lt;code&gt;$ readlink -f ~/.cache/magix/*blog-result
/nix/store/&amp;lt;hash&amp;gt;-blog&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://haskell.org/ghc/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;GHC&lt;/a&gt; statically links all the Haskell libraries into the executable. The only dynamic dependencies are a handful of libraries—zlib, libffi, gmp etc. So if we have the executable plus those few libraries as a self-contained unit, we don’t need the hundreds of other packages in the Nix store&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;.&lt;/p&gt;
&lt;h2 id=&quot;the-bundle&quot;&gt;The Bundle&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#the-bundle&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I wrote a small script, &lt;code&gt;magix-bundle.sh&lt;/code&gt;, with two subcommands:&lt;/p&gt;
&lt;pre class=&quot;plain&quot;&gt;&lt;code&gt;$ magix-bundle.sh bundle blog.hs     # creates a bundle
$ magix-bundle.sh run blog.hs build  # runs a bundled script&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The script works for any Magix script, not just &lt;code&gt;blog.hs&lt;/code&gt;. Let’s go through it.&lt;/p&gt;
&lt;p&gt;The script takes a command and a script file, derives the bundle name from the script file name, and resolves the directories it needs:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb7&quot;&gt;&lt;pre class=&quot;sourceCode numberSource bash&quot;&gt;&lt;code class=&quot;sourceCode bash&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;bu&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;-euo&lt;/span&gt; pipefail&lt;/span&gt;
&lt;span id=&quot;cb7-2&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb7-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-3&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb7-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;cf&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$#&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-lt&lt;/span&gt; 2 &lt;span class=&quot;bu&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;cf&quot;&gt;then&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-4&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb7-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;bu&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;usage: magix-bundle.sh &amp;lt;bundle|run&amp;gt; &amp;lt;script-file&amp;gt; [args...]&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-5&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb7-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;bu&quot;&gt;exit&lt;/span&gt; 1&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;cf&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-7&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb7-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;va&quot;&gt;CMD&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-8&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb7-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;bu&quot;&gt;shift&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-9&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb7-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;va&quot;&gt;SCRIPT_FILE&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-10&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb7-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;bu&quot;&gt;shift&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-11&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb7-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-12&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb7-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;bu&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$SCRIPT_FILE&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-13&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb7-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;bu&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;error: script not found: &lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$SCRIPT_FILE&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-14&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb7-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;bu&quot;&gt;exit&lt;/span&gt; 1&lt;/span&gt;
&lt;span id=&quot;cb7-15&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb7-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-16&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb7-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-17&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb7-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;va&quot;&gt;NAME&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;basename&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$SCRIPT_FILE&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-18&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb7-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;va&quot;&gt;NAME&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;${NAME&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;%&lt;/span&gt;.&lt;span class=&quot;pp&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-19&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb7-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;va&quot;&gt;HASH&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;sha256sum&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$SCRIPT_FILE&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;awk&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;'{print $1}'&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-20&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb7-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;va&quot;&gt;MAGIX_CACHE&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;${MAGIX_CACHE_DIR&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:-&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;${XDG_CACHE_HOME&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:-&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$HOME&lt;/span&gt;/.cache&lt;span class=&quot;va&quot;&gt;}&lt;/span&gt;/magix&lt;span class=&quot;va&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-21&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb7-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;va&quot;&gt;DEST&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;${MAGIX_BUNDLE_DIR&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:-&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$HOME&lt;/span&gt;/.cache/magix-bundles&lt;span class=&quot;va&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$HASH&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;NAME&lt;/code&gt; is the script file name without its extension, and &lt;code&gt;HASH&lt;/code&gt; is a SHA-256 hash of the script contents; together they key the bundle directory. &lt;code&gt;MAGIX_CACHE&lt;/code&gt; mirrors how Magix itself resolves its cache directory: &lt;code&gt;$XDG_CACHE_HOME/magix&lt;/code&gt; or &lt;code&gt;~/.cache/magix&lt;/code&gt;, overridable with the &lt;code&gt;MAGIX_CACHE_DIR&lt;/code&gt; environment variable. Bundles live under &lt;code&gt;~/.cache/magix-bundles&lt;/code&gt; by default, overridable with the &lt;code&gt;MAGIX_BUNDLE_DIR&lt;/code&gt; env var.&lt;/p&gt;
&lt;h3 id=&quot;creating-the-bundle&quot;&gt;Creating the Bundle&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#creating-the-bundle&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;bundle&lt;/code&gt; function locates the script’s build result in Magix’s cache, copies the executable out of the Nix store, and gathers the libraries it links against:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb8&quot;&gt;&lt;pre class=&quot;sourceCode numberSource bash&quot;&gt;&lt;code class=&quot;sourceCode bash&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;fu&quot;&gt;copy_lib_deps()&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-2&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;bu&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-3&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;bu&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;deps&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;dep&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;base&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-4&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;deps&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;ldd&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$src&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;awk&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;'/\/nix\/store\//{print $3}'&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-5&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;cf&quot;&gt;for&lt;/span&gt; dep &lt;span class=&quot;kw&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;$deps&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;cf&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-6&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;cf&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$dep&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-7&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;pp&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;pp&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;-glibc-&lt;/span&gt;&lt;span class=&quot;pp&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;pp&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cf&quot;&gt;continue&lt;/span&gt; &lt;span class=&quot;cf&quot;&gt;;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-8&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;cf&quot;&gt;esac&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-9&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;bu&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$dep&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-10&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;bu&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;error: dependency '&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$dep&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;' of '&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$src&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;' not found&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-11&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;bu&quot;&gt;exit&lt;/span&gt; 1&lt;/span&gt;
&lt;span id=&quot;cb8-12&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-13&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;va&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;basename&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$dep&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-14&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;cf&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$DEST&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;/lib/&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$base&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;cf&quot;&gt;then&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-15&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;fu&quot;&gt;cp&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;-L&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$dep&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$DEST&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;/lib/&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$base&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-16&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;ex&quot;&gt;copy_lib_deps&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$dep&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-17&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;cf&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-18&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;cf&quot;&gt;done&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-19&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-20&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-21&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;bundle()&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-22&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$DEST&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;/bin&quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$DEST&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;/lib&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-23&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-24&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;RESULT&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-25&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;cf&quot;&gt;for&lt;/span&gt; f &lt;span class=&quot;kw&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$MAGIX_CACHE&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;/&quot;&lt;/span&gt;&lt;span class=&quot;pp&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;-&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$NAME&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;-result&quot;&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;cf&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-26&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-26&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;bu&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-L&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$f&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;cf&quot;&gt;continue&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-27&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-27&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;bu&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$f&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;cf&quot;&gt;continue&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-28&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-28&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;cf&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-z&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$RESULT&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$f&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-nt&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$RESULT&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;cf&quot;&gt;then&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-29&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-29&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;RESULT&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$f&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-30&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-30&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;cf&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-31&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-31&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;cf&quot;&gt;done&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-32&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-32&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;bu&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-n&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$RESULT&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-33&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-33&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;bu&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;error: no build result for '&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$SCRIPT_FILE&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;' found in &lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$MAGIX_CACHE&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-34&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-34&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;bu&quot;&gt;exit&lt;/span&gt; 1&lt;/span&gt;
&lt;span id=&quot;cb8-35&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-35&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-36&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-36&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-37&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-37&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;RESULT&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;readlink&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$RESULT&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-38&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-38&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;va&quot;&gt;BIN&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$RESULT&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;/bin/.&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$NAME&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;-wrapped&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-39&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-39&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;cp&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$BIN&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$DEST&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;/bin/&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$NAME&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-40&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-40&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;fu&quot;&gt;chmod&lt;/span&gt; +w &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$DEST&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;/bin/&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$NAME&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-41&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-41&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-42&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-42&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ex&quot;&gt;copy_lib_deps&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$BIN&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-43&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-43&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-44&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-44&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;cf&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;uname&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;-m&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-45&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-45&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ss&quot;&gt;x86_64&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-46&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-46&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;INTERPRETER&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;=&lt;/span&gt;/lib64/ld-linux-x86-64.so.2&lt;/span&gt;
&lt;span id=&quot;cb8-47&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-47&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;cf&quot;&gt;;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-48&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-48&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ss&quot;&gt;aarch64&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-49&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-49&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;va&quot;&gt;INTERPRETER&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;=&lt;/span&gt;/lib/ld-linux-aarch64.so.1&lt;/span&gt;
&lt;span id=&quot;cb8-50&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-50&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;cf&quot;&gt;;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-51&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-51&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;pp&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-52&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-52&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;bu&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;error: unsupported architecture: &lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;uname&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;-m&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-53&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-53&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;bu&quot;&gt;exit&lt;/span&gt; 1&lt;/span&gt;
&lt;span id=&quot;cb8-54&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-54&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;cf&quot;&gt;;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-55&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-55&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;cf&quot;&gt;esac&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-56&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-56&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-57&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-57&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ex&quot;&gt;patchelf&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-58&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-58&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;at&quot;&gt;--set-interpreter&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$INTERPRETER&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-59&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-59&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;at&quot;&gt;--set-rpath&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;dt&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;ORIGIN/lib&quot;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-60&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-60&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$DEST&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;/bin/&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$NAME&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-61&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-61&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-62&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-62&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;cf&quot;&gt;for&lt;/span&gt; lib &lt;span class=&quot;kw&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$DEST&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;/lib/&lt;span class=&quot;pp&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;cf&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-63&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-63&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;bu&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$lib&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;cf&quot;&gt;continue&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-64&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-64&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;chmod&lt;/span&gt; +w &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$lib&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-65&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-65&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ex&quot;&gt;patchelf&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;--set-rpath&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;dt&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;ORIGIN&quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$lib&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-66&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-66&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;cf&quot;&gt;done&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-67&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-67&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;bu&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;bundle created at &lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$DEST&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-68&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb8-68&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here is what it does:&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;It picks the latest &lt;code&gt;&amp;lt;hash&amp;gt;-&amp;lt;name&amp;gt;-result&lt;/code&gt; symlink for the script by modified time, skipping dangling ones&lt;a class=&quot;footnote-ref&quot; href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#fn5&quot; id=&quot;fnref5&quot;&gt;&lt;sup&gt;5&lt;/sup&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;It dereferences the symlink to a Nix store path, copies the compiled executable at &lt;code&gt;bin/.&amp;lt;name&amp;gt;-wrapped&lt;/code&gt; from the Nix store path into the bundle&lt;a class=&quot;footnote-ref&quot; href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#fn6&quot; id=&quot;fnref6&quot;&gt;&lt;sup&gt;6&lt;/sup&gt;&lt;/a&gt;, and makes the copy writable.&lt;a class=&quot;footnote-ref&quot; href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#fn7&quot; id=&quot;fnref7&quot;&gt;&lt;sup&gt;7&lt;/sup&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;It copies the dynamic library dependencies of the executable by calling the function &lt;code&gt;copy_lib_deps&lt;/code&gt;. &lt;code&gt;copy_lib_deps&lt;/code&gt; finds the dependencies with &lt;code&gt;ldd&lt;/code&gt;, and copies the ones that live in &lt;code&gt;/nix/store&lt;/code&gt; into the bundle’s &lt;code&gt;lib/&lt;/code&gt; directory, skipping glibc. Note that it does this recursively, copying the dependencies of dependencies as well.&lt;/li&gt;
&lt;li&gt;It rewrites the executable with &lt;code&gt;patchelf&lt;/code&gt;, setting the interpreter and the library search path for it. It also sets the library search path for libraries themselves so that transitive dependencies work as well.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The two &lt;code&gt;patchelf&lt;/code&gt; flags are the interesting part. The &lt;code&gt;--set-rpath&lt;/code&gt; flag makes the dynamic loader find the bundled libraries, so we don’t need &lt;code&gt;LD_LIBRARY_PATH&lt;/code&gt; or the Nix store at run time. The &lt;code&gt;--set-interpreter&lt;/code&gt; flag is needed because Nix rewrites each executable’s dynamic loader to point at its own glibc inside the Nix store. Since we don’t bundle glibc, we reset the interpreter to the host’s loader according to the system’s architecture&lt;a class=&quot;footnote-ref&quot; href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#fn8&quot; id=&quot;fnref8&quot;&gt;&lt;sup&gt;8&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;bundling-glibc&quot;&gt;Bundling glibc?&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#bundling-glibc&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We deliberately do not bundle glibc. Unlike the other libraries, glibc cannot simply be shipped alongside the executable&lt;a class=&quot;footnote-ref&quot; href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#fn9&quot; id=&quot;fnref9&quot;&gt;&lt;sup&gt;9&lt;/sup&gt;&lt;/a&gt;. The dynamic loader needs to be at an absolute path and needs to be matched with the glibc version. So we simply don’t bundle it and rely on the host’s glibc. One caveat here is that the host’s glibc must be at least as new as the one the executable was built against. That works because glibc is backwards-compatible&lt;a class=&quot;footnote-ref&quot; href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#fn10&quot; id=&quot;fnref10&quot;&gt;&lt;sup&gt;10&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;running-the-bundle&quot;&gt;Running the Bundle&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#running-the-bundle&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The rest of the script is the &lt;code&gt;run&lt;/code&gt; subcommand and the command dispatch:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb9&quot;&gt;&lt;pre class=&quot;sourceCode numberSource bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb9-1&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb9-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;run()&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-2&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb9-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;bu&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;bin&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$DEST&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;/bin/&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$NAME&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&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;cf&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$bin&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$DEST&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;/lib&quot;&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;cf&quot;&gt;then&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;bu&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;error: no bundle for '&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$SCRIPT_FILE&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;' at &lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$DEST&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;2&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 class=&quot;bu&quot;&gt;exit&lt;/span&gt; 1&lt;/span&gt;
&lt;span id=&quot;cb9-6&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb9-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;cf&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-7&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb9-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;bu&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$bin&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$@&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&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;&lt;span class=&quot;kw&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;&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;&lt;span class=&quot;cf&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$CMD&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;in&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 class=&quot;ss&quot;&gt;bundle&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;)&lt;/span&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 class=&quot;cf&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$#&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-gt&lt;/span&gt; 0 &lt;span class=&quot;bu&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;cf&quot;&gt;then&lt;/span&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;bu&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;error: 'bundle' takes no extra arguments&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-14&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb9-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;bu&quot;&gt;exit&lt;/span&gt; 1&lt;/span&gt;
&lt;span id=&quot;cb9-15&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb9-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;cf&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-16&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb9-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ex&quot;&gt;bundle&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-17&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb9-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;cf&quot;&gt;;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-18&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb9-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ss&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ex&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$@&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;cf&quot;&gt;;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-19&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb9-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;pp&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-20&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb9-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;bu&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;error: unknown command '&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;$CMD&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;' (expected 'bundle' or 'run')&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-21&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb9-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;bu&quot;&gt;exit&lt;/span&gt; 1&lt;/span&gt;
&lt;span id=&quot;cb9-22&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb9-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;cf&quot;&gt;;;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-23&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb9-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;cf&quot;&gt;esac&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;run&lt;/code&gt; computes the same SHA-256 hash of the script, checks that the bundle exists, and &lt;a href=&quot;https://en.wikipedia.org/wiki/Exec_(system_call)&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;&lt;code&gt;exec&lt;/code&gt;&lt;/a&gt;s the executable, passing the remaining arguments through untouched.&lt;/p&gt;
&lt;h2 id=&quot;the-github-actions-workflow&quot;&gt;The GitHub Actions Workflow&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#the-github-actions-workflow&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The workflow uses Nix, Magix and the bundler script to execute the Haskell script.&lt;/p&gt;
&lt;p&gt;First, we set the runner image and the nixpkgs branch we track&lt;a class=&quot;footnote-ref&quot; href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#fn11&quot; id=&quot;fnref11&quot;&gt;&lt;sup&gt;11&lt;/sup&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb10&quot;&gt;&lt;pre class=&quot;sourceCode numberSource yaml&quot;&gt;&lt;code class=&quot;sourceCode yaml&quot;&gt;&lt;span id=&quot;cb10-1&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; Build blog&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-2&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-3&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-4&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-5&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;branches&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;kw&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;at&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-6&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;workflow_dispatch&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-7&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-8&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-9&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-10&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; build&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-11&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; ubuntu-26.04&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-12&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-13&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb10-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;NIXPKGS_BRANCH&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; release-26.05&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The next two steps compute the cache key and restore the bundle if we have one:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb11&quot;&gt;&lt;pre class=&quot;sourceCode numberSource yaml&quot;&gt;&lt;code class=&quot;sourceCode yaml&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;at&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&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;at&quot;&gt;      &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;fu&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; checkout&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 class=&quot;at&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; actions/checkout@v6&lt;/span&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 class=&quot;at&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&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;at&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;ref&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; main&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&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 class=&quot;at&quot;&gt;      &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;fu&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; resolve nixpkgs commit&lt;/span&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 class=&quot;at&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; nixpkgs&lt;/span&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;fu&quot;&gt;        run&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;ch&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-10&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb11-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          set -euo pipefail&lt;/span&gt;
&lt;span id=&quot;cb11-11&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb11-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          SHA=$(git ls-remote https://github.com/NixOS/nixpkgs.git &quot;refs/heads/$NIXPKGS_BRANCH&quot; | cut -f1)&lt;/span&gt;
&lt;span id=&quot;cb11-12&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb11-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          echo &quot;sha=$SHA&quot; &amp;gt;&amp;gt; &quot;$GITHUB_OUTPUT&quot;&lt;/span&gt;
&lt;span id=&quot;cb11-13&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb11-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-14&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb11-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;      &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;fu&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; cache blog bundle&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-15&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb11-15&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;id&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; cache-blog&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-16&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb11-16&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;uses&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; actions/cache@v5&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-17&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb11-17&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;with&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-18&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb11-18&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;path&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; ~/.cache/magix-bundles&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-19&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb11-19&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;key&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; magix-bundles-${{ hashFiles('blog.hs') }}-${{ steps.nixpkgs.outputs.sha }}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We resolve the nixpkgs branch to its latest commit with &lt;code&gt;git ls-remote&lt;/code&gt; at the start of the job, use that commit in the cache key, and pin the whole build to the same commit via &lt;code&gt;MAGIX_NIXPKGS_REF&lt;/code&gt;, as we see below.&lt;/p&gt;
&lt;p&gt;The cache key has two parts: the hash of the script and the resolved nixpkgs commit hash. When the branch moves or the script changes, the cache misses because of the key change, and we rebuild against the new commit and/or script. We also restore the previously cached bundle to &lt;code&gt;~/.cache/magix-bundles&lt;/code&gt;, if found.&lt;/p&gt;
&lt;p&gt;The next four steps run only on a cache miss:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb12&quot;&gt;&lt;pre class=&quot;sourceCode numberSource yaml&quot;&gt;&lt;code class=&quot;sourceCode yaml&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;at&quot;&gt;      &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;fu&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; install Nix&lt;/span&gt;&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;at&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; steps.cache-blog.outputs.cache-hit != 'true'&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;at&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; DeterminateSystems/nix-installer-action@v22&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;at&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;kw&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 class=&quot;fu&quot;&gt;          extra-conf&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;ch&quot;&gt;|&lt;/span&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;            extra-substituters = https://dschrempf-magix.cachix.org&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;            extra-trusted-public-keys = dschrempf-magix.cachix.org-1:cScG6NjZBiQvY7KjSPpQdUa9UXZVLz9rvUZHtuwdYwc=&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;at&quot;&gt;      &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;fu&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; install magix&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;at&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; steps.cache-blog.outputs.cache-hit != 'true'&lt;/span&gt;&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;at&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; nix profile install github:dschrempf/magix&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&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 class=&quot;at&quot;&gt;      &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;fu&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; compile blog&lt;/span&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 class=&quot;at&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; steps.cache-blog.outputs.cache-hit != 'true'&lt;/span&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;at&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;kw&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;at&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;MAGIX_NIXPKGS_REF&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; github:NixOS/nixpkgs/${{ steps.nixpkgs.outputs.sha }}&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;at&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; ./blog.hs&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-18&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb12-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-19&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb12-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;      &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;fu&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; create bundle&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-20&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb12-20&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;if&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; steps.cache-blog.outputs.cache-hit != 'true'&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-21&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb12-21&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;run&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; ./scripts/magix-bundle.sh bundle blog.hs&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;install Nix&lt;/code&gt; adds Magix’s binary cache to Nix, so that we get the prebuilt packages for Magix. The &lt;code&gt;compile blog&lt;/code&gt; step runs &lt;code&gt;./blog.hs&lt;/code&gt; with no arguments&lt;a class=&quot;footnote-ref&quot; href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#fn12&quot; id=&quot;fnref12&quot;&gt;&lt;sup&gt;12&lt;/sup&gt;&lt;/a&gt;: This causes Magix to compile the script, but Shake has nothing to build, so it exits immediately. The build is pinned to the same nixpkgs commit that keys the cache, via the &lt;code&gt;MAGIX_NIXPKGS_REF&lt;/code&gt; env variable used by Magix. Finally, &lt;code&gt;create bundle&lt;/code&gt; packages the compiled executable by running the bash script we saw earlier.&lt;/p&gt;
&lt;p&gt;The rest of the workflow runs on every run, cache hit or not:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb13&quot;&gt;&lt;pre class=&quot;sourceCode numberSource yaml&quot;&gt;&lt;code class=&quot;sourceCode yaml&quot;&gt;&lt;span id=&quot;cb13-1&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb13-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;at&quot;&gt;      &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;fu&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; build site&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-2&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb13-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;run&lt;/span&gt;&lt;span class=&quot;kw&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;at&quot;&gt; ENV=PROD ./scripts/magix-bundle.sh run blog.hs -j4 build&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I’ve cut down the rest of the workflow to the only step that is relevant to us: &lt;code&gt;build site&lt;/code&gt; that runs the bundled executable with the script’s arguments. Other steps are specific to BlogShake.&lt;/p&gt;
&lt;h2 id=&quot;the-payoff&quot;&gt;The Payoff&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#the-payoff&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;All of this work, what does it buy us? Here are two numbers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Build with no bundle: 1 min 45 sec.&lt;/li&gt;
&lt;li&gt;Build with cached bundle: 10 sec.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With the cached bundle, the runner just downloads it and runs the executable, skipping Nix and Magix installation and script compilation altogether.&lt;/p&gt;
&lt;h2 id=&quot;the-conclusion&quot;&gt;The Conclusion&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#the-conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This post showed how to speed up a Haskell script running on GitHub Actions by caching a compact bundle of its compiled executable. The approach works for any Haskell script that runs on Linux: compile once using Magix, bundle the binary with its library dependencies, and let the cache do the rest. One caveat though: the bundler script uses the internal details of Magix, which may break if Magix changes how it works.&lt;/p&gt;
&lt;p&gt;The full source code:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/abhin4v/shake-blog/blob/main/blog.hs&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;BlogShake Haskell script&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/abhin4v/shake-blog/blob/main/scripts/magix-bundle.sh&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Magix bundle script&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/abhin4v/shake-blog/blob/main/.github/workflows/build.yml&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;BlogShake GitHub Actions workflow&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;At the point of writing this post, Magix supported Bash, Haskell, and Python.&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;Because the executable is compiled once and run many times, we build the script with &lt;code&gt;-O2&lt;/code&gt;.&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;The shebang-based alternatives look like this:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb3&quot;&gt;&lt;pre class=&quot;sourceCode bash noNumberSource&quot;&gt;&lt;code class=&quot;sourceCode bash&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;co&quot;&gt;#! /usr/bin/env nix-shell&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-2&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;#! nix-shell -p &quot;haskellPackages.ghcWithPackages (p: [p.pandoc p.shake p.mustache p.feed p.yaml])&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-3&quot;&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#cb3-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;#! nix-shell -i runhaskell&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;for Nix, and:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb4&quot;&gt;&lt;pre class=&quot;sourceCode bash noNumberSource&quot;&gt;&lt;code class=&quot;sourceCode bash&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;co&quot;&gt;#! /usr/bin/env cabal&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;&lt;span class=&quot;ex&quot;&gt;{-&lt;/span&gt; cabal:&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;&lt;span class=&quot;ex&quot;&gt;build-depends:&lt;/span&gt; base, pandoc, shake, mustache, feed, yaml&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;ex&quot;&gt;-}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;for Cabal.&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;Why not cache the entire Nix store between runs? Because the size of the full Nix store closure required to build Haskell scripts is usually in GBs. Caching that per run would defeat the purpose of caching by taking way too much time to download the cache. You may also want to reach out for the &lt;a href=&quot;https://nix.dev/manual/nix/2.35/command-ref/new-cli/nix3-bundle.html&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Nix bundle&lt;/a&gt; feature, which produces self-contained compressed executables. But these executables are still too big: 45 MB compressed/178 MB uncompressed for BlogShake. Our approach in this post results in a 9 MB bundle, compressed.&lt;/p&gt;
&lt;p&gt;Another completely different option is to build a fully statically linked executable, which I wrote about in &lt;a href=&quot;https://abhinavsarkar.net/posts/nix-for-haskell-static-builds/?mtm_campaign=feed&quot;&gt;Nix for Haskell: Static Builds&lt;/a&gt;. However, that requires a custom toolchain, running which on GitHub Action is too complex and/or slow.&lt;a class=&quot;footnote-back&quot; href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#fnref4&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn5&quot;&gt;&lt;p&gt;A result symlink can be left dangling if the store path has been garbage-collected. We skip those and pick the newest live one.&lt;a class=&quot;footnote-back&quot; href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#fnref5&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn6&quot;&gt;&lt;p&gt;Magix wraps the built executable with &lt;code&gt;wrapProgram&lt;/code&gt;, which renames the real executable to &lt;code&gt;bin/.&amp;lt;name&amp;gt;-wrapped&lt;/code&gt; and puts a wrapper script in its place. We copy the real executable.&lt;a class=&quot;footnote-back&quot; href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#fnref6&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn7&quot;&gt;&lt;p&gt;Nix store files are read-only mode, and we are about to modify the file, so we make it writable.&lt;a class=&quot;footnote-back&quot; href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#fnref7&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn8&quot;&gt;&lt;p&gt;We hardcode the loader paths here, but it should work on most mainstream Linux distributions with glibc.&lt;a class=&quot;footnote-back&quot; href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#fnref8&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn9&quot;&gt;&lt;p&gt;Well, it can be actually. That’s what Nix bundle does. It copies the glibc in the Nix store to the bundle, and points the program interpreter at the bundled loader inside a &lt;a href=&quot;https://en.wikipedia.org/wiki/chroot&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;chroot&lt;/a&gt;.&lt;a class=&quot;footnote-back&quot; href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#fnref9&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn10&quot;&gt;&lt;p&gt;An executable built against glibc 2.42 runs fine on a host with glibc 2.43, but not the other way around.&lt;a class=&quot;footnote-back&quot; href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#fnref10&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn11&quot;&gt;&lt;p&gt;The glibc constraint dictates the runner image. Here we build against nixpkgs branch &lt;code&gt;release-26.05&lt;/code&gt;, which has glibc 2.42. Ubuntu 26.04, the GitHub runner image we use, ships with glibc 2.43. So they are compatible.&lt;a class=&quot;footnote-back&quot; href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#fnref11&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn12&quot;&gt;&lt;p&gt;That no-argument behavior is Shake-specific: with no actions given, Shake runs nothing, so a bare &lt;code&gt;./blog.hs&lt;/code&gt; compiles the script and exits. A general script won’t do that by default. If you adapt this for a non-Shake script, give it a mode that does nothing, say a &lt;code&gt;--compile&lt;/code&gt; flag, so running it bare just produces the executable. This step’s only job is to get Magix to build the script, not to run it.&lt;a class=&quot;footnote-back&quot; href=&quot;https://abhinavsarkar.net/posts/tags/haskell/feed.atom#fnref12&quot;&gt;↩︎&lt;/a&gt;&lt;/p&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/fast-haskell-scripts-on-github-actions/?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/117071410353946821&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/guqk6b&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/1vky99w/&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.nixos.org/t//79502&quot; rel=&quot;syndication&quot; target=&quot;_blank&quot;&gt;Discourse&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://abhinavsarkar.net/posts/fast-haskell-scripts-on-github-actions/?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>Mon, 10 Aug 2026 00:00:00 +0000</pubDate>
	<author>abhinav@abhinavsarkar.net (Abhinav Sarkar)</author>
</item>
<item>
	<title>Oskar Wickström: How Antithesis Found and Explained a Bombadil Race Condition</title>
	<guid isPermaLink="true">https://wickstrom.tech/2026-08-07-bombadil-race-condition-antithesis.html</guid>
	<link>https://wickstrom.tech/2026-08-07-bombadil-race-condition-antithesis.html</link>
	<description>&lt;p&gt;&lt;em&gt;Disclosure: I’m the original author and lead for the Bombadil project at Antithesis.&lt;/em&gt;&lt;/p&gt; &lt;p&gt;&lt;a href=&quot;https://catala.dev/&quot;&gt;Carlos Catala&lt;/a&gt;, interning at Antithesis and working on testing our webapps, found a strange crash while I was out camping. The tests he works on runs Antithesis’ webapp &lt;em&gt;inside Antithesis&lt;/em&gt; and explores it using Bombadil. That surfaced a particular sequence of events leading up to the following crash (logs are simplified for readability):&lt;/p&gt; &lt;pre&gt;&lt;code&gt;state machine error: unhandled transition: Running(10) + ActionAccepted(Click(&quot;Filters&quot;))&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;What does this mean? To understand it, we need to back up a little.&lt;/p&gt; &lt;p&gt;The heart of the browser &lt;em&gt;driver&lt;/em&gt; is a finite state machine, an abstract model of a tab in Chrome or Chromium, and how we’re interacting with it over CDP. This is necessary due to how you can only invoke certain commands in certain browser states, or it might hang or behave in other confounding ways. In our state machine, some transitions are valid, and those are handled in a big &lt;code&gt;match (state, event) { ... }&lt;/code&gt; expression that returns a new state. Invalid transitions are covered by the last branch that returns an &lt;code&gt;Err&lt;/code&gt; with a message like the above.&lt;/p&gt; &lt;p&gt;There’s another important component involved which is called the &lt;em&gt;runner&lt;/em&gt;. It decides the control flow of the test, and uses the driver to run the system under test. The driver emits a state, and the runner decides what action to take in that state. It hands back the action to the driver so that it can apply it. The browser driver actually pauses the JS runtime when capturing a state, and doesn’t resume execution until the driver has given back the next action.&lt;/p&gt; &lt;p&gt;Hence, the &lt;code&gt;ActionAccepted&lt;/code&gt; event (which is when the driver gets a new action from the runner) is not valid in the &lt;code&gt;Running&lt;/code&gt; state. It really is only valid in the &lt;code&gt;Paused&lt;/code&gt; state. How could this happen? The driver and runner are supposed to operate in lock-step, where the driver is only in control while the JS runtime is paused. This was the nut to crack.&lt;/p&gt; &lt;p&gt;When Carlos told me about this during my PTO, my camping brain was definitely not helpful, so I let it rest until I was back at work. Staring at logs and code also didn’t help much, except for a poorly conceived theory about what could be going on, mislead by the presence of &lt;a href=&quot;https://antithesis.com/docs/product/fault_injection/fault_types/#network-faults&quot;&gt;network faults&lt;/a&gt; in one test where we saw the bug. We tried but failed to reproduce this locally, so I decided to find a simpler test subject and, crucially, try to reproduce it in Antithesis.&lt;/p&gt; &lt;h2 id=&quot;a-simple-reproduction-with-causality-analysis&quot;&gt;A Simple Reproduction with Causality Analysis&lt;/h2&gt; &lt;p&gt;To reduce possible confusion I wanted to first see if I could trigger the same bug in Bombadil with a simpler system under test. I found a Dockerized version of &lt;a href=&quot;https://the-internet.herokuapp.com/&quot;&gt;the-internet&lt;/a&gt;, an example application by Sauce Labs made for automated browser testing. Based on what we had seen before, I wrote a very small specification that only performs three actions:&lt;/p&gt; &lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot;&gt;&lt;pre class=&quot;sourceCode typescript&quot;&gt;&lt;code class=&quot;sourceCode typescript&quot;&gt;&lt;span id=&quot;cb2-1&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb2-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;im&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;im&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;@antithesishq/bombadil/browser/defaults/properties&quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt; &lt;span id=&quot;cb2-2&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb2-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;im&quot;&gt;import&lt;/span&gt; { weighted } &lt;span class=&quot;im&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;@antithesishq/bombadil/browser&quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt; &lt;span id=&quot;cb2-3&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb2-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;im&quot;&gt;import&lt;/span&gt; {&lt;/span&gt; &lt;span id=&quot;cb2-4&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb2-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; back&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span id=&quot;cb2-5&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb2-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; forward&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span id=&quot;cb2-6&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb2-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; clicks&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span id=&quot;cb2-7&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb2-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;} &lt;span class=&quot;im&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;@antithesishq/bombadil/browser/defaults/actions&quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt; &lt;span id=&quot;cb2-8&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb2-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt; &lt;span id=&quot;cb2-9&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb2-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;im&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;const&lt;/span&gt; navigation &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;weighted&lt;/span&gt;([&lt;/span&gt; &lt;span id=&quot;cb2-10&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb2-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; [&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; clicks]&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span id=&quot;cb2-11&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb2-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; [&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; back]&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/span&gt; &lt;span id=&quot;cb2-12&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb2-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; [&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; forward]&lt;/span&gt; &lt;span id=&quot;cb2-13&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb2-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;])&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; &lt;p&gt;In addition to finding various bugs in the Ruby code, it also immediately reproduced the Bombadil bug! Time to dig in. I went through a few instances and started to see a pattern. In addition, this gave me an excellent opportunity to try out &lt;a href=&quot;https://antithesis.com/docs/product/debugging/causality_analysis/&quot;&gt;Causality Analysis&lt;/a&gt;, a mind-bending feature for learning what behavior increases the likelihood of a bug appearing. Here’s the report I got:&lt;/p&gt; &lt;figure&gt; &lt;img alt=&quot;The causality analysis report plots the likelihood and helps you understand what events caused a certain bug.&quot; src=&quot;https://wickstrom.tech/assets/causality-analysis.webp&quot; /&gt; &lt;figcaption&gt;The causality analysis report plots the likelihood and helps you understand what events caused a certain bug.&lt;/figcaption&gt; &lt;/figure&gt; &lt;p&gt;As you may see in the chart, there are three points where the probability increases markedly. Correlating those with the logs (which is easy, you see the bumps highlighted in the log too), I could find the chain leading up to the bug:&lt;/p&gt; &lt;ol type=&quot;1&quot;&gt; &lt;li&gt;Click a link that navigates to &lt;code&gt;/frames&lt;/code&gt; (probability goes to 20%)&lt;/li&gt; &lt;li&gt;On that page, click a link that navigates to &lt;code&gt;/iframe&lt;/code&gt; (probability goes to 47%)&lt;/li&gt; &lt;li&gt;Go back (I was a bit surprised that this didn’t bump probability noticeably)&lt;/li&gt; &lt;li&gt;Go forward (probability goes to 99.98%)&lt;/li&gt; &lt;/ol&gt; &lt;p&gt;After the last “Go forward” action, it’s a done deal. Digging into the details in between these points, I could then see how going back to a page which immediately throws an exception, after restoring from &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/bfcache&quot;&gt;bfcache&lt;/a&gt;, takes a different path than most page loads do.&lt;/p&gt; &lt;h2 id=&quot;the-bug&quot;&gt;The Bug&lt;/h2&gt; &lt;p&gt;When going back or forward in history, the state machine immediately transitions to &lt;code&gt;Running&lt;/code&gt;, waiting for confirmation by the browser to know what actually happened. Some pages prevent bfcache through JavaScript or HTTP headers, so a history navigation can also end up as a full page load with new HTTP requests. When the page is confirmed to have been restored from bfcache, the page and thus the state machine model skips the &lt;code&gt;Loading&lt;/code&gt; state entirely, and goes straight to &lt;code&gt;Running&lt;/code&gt;.&lt;/p&gt; &lt;p&gt;In this case, that was followed by the exception being thrown immediately (you can see it in the bottom of the screenshot above), which triggers another path: exceptions thrown while in &lt;code&gt;Running&lt;/code&gt; aren’t collected and reported at a later state capture, as is the case for the &lt;code&gt;Loading&lt;/code&gt; state — they immediately pause the runtime and trigger a new state read. This in turn let the runner pick a new action to perform. But the CDP event that confirms that the page was restored from bfcache hadn’t arrived yet.&lt;/p&gt; &lt;p&gt;This is a race between the asynchronous communication of runner and browser state machine, selecting the next action, and the CDP event sent by Chromium over a WebSocket confirming the bfcache restore. The unfortunate ordering that triggers the bug is:&lt;/p&gt; &lt;ol type=&quot;1&quot;&gt; &lt;li&gt;Back or forward, restoring from bfcache&lt;/li&gt; &lt;li&gt;Exception thrown on restored page, pausing the debugger and capturing a new state&lt;/li&gt; &lt;li&gt;Runner picking a new action and passing it back to the browser state machine&lt;/li&gt; &lt;li&gt;Confirmation of bfcache restoration coming in, transitioning state machine to &lt;code&gt;Running&lt;/code&gt;&lt;/li&gt; &lt;li&gt;State machine applying the &lt;code&gt;ActionAccepted&lt;/code&gt; event, which, as we noted in the beginning of this excursion, is not valid when in &lt;code&gt;Running&lt;/code&gt;&lt;/li&gt; &lt;/ol&gt; &lt;p&gt;This sequence causes the crash. It only happens with bfcache-enabled history navigation to a page with an exception being thrown before the confirmation from Chromium comes back. Antithesis’ deterministic fuzzing environment messes with process scheduling and action selection and discovers this sequence reliably.&lt;/p&gt; &lt;h2 id=&quot;in-conclusion&quot;&gt;In Conclusion&lt;/h2&gt; &lt;p&gt;I’m not going to describe the fix in too much detail, but it involves a more robust use of the already existing &lt;code&gt;Generation&lt;/code&gt; value in the browser state machine. It’s a monotonically increasing number that is used to detect stale timeouts and actions, so that the state machine can discard them. The browser state now carries the current generation, and that is threaded through the runner’s action selection process, so that a stale action (as in step 5 above) can be safely ignored. Additionally, some transitions now increment the generation in cases where all existing timeouts or actions are stale.&lt;/p&gt; &lt;p&gt;I’ve had bugs of this kind before, and understanding them from staring at logs, let alone reproducing them, has been painful. This, in contrast, feels a bit like cheating. Moreover, it extends to race conditions and complicated bugs in the webapps themselves, which makes me very excited about continued work on the Bombadil and Antithesis integration.&lt;/p&gt;</description>
	<pubDate>Thu, 06 Aug 2026 22:00:00 +0000</pubDate>
</item>
<item>
	<title>Mark Jason Dominus: The road to epsilon-zero: Coin-moving games with no coins</title>
	<guid isPermaLink="false">tag:,2026:/math/ordinals/04-coordinates</guid>
	<link>https://blog.plover.com/math/ordinals/04-coordinates.html</link>
	<description>&lt;p&gt;Previously:&lt;/p&gt;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

&lt;p&gt;Coming next:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can write a program to print an infinite list of strings, but
you can't always write one to print them in alphabetic order:
&lt;a href=&quot;https://blog.plover.com/math/ordinals/05-shortlex.html&quot;&gt;Productive programs and well-founded orders&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.plover.com/math/ordinals/06-nim-shortlex.html&quot;&gt;Shortlex order also orders sequences of numbers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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



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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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



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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

&lt;p&gt;[ Addendum 20260815: For now, the space on the right is being occupied by &lt;em&gt;The Crazy Ape&lt;/em&gt;, by Nobel prizewinner &lt;a href=&quot;https://en.wikipedia.org/wiki/Albert_Szent%2dGy%c3%b6rgyi&quot;&gt;Albert Szent-Györgyi&lt;/a&gt;.
This short book imprinted itself on me deeply when I was fourteen
years old and has guided me since.  Published in 1970, it is about how
wars are perpetrated by the old against the young. ]&lt;/p&gt;

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

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

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

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

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

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

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

Read this post and make me a Claude Code skill that reviews a Haskell diff for
the constraint-evading compromises it describes: suppressed warnings, string
and field stuffing, and weakened types that differ from any recorded plans.
Some of these hide in code that did not change but should have, so the skill
should start from the functions that changed and evaluate how they use or abuse
the types involved, but also spot type changes that look suspicious.&lt;/code&gt;&lt;/pre&gt;</description>
	<pubDate>Wed, 22 Jul 2026 16:10:56 +0000</pubDate>
</item>
<item>
	<title>Well-Typed.Com: New falsify release</title>
	<guid isPermaLink="false">http://www.well-typed.com/blog/2026/07/falsify-4</guid>
	<link>https://well-typed.com/blog/2026/07/falsify-4</link>
	<description>&lt;p&gt;Recently Martijn Bastiaan, QBayLogic’s &lt;a href=&quot;https://qbaylogic.com/team/&quot;&gt;COO&lt;/a&gt;,
invited Well-Typed to come to QBayLogic HQ and give a one-day workshop on
&lt;a href=&quot;https://hackage.haskell.org/package/falsify&quot;&gt;falsify&lt;/a&gt;, the new property based
testing library that I developed for the Haskell Symposium back in 2023
(&lt;a href=&quot;https://dl.acm.org/doi/10.1145/3609026.3609733&quot;&gt;paper&lt;/a&gt;,
&lt;a href=&quot;https://www.youtube.com/watch?v=csKkTas6X58&quot;&gt;presentation&lt;/a&gt;).
&lt;a href=&quot;https://qbaylogic.com/&quot;&gt;QBayLogic&lt;/a&gt; is the company behind
&lt;a href=&quot;https://clash-lang.org/&quot;&gt;Clash&lt;/a&gt;: a purely functional language for hardware
design. In case you haven’t heard of it, Clash translates Haskell to VHDL or
Verilog, which can in turn be translated to actual hardware. It literally uses
&lt;a href=&quot;https://hackage.haskell.org/package/clash-ghc&quot;&gt;&lt;code&gt;ghc&lt;/code&gt; as its frontend&lt;/a&gt; so you
have essentially the full power of Haskell available. It’s a great project, I
recommend checking it out.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;falsify&lt;/code&gt; library takes its main inspiration from the Python
&lt;a href=&quot;https://hypothesis.works/&quot;&gt;Hypothesis&lt;/a&gt; library, though it is not a direct
translation: it takes the same core idea (“parse, don’t generate”) but
reinterprets it in a way that better suits the Haskell way of thinking: more
axiomatic approach, support for generating infinite data types (including
functions), etc. For more information on &lt;code&gt;falsify&lt;/code&gt;, see also the original blog
post that announced it, &lt;a href=&quot;https://well-typed.com/blog/2023/04/falsify/&quot;&gt;&lt;code&gt;falsify&lt;/code&gt;: Hypothesis-inspired shrinking for
Haskell&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;At QBayLogic HQ we spent the morning developing
&lt;a href=&quot;https://github.com/well-typed/mini-falsify&quot;&gt;&lt;code&gt;mini-falsify&lt;/code&gt;&lt;/a&gt; from scratch, so
that we could focus on the main ideas without getting bogged down in the details
of the full library; similar in spirit to for example
&lt;a href=&quot;https://www.well-typed.com/blog/2015/11/implementing-a-minimal-version-of-haskell-servant/&quot;&gt;&lt;code&gt;TinyServant&lt;/code&gt;&lt;/a&gt;,
or perhaps Stephen Diehl’s &lt;a href=&quot;https://sdiehl.github.io/typechecker-zoo/&quot;&gt;Typechecker
Zoo&lt;/a&gt;. In the afternoon we hacked on
&lt;code&gt;falsify&lt;/code&gt; and its application within the &lt;code&gt;clash&lt;/code&gt; ecosystem. Partly as a result
of that work and partly as a result of me taking this opportunity to do some
long overdue maintenance on &lt;code&gt;falsify&lt;/code&gt;, there is now a new falsify release:
&lt;a href=&quot;https://hackage.haskell.org/package/falsify-0.4.0&quot;&gt;&lt;code&gt;falsify-0.4.0&lt;/code&gt;&lt;/a&gt;. In the
remainder of this blog post we give a brief overview of the main changes.&lt;/p&gt;

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

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

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

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

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

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

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

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

&lt;span class=&quot;token code&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;```&lt;/span&gt;&lt;span class=&quot;token code-language&quot;&gt;rust&lt;/span&gt;
&lt;span class=&quot;token code-block language-rust&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Hello, {name}!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;```&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Overall, I believe this is a perfectly acceptable trade-off: purity and statelessness provide an elegant and robust formatting pipeline, which is not worth giving up for gaining the ability to handle fragmented constructs, which are less common.&lt;/p&gt;
&lt;p&gt;Another known limitation is that, while Tree-sitter grammars are usually flexible enough to parse individual definitions or expressions, if a grammar strictly expects a full source file and nothing less, it won’t be able to parse short injected snippets correctly. Just like with fragmented code blocks, this will result in a parsing error unless &lt;code class=&quot;language-text&quot;&gt;--tolerate-parsing-errors&lt;/code&gt; is used. Fortunately, most grammars (e.g. Java, C#, or Rust) are remarkably flexible and do not exhibit this problem.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#conclusion&quot;&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;By leveraging language injection queries and extending the core formatting API, Topiary can now cleanly format embedded code snippets without breaking the host language layout. With language injections, Topiary is no longer just formatting single syntax trees: it’s formatting forests.&lt;/p&gt;
&lt;p&gt;This feature will be included in an upcoming release. In the meantime, if you’re working with OCamllex (for which Topiary is, to my knowledge, the only complete formatter!) or writing technical Markdown documents, you can try it out today.&lt;/p&gt;
&lt;p&gt;To run it on an OCamllex file using Nix, for example, you can use:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;nix run github:topiary/topiary -- &lt;span class=&quot;token function&quot;&gt;fmt&lt;/span&gt; myfile.mll&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn-1&quot;&gt;Usually embedded language spans are already parsed as leaves by the
tree-sitter grammar itself. But they don’t have to, so enforcing that
Topiary only sees leaves no matter what the grammar says is safer.&lt;a class=&quot;footnote-backref&quot; href=&quot;https://www.tweag.io/rss.xml#fnref-1&quot;&gt;↩&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description>
	<pubDate>Thu, 09 Jul 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>in Code: Extreme Haskell: Typed Expression EDSLs (Part 1)</title>
	<guid isPermaLink="true">https://blog.jle.im/entry/extreme-haskell-typed-expression-edsls-1.html</guid>
	<link>https://blog.jle.im/entry/extreme-haskell-typed-expression-edsls-1.html</link>
	<description>&lt;p&gt;I always say, inside every Haskeller there are two wolves, living on opposite
ends of the Haskell Fancy Code Spectrum. Are you going to write “simple
Haskell”, using basic GHC 2010 tools and writing universal Haskell that every
introductory course offers, trying to keep the code as immediately
understandable and accessible? Or are you going to pile in all of the Haskell
type system and evaluation tricks you can find and turn on all the extensions,
and go full fancy?&lt;/p&gt;
&lt;p&gt;In my &lt;a href=&quot;https://blog.jle.im/entry/levels-of-type-safety-haskell-lists.html&quot;&gt;Seven
Levels of Type Safety&lt;/a&gt; post, I described different extremes of type safety
and fancy code. I talked about how writing effective code was finding the
correct compromise for the level of communication and safety you need.&lt;/p&gt;
&lt;p&gt;But this is not that kind of blog post. This is the kind of blog post where
we celebrate terrifying type-safety, facetious fanciness, and masochistic
meta-analysis. This series is about what happens when we dare to go full fancy.
Let’s write code that is so inscrutable, so painful and torturous to write, yet
so &lt;em&gt;undeniably useful&lt;/em&gt; that you can’t help but try to throw it into every
single thing you write and will feel a gnawing emptiness in your soul until you
do.&lt;/p&gt;
&lt;p&gt;As our example, let’s write a type-safe method to specify your program as a
series of states, with triggered transitions between them: a type-safe state
machine graph using a type-safe lambda calculus. We want to specify this in a
way that we can write once and then:&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;be interpretable in a type-safe way within Haskell.&lt;/li&gt;
&lt;li&gt;be inspectable with visualizable control flow.&lt;/li&gt;
&lt;li&gt;be compilable to multiple actual back-ends, letting you run the same
function under multiple implementations.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This exact thing is something I’ve needed and used multiple times now in
projects. I want to specify one program graph within Haskell, but in a way that
can compile both in C and javascript while also being visualizable and
interactively explorable.&lt;/p&gt;
&lt;p&gt;Once you go down this road, everything you ever write will feel woefully
unsafe and limited. And everything you want to write will be hopelessly
inscrutable by normal humans and borderline unusable. But such is the curse we
all bear. Turn around now, you have been warned.&lt;/p&gt;
&lt;p&gt;This post will build up the embedded typed expression language. Part 2 will
use that expression language to define typed state machines with embedded
predicates and visualize them, and Part 3 will compile those machines to
different languages and verify they execute identically, with some live
demos.&lt;/p&gt;
&lt;p&gt;All of the code here is &lt;a href=&quot;https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/flake.nix&quot;&gt;available
online&lt;/a&gt;, and if you check out the repo and run &lt;code&gt;nix develop&lt;/code&gt; you
should be able to load it all in ghci:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb1-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;$&lt;/span&gt; cd code-samples/typed-sm-lc&lt;/span&gt;
&lt;span id=&quot;cb1-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb1-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;$&lt;/span&gt; nix develop&lt;/span&gt;
&lt;span id=&quot;cb1-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb1-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;$&lt;/span&gt; ghci&lt;/span&gt;
&lt;span id=&quot;cb1-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb1-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;ghci&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; :load ExprStage1.hs&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;the-lambda-calculus&quot;&gt;The Lambda Calculus&lt;/h2&gt;
&lt;p&gt;Let’s derive a way to express an algorithm or expression in Haskell that can
be reified and analyzed within Haskell, and eventually be a form we can compile
to different backends, interpret in Haskell, or generate Graphviz visualizations
for.&lt;/p&gt;
&lt;h3 id=&quot;a-first-pass&quot;&gt;A First Pass&lt;/h3&gt;
&lt;p&gt;One basic thing we can do is start with:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb2-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage1.hs#L18-L34&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Prim&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PBool&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Bool&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PString&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Show&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb2-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Op&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OTimes&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OLte&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OAnd&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Show&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb2-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Prim&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ELambda&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EApply&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Op&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ERecord&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb2-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EAccess&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EChoice&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-18&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ECase&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb2-19&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb2-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;deriving&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Eq&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Show&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And you can write &lt;code&gt;(\x -&amp;gt; x * 3) 5&lt;/code&gt; as:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb3&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb3-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb3-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage1.hs#L36-L37&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb3-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb3-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;fifteen ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb3-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;fifteen &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ELambda&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OTimes&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;))) &lt;span class=&quot;ot&quot;&gt;`EApply`&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The strings in &lt;code&gt;ELambda&lt;/code&gt; introduce variables, and
&lt;code&gt;EVar&lt;/code&gt; refers to the bound variable. As you can see, this is…pretty
untyped. We could easily write something that is meaningless:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb4&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb4-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage1.hs#L67-L69&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;badTypeExample ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;badTypeExample &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb4-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OAnd&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;)) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Of course, GHC can typecheck our code if we literally write
&lt;code&gt;\x -&amp;gt; x + 3&lt;/code&gt; and reject &lt;code&gt;1 &amp;amp;&amp;amp; 2&lt;/code&gt;. But we
aren’t trying to build opaque Haskell code here, we’re trying to represent our
expression as an ADT that we can analyze &lt;em&gt;within&lt;/em&gt; the language.&lt;/p&gt;
&lt;p&gt;If we want a record projection and one labeled choice with a case analysis
over it:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb5&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb5-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage1.hs#L39-L62&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;recordExample ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;recordExample &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ( &lt;span class=&quot;dt&quot;&gt;EAccess&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        ( &lt;span class=&quot;dt&quot;&gt;ERecord&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            M.fromList&lt;/span&gt;
&lt;span id=&quot;cb5-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;              [ (&lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;)),&lt;/span&gt;
&lt;span id=&quot;cb5-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                (&lt;span class=&quot;st&quot;&gt;&quot;label&quot;&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PString&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;found&quot;&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb5-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;              ]&lt;/span&gt;
&lt;span id=&quot;cb5-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        )&lt;/span&gt;
&lt;span id=&quot;cb5-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    )&lt;/span&gt;
&lt;span id=&quot;cb5-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb5-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-18&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;sumExample ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-19&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sumExample &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-20&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ECase&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-21&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;dt&quot;&gt;EChoice&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;)))&lt;/span&gt;
&lt;span id=&quot;cb5-22&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ( M.fromList&lt;/span&gt;
&lt;span id=&quot;cb5-23&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        [ (&lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt;, (&lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;)))),&lt;/span&gt;
&lt;span id=&quot;cb5-24&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          (&lt;span class=&quot;st&quot;&gt;&quot;Missing&quot;&lt;/span&gt;, (&lt;span class=&quot;st&quot;&gt;&quot;message&quot;&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;)))&lt;/span&gt;
&lt;span id=&quot;cb5-25&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        ]&lt;/span&gt;
&lt;span id=&quot;cb5-26&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb5-26&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    )&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now, for the entire point of &lt;code&gt;Expr&lt;/code&gt;, we can write a function to
pretty-print it, using the &lt;em&gt;&lt;a href=&quot;https://hackage.haskell.org/package/prettyprinter&quot;&gt;prettyprinter&lt;/a&gt;&lt;/em&gt;
library:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb6&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb6-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage1.hs#L253-L299&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;ppPrim ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Prim&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id=&quot;cb6-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppPrim &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; n &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; PP.pretty n&lt;/span&gt;
&lt;span id=&quot;cb6-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;PBool&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;PBool&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;false&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;PString&lt;/span&gt; s &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; PP.pretty (&lt;span class=&quot;fu&quot;&gt;show&lt;/span&gt; s)&lt;/span&gt;
&lt;span id=&quot;cb6-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;ppOp ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Op&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id=&quot;cb6-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppOp &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;+&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OTimes&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OLte&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&amp;lt;=&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OAnd&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&amp;amp;&amp;amp;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;ppExpr ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Bool&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id=&quot;cb6-18&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppExpr paren &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-19&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; p &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; ppPrim p&lt;/span&gt;
&lt;span id=&quot;cb6-20&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; v &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; PP.pretty v&lt;/span&gt;
&lt;span id=&quot;cb6-21&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ELambda&lt;/span&gt; n body &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-22&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    wrap &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;\\&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; PP.pretty n &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;-&amp;gt;&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt; body&lt;/span&gt;
&lt;span id=&quot;cb6-23&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EApply&lt;/span&gt; f x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-24&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    wrap &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; f &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; x&lt;/span&gt;
&lt;span id=&quot;cb6-25&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; o x y &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-26&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-26&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    wrap &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; x &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppOp o &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; y&lt;/span&gt;
&lt;span id=&quot;cb6-27&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-27&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ERecord&lt;/span&gt; xs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-28&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-28&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    PP.encloseSep &lt;span class=&quot;st&quot;&gt;&quot;{ &quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot; }&quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;, &quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-29&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-29&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      [PP.pretty k &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;=&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt; v &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; (k, v) &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; M.toList xs]&lt;/span&gt;
&lt;span id=&quot;cb6-30&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-30&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EAccess&lt;/span&gt; e k &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-31&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-31&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ppExpr &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; e &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;.&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; PP.pretty k&lt;/span&gt;
&lt;span id=&quot;cb6-32&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-32&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EChoice&lt;/span&gt; tag x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-33&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-33&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    wrap &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; PP.pretty tag &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; x&lt;/span&gt;
&lt;span id=&quot;cb6-34&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-34&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ECase&lt;/span&gt; x hs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-35&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-35&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    wrap &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-36&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-36&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      PP.sep&lt;/span&gt;
&lt;span id=&quot;cb6-37&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-37&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        [ &lt;span class=&quot;st&quot;&gt;&quot;case&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt; x &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;of&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-38&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-38&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        , PP.encloseSep &lt;span class=&quot;st&quot;&gt;&quot;{ &quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot; }&quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;; &quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-39&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-39&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            [ PP.pretty tag &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; PP.pretty n &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;-&amp;gt;&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt; body&lt;/span&gt;
&lt;span id=&quot;cb6-40&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-40&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; (tag, (n, body)) &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; M.toList hs&lt;/span&gt;
&lt;span id=&quot;cb6-41&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-41&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            ]&lt;/span&gt;
&lt;span id=&quot;cb6-42&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-42&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        ]&lt;/span&gt;
&lt;span id=&quot;cb6-43&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-43&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-44&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-44&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    wrap&lt;/span&gt;
&lt;span id=&quot;cb6-45&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-45&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; paren &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; PP.parens&lt;/span&gt;
&lt;span id=&quot;cb6-46&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-46&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;otherwise&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;id&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-47&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-47&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-48&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-48&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;prettyExpr ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id=&quot;cb6-49&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb6-49&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;prettyExpr &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb7&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb7-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb7-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; prettyExpr fifteen&lt;/span&gt;
&lt;span id=&quot;cb7-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb7-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;(\x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; x &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;) &lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb7-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; prettyExpr badTypeExample&lt;/span&gt;
&lt;span id=&quot;cb7-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb7-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb7-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; prettyExpr recordExample&lt;/span&gt;
&lt;span id=&quot;cb7-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb7-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;{ label &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;found&quot;&lt;/span&gt;, value &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt; }&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;value &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb7-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; prettyExpr sumExample&lt;/span&gt;
&lt;span id=&quot;cb7-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb7-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Found&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt; { &lt;span class=&quot;dt&quot;&gt;Found&lt;/span&gt; value &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; value &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;; &lt;span class=&quot;dt&quot;&gt;Missing&lt;/span&gt; message &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now, we can write a quick typechecker for this using a greedy type-checking
algorithm (&lt;a href=&quot;https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage1.hs#L77-L89&quot;&gt;written
out here&lt;/a&gt;), which is a fun exercise, but it’s beyond the point of this post.
For our purposes, we’re going to write the in-Haskell evaluator, which is one
sure-fire evidential/constructive way to prove an expression was valid
after-the-fact.&lt;/p&gt;
&lt;p&gt;So…how can you “evaluate” this to 15, within Haskell? What would the type
even be? The best we can do at this point is make the entire thing monadic by
returning &lt;code&gt;Maybe&lt;/code&gt; or &lt;code&gt;Either&lt;/code&gt;, and split out the
expressions we write from the values we can actually evaluate to:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb8&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb8-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage1.hs#L228-L330&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Bool&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVString&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVFun&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb8-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVRecord&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb8-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVChoice&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;eval ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;eval env &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; p &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; evalPrim p&lt;/span&gt;
&lt;span id=&quot;cb8-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; v &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; M.lookup v env&lt;/span&gt;
&lt;span id=&quot;cb8-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ELambda&lt;/span&gt; n body &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVFun&lt;/span&gt; (\x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; eval (M.insert n x env) body))&lt;/span&gt;
&lt;span id=&quot;cb8-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EApply&lt;/span&gt; f x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; eval env f &lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVFun&lt;/span&gt; f' &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; eval env x &lt;span class=&quot;op&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; f'&lt;/span&gt;
&lt;span id=&quot;cb8-18&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    _ &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-19&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; o x y &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-20&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    u &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id=&quot;cb8-21&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    v &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env y&lt;/span&gt;
&lt;span id=&quot;cb8-22&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; (u, v) &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-23&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      (&lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; a, &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; b) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; o &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-24&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; b))&lt;/span&gt;
&lt;span id=&quot;cb8-25&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;dt&quot;&gt;OTimes&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; b))&lt;/span&gt;
&lt;span id=&quot;cb8-26&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-26&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;dt&quot;&gt;OLte&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;&amp;lt;=&lt;/span&gt; b))&lt;/span&gt;
&lt;span id=&quot;cb8-27&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-27&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;dt&quot;&gt;OAnd&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-28&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-28&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      (&lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; a, &lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; b) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; o &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-29&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-29&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;dt&quot;&gt;OAnd&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; b))&lt;/span&gt;
&lt;span id=&quot;cb8-30&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-30&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        _ &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-31&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-31&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      _ &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-32&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-32&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ERecord&lt;/span&gt; xs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVRecord&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;traverse&lt;/span&gt; (eval env) xs&lt;/span&gt;
&lt;span id=&quot;cb8-33&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-33&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EAccess&lt;/span&gt; e k &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-34&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-34&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVRecord&lt;/span&gt; xs &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env e&lt;/span&gt;
&lt;span id=&quot;cb8-35&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-35&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    M.lookup k xs&lt;/span&gt;
&lt;span id=&quot;cb8-36&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-36&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EChoice&lt;/span&gt; tag x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVChoice&lt;/span&gt; tag &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id=&quot;cb8-37&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-37&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ECase&lt;/span&gt; x hs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-38&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-38&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVChoice&lt;/span&gt; tag payload &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id=&quot;cb8-39&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-39&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (n, body) &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; M.lookup tag hs&lt;/span&gt;
&lt;span id=&quot;cb8-40&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb8-40&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    eval (M.insert n payload env) body&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This would properly evaluate:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb9&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb9-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb9-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; eval M.empty fifteen&lt;/span&gt;
&lt;span id=&quot;cb9-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb9-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;15&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can also produce closures as values:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb10&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb10-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb10-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage1.hs#L64-L65&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb10-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb10-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;plusThree ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb10-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;plusThree &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ELambda&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;)))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb11&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb11-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb11-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; for_ (eval M.empty plusThree) \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb11-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVFun&lt;/span&gt; f &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;print&lt;/span&gt; (f (&lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb11-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb11-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    _ &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;putStrLn&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;not a function&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb11-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This kind of works if you remember to thread everything through
&lt;code&gt;Maybe&lt;/code&gt; (or &lt;code&gt;Either&lt;/code&gt;) or what have you. But this is not
ideal. You should be able to know, at compile-time, that your &lt;code&gt;Expr&lt;/code&gt;
is valid. After all, you want to be able to create one “valid”
&lt;code&gt;Expr&lt;/code&gt;, and run it at every context. It’s useless to you if every
single time you used an &lt;code&gt;Expr&lt;/code&gt;, you had to manually handle the
&lt;code&gt;Nothing&lt;/code&gt; case. Your diagram generator, your Haskell runner, your
code generator, will always be in &lt;code&gt;Either&lt;/code&gt; even though you know your
&lt;code&gt;Expr&lt;/code&gt; is valid, via tests or something. We want GHC to reject badly
typed expressions, so we never need to unwrap or handle a &lt;code&gt;Nothing&lt;/code&gt;
or &lt;code&gt;Left&lt;/code&gt;!&lt;/p&gt;
&lt;p&gt;No, no, this is not okay and not acceptable. We should be able to verify in
the types if an &lt;code&gt;Expr&lt;/code&gt; is valid.&lt;/p&gt;
&lt;h2 id=&quot;type-indexed-expressions&quot;&gt;Type-Indexed Expressions&lt;/h2&gt;
&lt;h3 id=&quot;just-add-the-index&quot;&gt;Just Add the Index&lt;/h3&gt;
&lt;p&gt;The next step you’ll see in posts online is to add a phantom index type to
&lt;code&gt;Expr&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb12&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb12-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage2.hs#L19-L49&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TBool&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Prim&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Prim&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;PBool&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Bool&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Prim&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TBool&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;PString&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Prim&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Op&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Op&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OTimes&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Op&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OLte&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Op&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TBool&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-18&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OAnd&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Op&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TBool&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TBool&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TBool&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-19&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-20&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-21&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Prim&lt;/span&gt; t &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; t&lt;/span&gt;
&lt;span id=&quot;cb12-22&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; t &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; t&lt;/span&gt;
&lt;span id=&quot;cb12-23&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ELambda&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;:-&amp;gt;&lt;/span&gt; b)&lt;/span&gt;
&lt;span id=&quot;cb12-24&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EApply&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;:-&amp;gt;&lt;/span&gt; b) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; b&lt;/span&gt;
&lt;span id=&quot;cb12-25&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb12-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Op&lt;/span&gt; a b c &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; c&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(We’ll explain each part of this declaration eventually)&lt;/p&gt;
&lt;p&gt;A phantom type is a type parameter that doesn’t represent any actual
&lt;em&gt;value&lt;/em&gt; “contained” inside the data type, but just serves to “tag” or
distinguish values for the compiler to reject or unify things in useful
ways.&lt;/p&gt;
&lt;p&gt;This introduces several new language features, so bear with me as I break
them down.&lt;/p&gt;
&lt;p&gt;First, we use &lt;code&gt;-XTypeData&lt;/code&gt; to define a data kind: &lt;code&gt;Ty&lt;/code&gt;
is a kind with types &lt;code&gt;TInt :: Ty&lt;/code&gt;, &lt;code&gt;TBool :: Ty&lt;/code&gt;, etc. And
in &lt;code&gt;Expr t&lt;/code&gt;, we have an expression tagged with &lt;code&gt;t&lt;/code&gt;, which
describes the result type. (In fact, &lt;em&gt;all&lt;/em&gt; data types are automatically
promoted to the type level with &lt;code&gt;-XDataKinds&lt;/code&gt;. You might see the
&lt;code&gt;'Nothing&lt;/code&gt; quote prefix syntax in cases where it’s ambiguous if
you’re talking about the data constructor or the type constructor, like
&lt;code&gt;'[]&lt;/code&gt; and &lt;code&gt;'(,)&lt;/code&gt;)&lt;/p&gt;
&lt;p&gt;For example, because we have &lt;code&gt;EPrim :: Prim t -&amp;gt; Expr t&lt;/code&gt;, and
&lt;code&gt;PInt 3 :: Prim TInt&lt;/code&gt;, we have
&lt;code&gt;EPrim (PInt 3) :: Expr TInt&lt;/code&gt;: a primitive 3 is an expression
describing an integer.&lt;/p&gt;
&lt;p&gt;And because
&lt;code&gt;EOp :: Op a b c -&amp;gt; Expr a -&amp;gt; Expr b -&amp;gt; Expr c&lt;/code&gt;, and
&lt;code&gt;OLte :: Op TInt TInt TBool&lt;/code&gt;, we have&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb13&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb13-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb13-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OLte&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TBool&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So we can write an operation on two &lt;code&gt;Expr&lt;/code&gt;s that typecheck how
we’d expect:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb14&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb14-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb14-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;t &lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OLte&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;)) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb14-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb14-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TBool&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We also have
&lt;code&gt;EOp OAnd :: Expr TBool -&amp;gt; Expr TBool -&amp;gt; Expr TBool&lt;/code&gt;, which
means the compiler will reject our previous &lt;code&gt;1 &amp;amp;&amp;amp; 2&lt;/code&gt;
example:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb15&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb15-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb15-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;t &lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OAnd&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;)) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb15-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb15-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;interactive&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb15-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb15-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    • &lt;span class=&quot;dt&quot;&gt;Couldn't&lt;/span&gt; match &lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; ‘&lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;’ with ‘&lt;span class=&quot;dt&quot;&gt;TBool&lt;/span&gt;’&lt;/span&gt;
&lt;span id=&quot;cb15-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb15-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;Expected&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Prim&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TBool&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb15-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb15-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;dt&quot;&gt;Actual&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Prim&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can write lambdas in this system too:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb16&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb16-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb16-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage2.hs#L51-L55&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb16-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb16-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;fifteen ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb16-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;fifteen &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb16-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EApply&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb16-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb16-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;dt&quot;&gt;ELambda&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OTimes&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;))))&lt;/span&gt;
&lt;span id=&quot;cb16-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb16-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Because of &lt;code&gt;Ty&lt;/code&gt;, we can also make a new indexed data type with
phantoms of “fully resolved” values:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb17&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb17-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb17-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage2.hs#L115-L119&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb17-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb17-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb17-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb17-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Bool&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TBool&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb17-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVString&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb17-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVFun&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; b)) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;:-&amp;gt;&lt;/span&gt; b)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is what we want to eventually &lt;code&gt;eval&lt;/code&gt; into, as we can
guarantee ourselves to get a value of the correct type based on the
&lt;code&gt;Ty&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb18&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb18-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb18-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;eValueToInt ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb18-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb18-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;eValueToInt &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb18-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb18-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; x&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And GHC will verify this as a total pattern match because &lt;code&gt;EVInt&lt;/code&gt;
is the only possible way to create an &lt;code&gt;EValue TInt&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;singletons-and-existentials&quot;&gt;Singletons and Existentials&lt;/h3&gt;
&lt;p&gt;We’ll keep our bound variables stored as an ambient map of variable names to
their evaluated values for now. But, to do this, we need to turn the
heterogeneous &lt;code&gt;EValue t&lt;/code&gt; into the homogeneous
&lt;code&gt;Map String SomeValue&lt;/code&gt; by wrapping the type variable as an
existential type.&lt;/p&gt;
&lt;p&gt;You might notice we have a &lt;a href=&quot;https://blog.jle.im/entries/series/+introduction-to-singletons.html&quot;&gt;singleton&lt;/a&gt;
for our &lt;code&gt;Ty&lt;/code&gt; type, &lt;code&gt;STy&lt;/code&gt;, that pops up in multiple
situations.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb19&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb19-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb19-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage2.hs#L27-L31&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb19-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb19-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb19-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb19-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STBool&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TBool&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb19-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STString&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb19-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STFun&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;:-&amp;gt;&lt;/span&gt; b)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Firstly, it might help to recognize the general pattern where
&lt;code&gt;STy&lt;/code&gt; (the singleton) appears. It &lt;em&gt;usually&lt;/em&gt; pops up whenever
we have existentially scoped variables, like in
&lt;code&gt;data SomeValue = forall t. SomeValue (STy t) (EValue t)&lt;/code&gt;. In this
case, the &lt;code&gt;t&lt;/code&gt; is completely lost to the outside world, and
&lt;code&gt;STy t&lt;/code&gt; is used to allow us to recover a runtime witness to what
&lt;code&gt;t&lt;/code&gt; was, after pattern matching on &lt;code&gt;STy&lt;/code&gt;. This is the
&lt;em&gt;dependent sum&lt;/em&gt; pattern, and is similar to how &lt;code&gt;Typeable&lt;/code&gt; is
used in &lt;em&gt;Data.Dynamic&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;In our case, because variables are still stored ambiently in the environment
and validated at runtime, we &lt;em&gt;do&lt;/em&gt; need singletons to implement
&lt;code&gt;eval&lt;/code&gt; . The type &lt;code&gt;Expr t&lt;/code&gt; only specifies the type of the
result, but the type information of the ambient variables is not available. So,
you can write &lt;code&gt;EVar STInt &quot;myVar&quot; :: Expr TInt&lt;/code&gt;, but:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;myVar&lt;/code&gt; might not be a variable in scope at all, so
&lt;code&gt;eval&lt;/code&gt; will fail at runtime&lt;/li&gt;
&lt;li&gt;&lt;code&gt;myVar&lt;/code&gt; might be in scope, but might be a &lt;code&gt;TString&lt;/code&gt;
and not a &lt;code&gt;TInt&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first case is easy enough to deal with (&lt;code&gt;M.lookup&lt;/code&gt; returns
&lt;code&gt;Nothing&lt;/code&gt;), but the second one is a little more subtle. Let’s say we
&lt;em&gt;do&lt;/em&gt; have a &lt;code&gt;SomeValue&lt;/code&gt; under our key &lt;code&gt;myVar&lt;/code&gt;…how
do we make sure it has the correct type?&lt;/p&gt;
&lt;h3 id=&quot;runtime-type-equality&quot;&gt;Runtime Type Equality&lt;/h3&gt;
&lt;p&gt;We can do ad-hoc pattern matching on &lt;code&gt;EValue&lt;/code&gt;, but that won’t get
us too far. Mostly because some of the &lt;code&gt;EValue&lt;/code&gt; constructors actually
don’t have enough information for us to validate their actual type (try it!
&lt;code&gt;EVFun&lt;/code&gt; will give you a lot of trouble). So, what we can do is write
a function that takes two &lt;code&gt;STy&lt;/code&gt; at runtime and &lt;em&gt;unifies&lt;/em&gt; them
conditionally if they are the same. We’ll write a function
&lt;code&gt;sameTy :: STy a -&amp;gt; STy b -&amp;gt; Maybe (a :~: b)&lt;/code&gt;, where&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb20&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb20-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb20-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; (:~:) ::&lt;/span&gt; k &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; k &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb20-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; a &lt;span class=&quot;op&quot;&gt;:~:&lt;/span&gt; a&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;pattern matching&lt;/em&gt; on a value of type &lt;code&gt;a :~: b&lt;/code&gt; will reveal
that &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; are the same type variable, because the
only way to construct it is with &lt;code&gt;Refl :: a :~: a&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;With that, we can write &lt;code&gt;sameTy&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb21&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb21-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage2.hs#L133-L143&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;sameTy ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;:~:&lt;/span&gt; b)&lt;/span&gt;
&lt;span id=&quot;cb21-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sameTy &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt;; _ &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STBool&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STBool&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt;; _ &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STString&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STString&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt;; _ &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STFun&lt;/span&gt; a b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;STFun&lt;/span&gt; c d &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; sameTy a c&lt;/span&gt;
&lt;span id=&quot;cb21-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; sameTy b d&lt;/span&gt;
&lt;span id=&quot;cb21-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb21-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    _ &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There’s a typeclass in &lt;em&gt;base&lt;/em&gt; (or rather, a “kindclass”),
&lt;code&gt;TestEquality&lt;/code&gt;, that encapsulates this pattern:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb22&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb22-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb22-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TestEquality&lt;/span&gt; f &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb22-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb22-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;    testEquality ::&lt;/span&gt; f a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; f b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;:~:&lt;/span&gt; b)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In fact, we can write our &lt;code&gt;sameTy&lt;/code&gt; as an instance:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb23&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb23-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb23-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage2.hs#L130-L131&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb23-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb23-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb23-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb23-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TestEquality&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb23-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb23-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  testEquality &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sameTy&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We’re now at a higher fanciness level than before. But you might see the
problem here: &lt;code&gt;EVar STInt &quot;x&quot;&lt;/code&gt;. &lt;code&gt;x&lt;/code&gt; might not be defined,
and it also might not have the correct type. Soooo yes, we still have issues
here.&lt;/p&gt;
&lt;p&gt;But now at least we can write &lt;code&gt;eval&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb24&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb24-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage2.hs#L145-L176&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;eval ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;SomeValue&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; t &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; t)&lt;/span&gt;
&lt;span id=&quot;cb24-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;eval env &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; n) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; n)&lt;/span&gt;
&lt;span id=&quot;cb24-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PBool&lt;/span&gt; b) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; b)&lt;/span&gt;
&lt;span id=&quot;cb24-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PString&lt;/span&gt; s) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVString&lt;/span&gt; s)&lt;/span&gt;
&lt;span id=&quot;cb24-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; t v &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;SomeValue&lt;/span&gt; t' v' &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; M.lookup v env&lt;/span&gt;
&lt;span id=&quot;cb24-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; sameTy t t'&lt;/span&gt;
&lt;span id=&quot;cb24-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; v'&lt;/span&gt;
&lt;span id=&quot;cb24-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ELambda&lt;/span&gt; ta n body &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVFun&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; \x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; eval (M.insert n (&lt;span class=&quot;dt&quot;&gt;SomeValue&lt;/span&gt; ta x) env) body&lt;/span&gt;
&lt;span id=&quot;cb24-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EApply&lt;/span&gt; f x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVFun&lt;/span&gt; g &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env f&lt;/span&gt;
&lt;span id=&quot;cb24-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    x' &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id=&quot;cb24-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    g x'&lt;/span&gt;
&lt;span id=&quot;cb24-18&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; o x y &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; o &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-19&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-20&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id=&quot;cb24-21&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env y&lt;/span&gt;
&lt;span id=&quot;cb24-22&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; b))&lt;/span&gt;
&lt;span id=&quot;cb24-23&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;OTimes&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-24&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id=&quot;cb24-25&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env y&lt;/span&gt;
&lt;span id=&quot;cb24-26&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-26&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; b))&lt;/span&gt;
&lt;span id=&quot;cb24-27&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-27&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;OLte&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-28&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-28&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id=&quot;cb24-29&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-29&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env y&lt;/span&gt;
&lt;span id=&quot;cb24-30&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-30&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;&amp;lt;=&lt;/span&gt; b))&lt;/span&gt;
&lt;span id=&quot;cb24-31&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-31&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;OAnd&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-32&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-32&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id=&quot;cb24-33&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-33&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env y&lt;/span&gt;
&lt;span id=&quot;cb24-34&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb24-34&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; b))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This does seem to work:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb25&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb25-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb25-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; for_ (eval M.empty fifteen) \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb25-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb25-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;print&lt;/span&gt; x&lt;/span&gt;
&lt;span id=&quot;cb25-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb25-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dv&quot;&gt;15&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Our system also allows us to produce closures and functions as values:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb26&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb26-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb26-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage2.hs#L63-L64&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb26-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb26-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb26-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb26-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;plusThree ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb26-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb26-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;plusThree &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ELambda&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;)))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb27&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb27-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb27-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; for_ (eval M.empty plusThree) \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb27-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb27-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVFun&lt;/span&gt; f &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; for_ (f (&lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;)) \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb27-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb27-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;print&lt;/span&gt; x    &lt;span class=&quot;co&quot;&gt;-- compiler-verified to always be EVInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb27-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb27-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We have a type-safe &lt;code&gt;eval&lt;/code&gt; now that will create a value of the
type we want. But we still have the same errors when looking at variables:
variables can still not be defined, or be defined as the wrong type.&lt;/p&gt;
&lt;h3 id=&quot;pretty-printing&quot;&gt;Pretty-Printing&lt;/h3&gt;
&lt;p&gt;One nice consequence of this type-index method is that if you choose to
consume them into an untyped target, you can do it more or less in the same way
as the non-indexed untyped data.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb28&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb28-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage2.hs#L87-L113&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;ppPrim ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Prim&lt;/span&gt; t &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id=&quot;cb28-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppPrim &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; n &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; PP.pretty n&lt;/span&gt;
&lt;span id=&quot;cb28-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;PBool&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;if&lt;/span&gt; b &lt;span class=&quot;kw&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;true&quot;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;false&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;PString&lt;/span&gt; s &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; PP.pretty (&lt;span class=&quot;fu&quot;&gt;show&lt;/span&gt; s)&lt;/span&gt;
&lt;span id=&quot;cb28-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;ppOp ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Op&lt;/span&gt; a b c &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id=&quot;cb28-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppOp &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;+&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OTimes&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OLte&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&amp;lt;=&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OAnd&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&amp;amp;&amp;amp;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;ppExpr ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Bool&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; t &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id=&quot;cb28-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppExpr paren &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-18&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; p &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; ppPrim p&lt;/span&gt;
&lt;span id=&quot;cb28-19&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; _ v &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; PP.pretty v&lt;/span&gt;
&lt;span id=&quot;cb28-20&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ELambda&lt;/span&gt; _ n body &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; wrap &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;\\&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; PP.pretty n &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;-&amp;gt;&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt; body&lt;/span&gt;
&lt;span id=&quot;cb28-21&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EApply&lt;/span&gt; f x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; wrap &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; f &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; x&lt;/span&gt;
&lt;span id=&quot;cb28-22&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; o x y &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; wrap &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; x &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppOp o &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; y&lt;/span&gt;
&lt;span id=&quot;cb28-23&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-24&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    wrap&lt;/span&gt;
&lt;span id=&quot;cb28-25&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; paren &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; PP.parens&lt;/span&gt;
&lt;span id=&quot;cb28-26&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-26&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;otherwise&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;id&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-27&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-27&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-28&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-28&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;prettyExpr ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; t &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id=&quot;cb28-29&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb28-29&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;prettyExpr &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And they render the same way:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb29&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb29-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb29-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; prettyExpr fifteen&lt;/span&gt;
&lt;span id=&quot;cb29-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb29-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;(\x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; x &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;) &lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb29-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb29-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; prettyExpr plusThree&lt;/span&gt;
&lt;span id=&quot;cb29-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb29-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;\x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; x &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb29-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb29-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; prettyExpr badVariable&lt;/span&gt;
&lt;span id=&quot;cb29-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb29-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;(\x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; x &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;) true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;still-not-fully-verified&quot;&gt;Still Not Fully Verified&lt;/h3&gt;
&lt;p&gt;Implicit in the previous section was the admission of failure: this system
lets us use indexed types to help propagate unification (the result types of
&lt;code&gt;OLte&lt;/code&gt;, &lt;code&gt;OAnd&lt;/code&gt;, &lt;code&gt;OPlus&lt;/code&gt;, etc.), but it can’t
prevent all ill-defined programs from compiling.&lt;/p&gt;
&lt;p&gt;The issue is &lt;code&gt;EVar&lt;/code&gt;: its type
&lt;code&gt;EVar :: STy t -&amp;gt; String -&amp;gt; Expr t&lt;/code&gt; lets us bind &lt;em&gt;any&lt;/em&gt;
variable name as &lt;em&gt;any&lt;/em&gt; type, and it’ll still typecheck. Even with the
help of everything we have, we can just straight-up declare a reference to an
unbound variable&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb30&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb30-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb30-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage2.hs#L71-L72&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb30-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb30-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb30-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb30-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;unboundVariable ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb30-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb30-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;unboundVariable &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;missing&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This typechecks in GHC even though it’s meaningless in the domain. We can
also reference the variable under any &lt;em&gt;type&lt;/em&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb31&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb31-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb31-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage2.hs#L57-L61&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb31-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb31-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb31-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb31-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;badVariable ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb31-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb31-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;badVariable &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb31-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb31-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EApply&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb31-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb31-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;dt&quot;&gt;ELambda&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STBool&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;))))&lt;/span&gt;
&lt;span id=&quot;cb31-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb31-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PBool&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That’s because &lt;code&gt;EVar&lt;/code&gt; can freely take any &lt;code&gt;STy&lt;/code&gt; without
any restriction, and no association with the binder name, so there’s no way for
GHC to stop us.&lt;/p&gt;
&lt;p&gt;So, again, we cannot create a &lt;em&gt;fully&lt;/em&gt; type-checked &lt;code&gt;Expr&lt;/code&gt;.
We still have to deal with &lt;em&gt;most&lt;/em&gt; of the same errors. This is noble, but
clearly not good enough. We have to go deeper.&lt;/p&gt;
&lt;h2 id=&quot;typed-records-and-sums&quot;&gt;Typed Records and Sums&lt;/h2&gt;
&lt;p&gt;A quick detour: you might have noticed that this past implementation dropped
records and sums. Before we move on, let’s go ahead and add those. Introducing
records and sums at the same time as type-indexed &lt;code&gt;Expr&lt;/code&gt; is a bit
&lt;em&gt;too&lt;/em&gt; much of a jump to fit into a single section.&lt;/p&gt;
&lt;p&gt;Let’s add sums and records, which can use pretty similar mechanisms (via
duality) for implementation.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb32&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb32-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb32-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L31-L79&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb32-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb32-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb32-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb32-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TBool&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb32-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb32-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TRecord&lt;/span&gt; [(&lt;span class=&quot;dt&quot;&gt;Symbol&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt;)]&lt;/span&gt;
&lt;span id=&quot;cb32-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb32-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TSum&lt;/span&gt; [(&lt;span class=&quot;dt&quot;&gt;Symbol&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt;)]&lt;/span&gt;
&lt;span id=&quot;cb32-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb32-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb32-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb32-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb32-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb32-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STBool&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TBool&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb32-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STString&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb32-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STRecord&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STyField&lt;/span&gt; as &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;TRecord&lt;/span&gt; as)&lt;/span&gt;
&lt;span id=&quot;cb32-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb32-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STSum&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STyField&lt;/span&gt; as &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;TSum&lt;/span&gt; as)&lt;/span&gt;
&lt;span id=&quot;cb32-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb32-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STFun&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;:-&amp;gt;&lt;/span&gt; b)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;Ty&lt;/code&gt; now includes &lt;code&gt;TRecord [(Symbol, Ty)]&lt;/code&gt; and
&lt;code&gt;TSum [(Symbol, Ty)]&lt;/code&gt;, which represent the field names and
constructor payloads (&lt;code&gt;Symbol&lt;/code&gt; being a type-level string). So, for
example, &lt;code&gt;TRecord [&quot;value&quot; ::: TInt, &quot;label&quot; ::: TString]&lt;/code&gt; would be
the type of a record with ordered fields &lt;code&gt;value&lt;/code&gt; and
&lt;code&gt;label&lt;/code&gt; of integers and strings, respectively.
&lt;code&gt;TSum [&quot;Found&quot; ::: TInt, &quot;Missing&quot; ::: TString]&lt;/code&gt; would be the type of
a sum between &lt;code&gt;Found&lt;/code&gt; containing an integer and &lt;code&gt;Missing&lt;/code&gt;
containing a string. Note we take a page out of &lt;a href=&quot;https://hackage.haskell.org/package/vinyl&quot;&gt;vinyl&lt;/a&gt; by defining the type
alias &lt;code&gt;(:::) = '(,)&lt;/code&gt; to make things syntactically nicer.&lt;/p&gt;
&lt;h3 id=&quot;record-access&quot;&gt;Record Access&lt;/h3&gt;
&lt;p&gt;We need the fields and types at the type level because we have to answer what
the &lt;code&gt;Expr&lt;/code&gt; phantom type of field access is. If we had an
&lt;code&gt;x :: Expr (TRecord [&quot;value&quot; ::: TInt, &quot;label&quot; ::: TString])&lt;/code&gt;, we
want the type of &lt;code&gt;x.value&lt;/code&gt; to be &lt;code&gt;Expr TInt&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To do this, we need to have a &lt;em&gt;value&lt;/em&gt; in our &lt;code&gt;Expr&lt;/code&gt; for
field access that can “point” at a specific field in the type. One way to do
that is to take a field of type &lt;code&gt;Index&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb33&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb33-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb33-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L47-L49&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb33-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb33-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; [k] &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; k &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb33-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;IZ&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; (x &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; xs) x&lt;/span&gt;
&lt;span id=&quot;cb33-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb33-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;IS&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; xs x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; (y &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; xs) x&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can read this as: “&lt;code&gt;IZ&lt;/code&gt; is an index to the head of the
type-level list, and &lt;code&gt;IS n&lt;/code&gt; is an index to the n-th item of the
tail”. So, &lt;code&gt;IS IZ&lt;/code&gt; is an index into the second element,
&lt;code&gt;IS (IS IZ)&lt;/code&gt; is an index into the third, etc.&lt;/p&gt;
&lt;p&gt;If we have &lt;code&gt;[&quot;value&quot; ::: TInt, &quot;label&quot; ::: TString]&lt;/code&gt;, then we have
values:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb34&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb34-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb34-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;IZ&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;    ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; [&lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&quot;label&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;] (&lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb34-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb34-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IZ&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; [&lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&quot;label&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;] (&lt;span class=&quot;st&quot;&gt;&quot;label&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note that the way this is constructed, it’s impossible for
&lt;code&gt;IS (IS IZ) :: Index [&quot;value&quot; ::: TInt, &quot;label&quot; ::: TString] _&lt;/code&gt; to
typecheck as anything!&lt;/p&gt;
&lt;p&gt;In this way, we have a well-typed field accessor syntax, which takes an
&lt;code&gt;Expr&lt;/code&gt; of a record of fields and indexes it to get an
&lt;code&gt;Expr&lt;/code&gt; of the type at that index:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb35&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb35-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb35-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L105-L105&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb35-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb35-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb35-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb35-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EAccess&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; l &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;TRecord&lt;/span&gt; as) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; as (l &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; a&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Which is typed as:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb36&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb36-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb36-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;(&lt;span class=&quot;ot&quot;&gt;`EAccess`&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IZ&lt;/span&gt;)&lt;span class=&quot;ot&quot;&gt;    ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;TRecord&lt;/span&gt; [&lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&quot;label&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;]) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb36-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb36-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;(&lt;span class=&quot;ot&quot;&gt;`EAccess`&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IZ&lt;/span&gt;)&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;TRecord&lt;/span&gt; [&lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&quot;label&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;]) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To &lt;em&gt;create&lt;/em&gt; an &lt;code&gt;Expr&lt;/code&gt; of a record, we can use
&lt;code&gt;Rec&lt;/code&gt; from &lt;em&gt;&lt;a href=&quot;https://hackage.haskell.org/package/vinyl&quot;&gt;vinyl&lt;/a&gt;&lt;/em&gt; or
&lt;code&gt;NP&lt;/code&gt; from &lt;em&gt;&lt;a href=&quot;https://hackage.haskell.org/package/sop-core&quot;&gt;sop-core&lt;/a&gt;&lt;/em&gt;: a
heterogeneous list indexed by a type-level list.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb37&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb37-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb37-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L43-L45&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb37-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb37-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb37-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb37-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; (k &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Type&lt;/span&gt;) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; [k] &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb37-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb37-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; f '[]&lt;/span&gt;
&lt;span id=&quot;cb37-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb37-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;  (:&amp;amp;) ::&lt;/span&gt; f x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; f xs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; f (x &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; xs)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you haven’t seen &lt;code&gt;Rec&lt;/code&gt; before, basically
&lt;code&gt;Rec f [a,b,c]&lt;/code&gt; is a tuple of &lt;code&gt;f a&lt;/code&gt;, &lt;code&gt;f b&lt;/code&gt;, and
&lt;code&gt;f c&lt;/code&gt;. For example:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb38&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb38-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb38-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;t &lt;span class=&quot;dt&quot;&gt;Identity&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Identity&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Identity&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;hello&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb38-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb38-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Identity&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Bool&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;]&lt;/span&gt;
&lt;span id=&quot;cb38-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb38-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;t &lt;span class=&quot;dt&quot;&gt;Const&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Const&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;y&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb38-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb38-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Const&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt;) [x1, x2]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Keeping &lt;code&gt;Rec f as&lt;/code&gt; instead of a direct heterogeneous list of
&lt;code&gt;a&lt;/code&gt;s lets us store more interesting things than just
&lt;code&gt;Type&lt;/code&gt;-kinded things. For example, since our lists here are lists of
&lt;code&gt;(Symbol, Ty)&lt;/code&gt;, we can create a container to hold fields:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb39&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb39-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb39-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L109-L110&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb39-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb39-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb39-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb39-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ExprField&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Symbol&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt;) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb39-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb39-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EField&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; l &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ExprField&lt;/span&gt; (l &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The field constructor keeps a &lt;code&gt;KnownSymbol l&lt;/code&gt; constraint, so the
type-level label is still available later when we need to render it:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb40&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb40-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb40-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;t &lt;span class=&quot;dt&quot;&gt;EField&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb40-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb40-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EField&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;label&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PString&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;found&quot;&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb40-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb40-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb40-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb40-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ExprField&lt;/span&gt; [&lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&quot;label&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So, we can create
&lt;code&gt;Expr (TRecord [&quot;value&quot; ::: TInt, &quot;label&quot; ::: TString])&lt;/code&gt; by taking a
&lt;code&gt;Rec&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb41&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb41-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb41-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L104-L104&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb41-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb41-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb41-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb41-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ERecord&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ExprField&lt;/span&gt; as &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;TRecord&lt;/span&gt; as)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can make this a little more ergonomic by using
&lt;code&gt;-XRequiredTypeArguments&lt;/code&gt; (as of GHC 9.10) to get rid of the
&lt;code&gt;-XTypeApplication&lt;/code&gt; ugliness:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb42&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb42-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb42-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L115-L150&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb42-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb42-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb42-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb42-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;eField ::&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;forall&lt;/span&gt; l &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; l &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ExprField&lt;/span&gt; (l &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a)&lt;/span&gt;
&lt;span id=&quot;cb42-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb42-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;eField l &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EField&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l&lt;/span&gt;
&lt;span id=&quot;cb42-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb42-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb42-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb42-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;makeRecordExample ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;TRecord&lt;/span&gt; [&lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&quot;label&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;])&lt;/span&gt;
&lt;span id=&quot;cb42-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb42-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;makeRecordExample &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb42-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb42-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ERecord&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb42-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb42-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ( eField &lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb42-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb42-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; eField &lt;span class=&quot;st&quot;&gt;&quot;label&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PString&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;found&quot;&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb42-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb42-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb42-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb42-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    )&lt;/span&gt;
&lt;span id=&quot;cb42-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb42-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb42-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb42-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;recordExample ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb42-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb42-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;recordExample &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EAccess&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; makeRecordExample &lt;span class=&quot;dt&quot;&gt;IZ&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;sum-injection-and-case-analysis&quot;&gt;Sum Injection and Case Analysis&lt;/h3&gt;
&lt;p&gt;We also need a type-level list witness for &lt;em&gt;sum&lt;/em&gt; types, because we
need to be able to implement the correct continuations for pattern matches: How
do we know &lt;em&gt;what&lt;/em&gt; thing to handle in each pattern match, unless the sum
type has that information in its type?&lt;/p&gt;
&lt;p&gt;Luckily due to the magic of duality, we can use the same tools, for the most
part! We can inject into a sum with an &lt;code&gt;Index&lt;/code&gt;, let’s say for a
&lt;code&gt;Expr (TSum [&quot;Found&quot; ::: TInt, &quot;Missing&quot; ::: TString])&lt;/code&gt;: sum type
with &lt;code&gt;Found&lt;/code&gt; containing an integer and &lt;code&gt;Missing&lt;/code&gt;
containing a string:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb43&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb43-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb43-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L106-L106&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb43-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb43-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb43-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb43-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EChoice&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; l &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; as (l &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;TSum&lt;/span&gt; as)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb44&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb44-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb44-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;EChoice&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IZ&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;        ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;TSum&lt;/span&gt; [&lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&quot;Missing&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;])&lt;/span&gt;
&lt;span id=&quot;cb44-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb44-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;EChoice&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;Missing&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IZ&lt;/span&gt;)&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;TSum&lt;/span&gt; [&lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&quot;Missing&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;])&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb45&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb45-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb45-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L181-L182&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb45-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb45-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb45-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb45-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;makeSumExample ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;TSum&lt;/span&gt; [&lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&quot;Missing&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;])&lt;/span&gt;
&lt;span id=&quot;cb45-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb45-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;makeSumExample &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EChoice&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IZ&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And we can re-use &lt;code&gt;Rec&lt;/code&gt; to define a type that can &lt;em&gt;handle&lt;/em&gt;
a &lt;code&gt;[&quot;Found&quot; ::: TInt, &quot;Missing&quot; ::: TString]&lt;/code&gt; sum:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb46&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb46-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb46-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L112-L133&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb46-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb46-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb46-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb46-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ExprHandler&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Symbol&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt;) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb46-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb46-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EHandler&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; l &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ExprHandler&lt;/span&gt; b (l &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a)&lt;/span&gt;
&lt;span id=&quot;cb46-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb46-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb46-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb46-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;eHandler ::&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;forall&lt;/span&gt; l &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; l &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ExprHandler&lt;/span&gt; b (l &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a)&lt;/span&gt;
&lt;span id=&quot;cb46-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb46-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;eHandler l &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EHandler&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb47&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb47-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb47-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;t eHandler &lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;)))&lt;/span&gt;
&lt;span id=&quot;cb47-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb47-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;ExprHandler&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt; (&lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb47-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb47-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;         &lt;span class=&quot;co&quot;&gt;-- ^ result           ^ payload&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And we can put these into a &lt;code&gt;Rec&lt;/code&gt; to handle each option in the
list:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb48&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb48-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb48-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;t eHandler &lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;)))&lt;/span&gt;
&lt;span id=&quot;cb48-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb48-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;           &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; eHandler &lt;span class=&quot;st&quot;&gt;&quot;Missing&quot;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STString&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;message&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb48-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb48-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;           &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb48-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb48-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;ExprHandler&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;) [&lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&quot;Missing&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And that’s exactly what a case statement is:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb49&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb49-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb49-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L107-L107&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb49-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb49-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb49-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb49-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ECase&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;TSum&lt;/span&gt; as) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;ExprHandler&lt;/span&gt; b) as &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; b&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb50&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb50-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb50-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L184-L191&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb50-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb50-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb50-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb50-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;sumExample ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb50-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb50-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sumExample &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb50-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb50-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ECase&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb50-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb50-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    makeSumExample&lt;/span&gt;
&lt;span id=&quot;cb50-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb50-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ( eHandler &lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;)))&lt;/span&gt;
&lt;span id=&quot;cb50-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb50-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; eHandler &lt;span class=&quot;st&quot;&gt;&quot;Missing&quot;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STString&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;message&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb50-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb50-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb50-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb50-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    )&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note that we’re still using string binders, so there’s still an element of
unsafety here… we say that the variable name is &lt;code&gt;&quot;value&quot;&lt;/code&gt; and that it
is a &lt;code&gt;TInt&lt;/code&gt;, but when we later refer to the variable with
&lt;code&gt;EVar STInt &quot;value&quot;&lt;/code&gt;, it isn’t type-checked that later references use
the same type. The compiler would be just as happy with
&lt;code&gt;EVar STString &quot;value&quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here’s an example demonstrating both failure modes: the first handler
references a variable that doesn’t exist, and the second handler references a
variable that does exist as an incorrect type! How unfortunate.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb51&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb51-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb51-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L202-L209&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb51-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb51-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb51-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb51-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;badCaseBranchExample ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb51-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb51-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;badCaseBranchExample &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb51-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb51-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ECase&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb51-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb51-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;dt&quot;&gt;EChoice&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IZ&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;)))&lt;/span&gt;
&lt;span id=&quot;cb51-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb51-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ( eHandler &lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;missing&quot;&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;)))&lt;/span&gt;
&lt;span id=&quot;cb51-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb51-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; eHandler &lt;span class=&quot;st&quot;&gt;&quot;Missing&quot;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STString&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;message&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;message&quot;&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;)))&lt;/span&gt;
&lt;span id=&quot;cb51-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb51-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb51-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb51-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    )&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;runtime-equality-for-records-and-sums&quot;&gt;Runtime Equality for Records and
Sums&lt;/h3&gt;
&lt;p&gt;One complication is that we need to update the &lt;code&gt;TestEquality&lt;/code&gt;
instance for &lt;code&gt;STy&lt;/code&gt;. The record and sum labels are type-level
&lt;code&gt;Symbol&lt;/code&gt;s, so we compare those with the &lt;code&gt;sameSymbol&lt;/code&gt; (kind
of like &lt;code&gt;testEquality&lt;/code&gt; for any &lt;code&gt;KnownSymbol&lt;/code&gt; instance) and
then compare the payload types recursively.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb52&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb52-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L284-L324&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TestEquality&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    testEquality &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sameTy&lt;/span&gt;
&lt;span id=&quot;cb52-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TestEquality&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STyField&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    testEquality &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sameField&lt;/span&gt;
&lt;span id=&quot;cb52-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;sameTy ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STy&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;:~:&lt;/span&gt; b)&lt;/span&gt;
&lt;span id=&quot;cb52-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sameTy &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STInt&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt;; _ &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STBool&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STBool&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt;; _ &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STString&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STString&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt;; _ &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STRecord&lt;/span&gt; as &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;STRecord&lt;/span&gt; bs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; sameFields as bs&lt;/span&gt;
&lt;span id=&quot;cb52-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-18&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    _ &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-19&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STSum&lt;/span&gt; as &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-20&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;STSum&lt;/span&gt; bs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-21&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; sameFields as bs&lt;/span&gt;
&lt;span id=&quot;cb52-22&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-23&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    _ &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-24&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;STFun&lt;/span&gt; a b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-25&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;STFun&lt;/span&gt; c d &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-26&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-26&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; sameTy a c&lt;/span&gt;
&lt;span id=&quot;cb52-27&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-27&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; sameTy b d&lt;/span&gt;
&lt;span id=&quot;cb52-28&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-28&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-29&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-29&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    _ &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-30&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-30&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-31&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-31&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;sameFields ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STyField&lt;/span&gt; xs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STyField&lt;/span&gt; ys &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; (xs &lt;span class=&quot;op&quot;&gt;:~:&lt;/span&gt; ys)&lt;/span&gt;
&lt;span id=&quot;cb52-32&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-32&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sameFields &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-33&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-33&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sameFields (x &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; xs) (y &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; ys) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-34&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-34&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; sameField x y&lt;/span&gt;
&lt;span id=&quot;cb52-35&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-35&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; sameFields xs ys&lt;/span&gt;
&lt;span id=&quot;cb52-36&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-36&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-37&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-37&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sameFields _ _ &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-38&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-38&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-39&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-39&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;sameField ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STyField&lt;/span&gt; x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;STyField&lt;/span&gt; y &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; (x &lt;span class=&quot;op&quot;&gt;:~:&lt;/span&gt; y)&lt;/span&gt;
&lt;span id=&quot;cb52-40&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-40&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sameField (&lt;span class=&quot;dt&quot;&gt;STyField&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l tx) (&lt;span class=&quot;dt&quot;&gt;STyField&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;m ty) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb52-41&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-41&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; sameSymbol (&lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l) (&lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;m)&lt;/span&gt;
&lt;span id=&quot;cb52-42&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-42&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; sameTy tx ty&lt;/span&gt;
&lt;span id=&quot;cb52-43&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb52-43&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;the-full-eval&quot;&gt;The Full Eval&lt;/h3&gt;
&lt;p&gt;Before we write the final &lt;code&gt;eval&lt;/code&gt;, let’s practice using
&lt;code&gt;Index&lt;/code&gt; and &lt;code&gt;Rec&lt;/code&gt; together. If we have an index
&lt;code&gt;Index as a&lt;/code&gt; that picks out a value &lt;code&gt;a&lt;/code&gt; in
&lt;code&gt;as&lt;/code&gt;, then we can pick out the &lt;code&gt;f a&lt;/code&gt; from a
&lt;code&gt;Rec f as&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb53&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb53-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb53-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L60-L63&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb53-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb53-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb53-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb53-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;indexRec ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; xs x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; f xs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; f x&lt;/span&gt;
&lt;span id=&quot;cb53-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb53-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;indexRec &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb53-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb53-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;IZ&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; \(x &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; _) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; x&lt;/span&gt;
&lt;span id=&quot;cb53-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb53-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;IS&lt;/span&gt; i &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; \(_ &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; xs) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; indexRec i xs&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We also can recursively iterate a function over each item, assuming the
function &lt;code&gt;forall x. f x -&amp;gt; g x&lt;/code&gt;: that is, we can turn a
&lt;code&gt;Rec f as&lt;/code&gt; into a &lt;code&gt;Rec g as&lt;/code&gt; assuming our function is
polymorphic over each &lt;code&gt;x&lt;/code&gt;, and only depends on the shape of
&lt;code&gt;f&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb54&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb54-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb54-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L65-L67&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb54-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb54-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb54-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb54-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;traverseRec ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Applicative&lt;/span&gt; m &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; (&lt;span class=&quot;kw&quot;&gt;forall&lt;/span&gt; x&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt; f x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (g x)) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; f xs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; m (&lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; g xs)&lt;/span&gt;
&lt;span id=&quot;cb54-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb54-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;traverseRec _ &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb54-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb54-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;traverseRec f (x &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; xs) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; (&lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; f x &lt;span class=&quot;op&quot;&gt;&amp;lt;*&amp;gt;&lt;/span&gt; traverseRec f xs&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With that, we can write our full &lt;code&gt;eval&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb55&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb55-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L326-L369&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb55-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb55-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;eval ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Map&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;SomeValue&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; t &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Maybe&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; t)&lt;/span&gt;
&lt;span id=&quot;cb55-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;eval env &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb55-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; n) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; n)&lt;/span&gt;
&lt;span id=&quot;cb55-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PBool&lt;/span&gt; b) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; b)&lt;/span&gt;
&lt;span id=&quot;cb55-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PString&lt;/span&gt; s) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVString&lt;/span&gt; s)&lt;/span&gt;
&lt;span id=&quot;cb55-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; t v &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb55-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;SomeValue&lt;/span&gt; t' v' &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; M.lookup v env&lt;/span&gt;
&lt;span id=&quot;cb55-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;Refl&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; sameTy t t'&lt;/span&gt;
&lt;span id=&quot;cb55-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; v'&lt;/span&gt;
&lt;span id=&quot;cb55-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ELambda&lt;/span&gt; ta n body &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb55-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVFun&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; \x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; eval (M.insert n (&lt;span class=&quot;dt&quot;&gt;SomeValue&lt;/span&gt; ta x) env) body&lt;/span&gt;
&lt;span id=&quot;cb55-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EApply&lt;/span&gt; f x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb55-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVFun&lt;/span&gt; g &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env f&lt;/span&gt;
&lt;span id=&quot;cb55-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    x' &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id=&quot;cb55-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    g x'&lt;/span&gt;
&lt;span id=&quot;cb55-18&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; o x y &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; o &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb55-19&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb55-20&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id=&quot;cb55-21&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env y&lt;/span&gt;
&lt;span id=&quot;cb55-22&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; b))&lt;/span&gt;
&lt;span id=&quot;cb55-23&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;OTimes&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb55-24&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id=&quot;cb55-25&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env y&lt;/span&gt;
&lt;span id=&quot;cb55-26&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-26&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; b))&lt;/span&gt;
&lt;span id=&quot;cb55-27&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-27&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;OLte&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb55-28&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-28&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id=&quot;cb55-29&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-29&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env y&lt;/span&gt;
&lt;span id=&quot;cb55-30&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-30&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;&amp;lt;=&lt;/span&gt; b))&lt;/span&gt;
&lt;span id=&quot;cb55-31&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-31&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;OAnd&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb55-32&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-32&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id=&quot;cb55-33&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-33&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env y&lt;/span&gt;
&lt;span id=&quot;cb55-34&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-34&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; b))&lt;/span&gt;
&lt;span id=&quot;cb55-35&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-35&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ERecord&lt;/span&gt; xs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb55-36&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-36&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVRecord&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; traverseRec (evalField env) xs&lt;/span&gt;
&lt;span id=&quot;cb55-37&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-37&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EAccess&lt;/span&gt; e i &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb55-38&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-38&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVRecord&lt;/span&gt; xs &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env e&lt;/span&gt;
&lt;span id=&quot;cb55-39&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-39&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; indexRec i xs &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb55-40&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-40&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVField&lt;/span&gt; v &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;pure&lt;/span&gt; v&lt;/span&gt;
&lt;span id=&quot;cb55-41&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-41&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EChoice&lt;/span&gt; i x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb55-42&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-42&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVSum&lt;/span&gt; i &lt;span class=&quot;op&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id=&quot;cb55-43&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-43&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ECase&lt;/span&gt; x hs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb55-44&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-44&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVSum&lt;/span&gt; i v &lt;span class=&quot;ot&quot;&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id=&quot;cb55-45&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-45&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; indexRec i hs &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb55-46&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb55-46&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EHandler&lt;/span&gt; t n body &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; eval (M.insert n (&lt;span class=&quot;dt&quot;&gt;SomeValue&lt;/span&gt; t v) env) body&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;ergonomics-of-records-and-sums&quot;&gt;Ergonomics of Records and Sums&lt;/h3&gt;
&lt;p&gt;Note that we could also choose to implement records and sums using row types
indexed by the name of the field itself, instead of an ordered list of tuples.
This would have the advantage of making, for example,
&lt;code&gt;{ value :: Int, label :: String }&lt;/code&gt; the same type as
&lt;code&gt;{ label :: String, value :: Int }&lt;/code&gt;. However, I personally prefer the
style of building things inductively (&lt;code&gt;:&amp;amp;&lt;/code&gt;/&lt;code&gt;RNil&lt;/code&gt; and
&lt;code&gt;IS&lt;/code&gt;/&lt;code&gt;IZ&lt;/code&gt;), it makes the type errors and constructions a
lot easier to work with and reason with.&lt;/p&gt;
&lt;p&gt;However, we can get a little bit of the best of both worlds by using
typeclasses to auto-insert the &lt;code&gt;Index&lt;/code&gt; witnesses into a list.&lt;/p&gt;
&lt;p&gt;First, we can write a typeclass that searches a type-level list of fields and
produces the right &lt;code&gt;Index&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb56&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb56-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb56-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L51-L58&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb56-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb56-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb56-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb56-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ListIx&lt;/span&gt; (&lt;span class=&quot;ot&quot;&gt;l ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Symbol&lt;/span&gt;) (&lt;span class=&quot;ot&quot;&gt;xs ::&lt;/span&gt; [(&lt;span class=&quot;dt&quot;&gt;Symbol&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt;)]) (&lt;span class=&quot;ot&quot;&gt;a ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; l xs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; a &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb56-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb56-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;  listIx ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; xs (l &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a)&lt;/span&gt;
&lt;span id=&quot;cb56-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb56-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb56-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb56-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ListIx&lt;/span&gt; l (l &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; xs) a &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb56-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb56-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  listIx &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IZ&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb56-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb56-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb56-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb56-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{-# OVERLAPPABLE #-}&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ListIx&lt;/span&gt; l xs a &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ListIx&lt;/span&gt; l (m &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; b &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; xs) a &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb56-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb56-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  listIx &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IS&lt;/span&gt; (listIx &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The FunDep &lt;code&gt;l xs -&amp;gt; a&lt;/code&gt; lets us use this like a function: for a
label &lt;code&gt;l&lt;/code&gt; and a list &lt;code&gt;xs&lt;/code&gt;, we should be able to uniquely
determine the &lt;code&gt;a&lt;/code&gt; type it singles out, if it exists. So we have an
instance of
&lt;code&gt;ListIx &quot;value&quot; [&quot;value&quot; ::: TInt, &quot;label&quot; ::: TString] TInt&lt;/code&gt;, where
the label &lt;code&gt;&quot;value&quot;&lt;/code&gt; and the list uniquely determines the result type
&lt;code&gt;TInt&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We can now have a helper function that we can call like
&lt;code&gt;eAccess &quot;value&quot;&lt;/code&gt; using GHC 9.10’s
&lt;code&gt;RequiredTypeArguments&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb57&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb57-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb57-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L118-L123&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb57-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb57-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb57-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb57-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;eAccess ::&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb57-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb57-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;forall&lt;/span&gt; (&lt;span class=&quot;ot&quot;&gt;l ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Symbol&lt;/span&gt;) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb57-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb57-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  (&lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; l, &lt;span class=&quot;dt&quot;&gt;ListIx&lt;/span&gt; l as a) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb57-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb57-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;TRecord&lt;/span&gt; as) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb57-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb57-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; a&lt;/span&gt;
&lt;span id=&quot;cb57-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb57-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;eAccess l e &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EAccess&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l e (listIx &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That lets us write the field name directly, and the compiler will generate
the &lt;code&gt;Index&lt;/code&gt; automatically for us:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb58&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb58-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb58-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L167-L176&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb58-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb58-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb58-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb58-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;namedAccessExample ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb58-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb58-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;namedAccessExample &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb58-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb58-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  eAccess&lt;/span&gt;
&lt;span id=&quot;cb58-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb58-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;st&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb58-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb58-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ( &lt;span class=&quot;dt&quot;&gt;ERecord&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb58-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb58-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        ( eField &lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb58-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb58-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; eField &lt;span class=&quot;st&quot;&gt;&quot;label&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PString&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;found&quot;&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb58-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb58-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb58-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb58-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        )&lt;/span&gt;
&lt;span id=&quot;cb58-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb58-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    )&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here,
&lt;code&gt;eAccess &quot;value&quot; :: Expr (TRecord [&quot;value&quot; ::: TInt, &quot;label&quot; ::: TString]) -&amp;gt; Expr TInt&lt;/code&gt;,
its result type uniquely determined by the types in the record fields.&lt;/p&gt;
&lt;p&gt;The same trick works for sum injections, so we can write the constructor name
directly:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb59&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb59-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb59-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L125-L179&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb59-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb59-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb59-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb59-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;eChoice ::&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb59-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb59-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;forall&lt;/span&gt; (&lt;span class=&quot;ot&quot;&gt;l ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Symbol&lt;/span&gt;) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb59-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb59-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  (&lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; l, &lt;span class=&quot;dt&quot;&gt;ListIx&lt;/span&gt; l as a) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb59-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb59-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb59-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb59-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;TSum&lt;/span&gt; as)&lt;/span&gt;
&lt;span id=&quot;cb59-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb59-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;eChoice l e &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EChoice&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l (listIx &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l) e&lt;/span&gt;
&lt;span id=&quot;cb59-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb59-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb59-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb59-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;namedChoiceExample ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;TSum&lt;/span&gt; [&lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&quot;Missing&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;])&lt;/span&gt;
&lt;span id=&quot;cb59-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb59-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;namedChoiceExample &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; eChoice &lt;span class=&quot;st&quot;&gt;&quot;Missing&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PString&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;not here&quot;&lt;/span&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here,
&lt;code&gt;eChoice &quot;Missing&quot; :: Expr TString -&amp;gt; Expr (TSum [&quot;Found&quot; ::: TInt, &quot;Missing&quot; ::: TString])&lt;/code&gt;,
because the constructor name &lt;code&gt;&quot;Missing&quot;&lt;/code&gt; uniquely determines the
payload type inside that sum.&lt;/p&gt;
&lt;h3 id=&quot;pretty-printing-records-and-sums&quot;&gt;Pretty-Printing Records and Sums&lt;/h3&gt;
&lt;p&gt;To pretty-print, we finally use that &lt;code&gt;KnownSymbol&lt;/code&gt; constraint
we’ve been tracking this entire time. We can use
&lt;code&gt;symbolVal :: KnownSymbol s =&amp;gt; p s -&amp;gt; String&lt;/code&gt; to get the string
&lt;em&gt;value&lt;/em&gt; from the type-level string.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb60&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb60-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage3.hs#L237-L282&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;ppPrim ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Prim&lt;/span&gt; t &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id=&quot;cb60-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppPrim &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; n &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; PP.pretty n&lt;/span&gt;
&lt;span id=&quot;cb60-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;PBool&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;if&lt;/span&gt; b &lt;span class=&quot;kw&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;true&quot;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;false&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;PString&lt;/span&gt; s &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; PP.pretty (&lt;span class=&quot;fu&quot;&gt;show&lt;/span&gt; s)&lt;/span&gt;
&lt;span id=&quot;cb60-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;ppOp ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Op&lt;/span&gt; a b c &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id=&quot;cb60-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppOp &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;+&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OTimes&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OLte&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&amp;lt;=&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OAnd&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&amp;amp;&amp;amp;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;ppFields ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ExprField&lt;/span&gt; xs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann]&lt;/span&gt;
&lt;span id=&quot;cb60-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppFields &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; []&lt;/span&gt;
&lt;span id=&quot;cb60-18&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppFields (&lt;span class=&quot;dt&quot;&gt;EField&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l x &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; xs) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-19&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  (PP.pretty (symbolVal (&lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l)) &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;=&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt; x) &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; ppFields xs&lt;/span&gt;
&lt;span id=&quot;cb60-20&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-21&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;ppHandlers ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;ExprHandler&lt;/span&gt; b) xs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann]&lt;/span&gt;
&lt;span id=&quot;cb60-22&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppHandlers &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; []&lt;/span&gt;
&lt;span id=&quot;cb60-23&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppHandlers (&lt;span class=&quot;dt&quot;&gt;EHandler&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l _ n body &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; xs) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-24&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  (PP.pretty (symbolVal (&lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l)) &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; PP.pretty n &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;-&amp;gt;&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt; body) &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; ppHandlers xs&lt;/span&gt;
&lt;span id=&quot;cb60-25&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-26&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-26&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;ppExpr ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Bool&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; t &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id=&quot;cb60-27&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-27&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppExpr paren &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-28&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-28&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; p &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; ppPrim p&lt;/span&gt;
&lt;span id=&quot;cb60-29&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-29&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; _ v &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; PP.pretty v&lt;/span&gt;
&lt;span id=&quot;cb60-30&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-30&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ELambda&lt;/span&gt; _ n body &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; wrap &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;\\&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; PP.pretty n &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;-&amp;gt;&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt; body&lt;/span&gt;
&lt;span id=&quot;cb60-31&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-31&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EApply&lt;/span&gt; f x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; wrap &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; f &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; x&lt;/span&gt;
&lt;span id=&quot;cb60-32&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-32&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; o x y &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; wrap &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; x &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppOp o &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; y&lt;/span&gt;
&lt;span id=&quot;cb60-33&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-33&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ERecord&lt;/span&gt; xs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; PP.encloseSep &lt;span class=&quot;st&quot;&gt;&quot;{ &quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot; }&quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;, &quot;&lt;/span&gt; (ppFields xs)&lt;/span&gt;
&lt;span id=&quot;cb60-34&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-34&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EAccess&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l e _ &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; e &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;.&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; PP.pretty (symbolVal (&lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l))&lt;/span&gt;
&lt;span id=&quot;cb60-35&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-35&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EChoice&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l _ x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; wrap &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; PP.pretty (symbolVal (&lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l)) &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; x&lt;/span&gt;
&lt;span id=&quot;cb60-36&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-36&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ECase&lt;/span&gt; x hs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-37&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-37&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    wrap &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-38&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-38&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      PP.sep&lt;/span&gt;
&lt;span id=&quot;cb60-39&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-39&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        [ &lt;span class=&quot;st&quot;&gt;&quot;case&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt; x &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;of&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-40&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-40&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        , PP.encloseSep &lt;span class=&quot;st&quot;&gt;&quot;{ &quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot; }&quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;; &quot;&lt;/span&gt; (ppHandlers hs)&lt;/span&gt;
&lt;span id=&quot;cb60-41&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-41&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        ]&lt;/span&gt;
&lt;span id=&quot;cb60-42&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-42&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-43&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-43&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    wrap&lt;/span&gt;
&lt;span id=&quot;cb60-44&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-44&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; paren &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; PP.parens&lt;/span&gt;
&lt;span id=&quot;cb60-45&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-45&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;otherwise&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;id&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-46&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-46&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-47&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-47&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;prettyExpr ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; t &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id=&quot;cb60-48&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb60-48&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;prettyExpr &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;capturing-variables&quot;&gt;Capturing Variables&lt;/h2&gt;
&lt;p&gt;In order to have &lt;code&gt;EVar&lt;/code&gt; be type-safe, the environment itself needs
to be a part of the &lt;code&gt;Expr&lt;/code&gt; type, and you should only be able to use
&lt;code&gt;EVar&lt;/code&gt; if the &lt;code&gt;Expr&lt;/code&gt; enforces it. &lt;code&gt;ELambda&lt;/code&gt;
would, therefore, introduce the new variable to the environment.&lt;/p&gt;
&lt;p&gt;We’ll have:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb61&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb61-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb61-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage4.hs#L80-L80&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb61-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb61-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb61-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb61-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; [(&lt;span class=&quot;dt&quot;&gt;Symbol&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt;)] &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So a value of type &lt;code&gt;Expr [&quot;x&quot; ::: TInt, &quot;y&quot; ::: TBool] t&lt;/code&gt; is an
expression with free variables &lt;code&gt;x&lt;/code&gt; of type &lt;code&gt;Int&lt;/code&gt; and
&lt;code&gt;y&lt;/code&gt; of type &lt;code&gt;Bool&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Surprise! That small detour to add records and sums to our language actually
ended up being a smooth precursor to all of the techniques we will be using to
solve for variable binders.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ELambda&lt;/code&gt; would therefore take an &lt;code&gt;Expr&lt;/code&gt; with a free
variable and turn it into an &lt;code&gt;Expr&lt;/code&gt; of a function type. We also keep
a &lt;code&gt;KnownSymbol&lt;/code&gt; constraint for the name so that we can recover the
name when we render the expression.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb62&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb62-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb62-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage4.hs#L83-L83&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb62-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb62-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb62-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb62-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ELambda&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; n &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (n &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a '&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; vs) b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs (a &lt;span class=&quot;op&quot;&gt;:-&amp;gt;&lt;/span&gt; b)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;EVar&lt;/code&gt; then becomes exactly like &lt;code&gt;EAccess&lt;/code&gt;! We “index”
into the environment of the &lt;code&gt;Expr vs a&lt;/code&gt; using &lt;code&gt;Index&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb63&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb63-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb63-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage4.hs#L82-L82&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb63-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb63-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb63-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb63-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; vs (n &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; t) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs t&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So it is legal to have
&lt;code&gt;EVar IZ :: Expr [&quot;x&quot; ::: TInt, &quot;y&quot; ::: TBool] TInt&lt;/code&gt;, and also it is
automatically inferred to be a &lt;code&gt;TInt&lt;/code&gt;. But we could &lt;em&gt;not&lt;/em&gt;
write &lt;code&gt;EVar IZ :: Expr [] TInt&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And finally, our whole &lt;code&gt;Expr&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb64&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb64-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb64-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage4.hs#L80-L89&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb64-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb64-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb64-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb64-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; [(&lt;span class=&quot;dt&quot;&gt;Symbol&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt;)] &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb64-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb64-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Prim&lt;/span&gt; t &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs t&lt;/span&gt;
&lt;span id=&quot;cb64-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb64-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; vs (n &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; t) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs t&lt;/span&gt;
&lt;span id=&quot;cb64-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb64-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ELambda&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; n &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (n &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a '&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; vs) b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs (a &lt;span class=&quot;op&quot;&gt;:-&amp;gt;&lt;/span&gt; b)&lt;/span&gt;
&lt;span id=&quot;cb64-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb64-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EApply&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs (a &lt;span class=&quot;op&quot;&gt;:-&amp;gt;&lt;/span&gt; b) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs b&lt;/span&gt;
&lt;span id=&quot;cb64-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb64-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Op&lt;/span&gt; a b c &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs c&lt;/span&gt;
&lt;span id=&quot;cb64-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb64-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ERecord&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;ExprField&lt;/span&gt; vs) as &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs (&lt;span class=&quot;dt&quot;&gt;TRecord&lt;/span&gt; as)&lt;/span&gt;
&lt;span id=&quot;cb64-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb64-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EAccess&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; l &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs (&lt;span class=&quot;dt&quot;&gt;TRecord&lt;/span&gt; as) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; as (l &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs a&lt;/span&gt;
&lt;span id=&quot;cb64-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb64-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EChoice&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; l &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; as (l &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs (&lt;span class=&quot;dt&quot;&gt;TSum&lt;/span&gt; as)&lt;/span&gt;
&lt;span id=&quot;cb64-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb64-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ECase&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs (&lt;span class=&quot;dt&quot;&gt;TSum&lt;/span&gt; as) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;ExprHandler&lt;/span&gt; vs b) as &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs b&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Just like with record access, we can use the &lt;code&gt;ListIx&lt;/code&gt; class to
write a named helper:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb65&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb65-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb65-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage4.hs#L47-L120&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb65-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb65-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb65-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb65-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ListIx&lt;/span&gt; (&lt;span class=&quot;ot&quot;&gt;l ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Symbol&lt;/span&gt;) (&lt;span class=&quot;ot&quot;&gt;xs ::&lt;/span&gt; [(&lt;span class=&quot;dt&quot;&gt;Symbol&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt;)]) (&lt;span class=&quot;ot&quot;&gt;a ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; l xs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; a &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb65-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb65-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;  listIx ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; xs (l &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a)&lt;/span&gt;
&lt;span id=&quot;cb65-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb65-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb65-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb65-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ListIx&lt;/span&gt; l (l &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a '&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; xs) a &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb65-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb65-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  listIx &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IZ&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb65-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb65-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb65-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb65-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{-# OVERLAPPABLE #-}&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ListIx&lt;/span&gt; l xs a &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ListIx&lt;/span&gt; l (m &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; b '&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; xs) a &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb65-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb65-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  listIx &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IS&lt;/span&gt; (listIx &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l)&lt;/span&gt;
&lt;span id=&quot;cb65-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb65-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb65-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb65-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;eVar ::&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;forall&lt;/span&gt; n &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ListIx&lt;/span&gt; n vs a &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs a&lt;/span&gt;
&lt;span id=&quot;cb65-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb65-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;eVar n &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; (listIx &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;n)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Adding in our other &lt;code&gt;-XRequiredTypeArguments&lt;/code&gt; helpers:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb66&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb66-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage4.hs#L91-L117&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;eLambda ::&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;forall&lt;/span&gt; n &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; n &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (n &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a '&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; vs) b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs (a &lt;span class=&quot;op&quot;&gt;:-&amp;gt;&lt;/span&gt; b)&lt;/span&gt;
&lt;span id=&quot;cb66-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;eLambda n &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ELambda&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;n&lt;/span&gt;
&lt;span id=&quot;cb66-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;eField ::&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;forall&lt;/span&gt; l &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; l &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;ExprField&lt;/span&gt; vs (l &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a)&lt;/span&gt;
&lt;span id=&quot;cb66-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;eField l &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EField&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l&lt;/span&gt;
&lt;span id=&quot;cb66-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;eAccess ::&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;forall&lt;/span&gt; l &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  (&lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; l, &lt;span class=&quot;dt&quot;&gt;ListIx&lt;/span&gt; l as a) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs (&lt;span class=&quot;dt&quot;&gt;TRecord&lt;/span&gt; as) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs a&lt;/span&gt;
&lt;span id=&quot;cb66-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;eAccess l e &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EAccess&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l e (listIx &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l)&lt;/span&gt;
&lt;span id=&quot;cb66-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;eChoice ::&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;forall&lt;/span&gt; l &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-18&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  (&lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; l, &lt;span class=&quot;dt&quot;&gt;ListIx&lt;/span&gt; l as a) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-19&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-20&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs (&lt;span class=&quot;dt&quot;&gt;TSum&lt;/span&gt; as)&lt;/span&gt;
&lt;span id=&quot;cb66-21&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;eChoice l e &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EChoice&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l (listIx &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l) e&lt;/span&gt;
&lt;span id=&quot;cb66-22&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-23&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;eHandler ::&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-24&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;forall&lt;/span&gt; n &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-25&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;forall&lt;/span&gt; l &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-26&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-26&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  (&lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; n, &lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; l) &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-27&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-27&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; (n &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a '&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; vs) b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-28&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-28&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ExprHandler&lt;/span&gt; vs b (l &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a)&lt;/span&gt;
&lt;span id=&quot;cb66-29&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb66-29&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;eHandler n l &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EHandler&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;n &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And we get something that is &lt;em&gt;truly&lt;/em&gt; type-safe: all expressions are
well-typed, and all variables are ensured to be bound!&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb67&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb67-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage4.hs#L139-L171&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;fifteen ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; '[] &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;fifteen &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EApply&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (eLambda &lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OTimes&lt;/span&gt; (eVar &lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;))))&lt;/span&gt;
&lt;span id=&quot;cb67-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb67-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;recordExample ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; '[] &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;recordExample &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ( eAccess&lt;/span&gt;
&lt;span id=&quot;cb67-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        ( &lt;span class=&quot;dt&quot;&gt;ERecord&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            ( eField &lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb67-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; eField &lt;span class=&quot;st&quot;&gt;&quot;label&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PString&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;found&quot;&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb67-18&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-19&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            )&lt;/span&gt;
&lt;span id=&quot;cb67-20&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        )&lt;/span&gt;
&lt;span id=&quot;cb67-21&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    )&lt;/span&gt;
&lt;span id=&quot;cb67-22&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb67-23&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-24&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;sumExample ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; '[] &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-25&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sumExample &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-26&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-26&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ECase&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-27&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-27&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (eChoice &lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;)))&lt;/span&gt;
&lt;span id=&quot;cb67-28&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-28&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ( eHandler &lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; (eVar &lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;)))&lt;/span&gt;
&lt;span id=&quot;cb67-29&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-29&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; eHandler &lt;span class=&quot;st&quot;&gt;&quot;message&quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;Missing&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;))&lt;/span&gt;
&lt;span id=&quot;cb67-30&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-30&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-31&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb67-31&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    )&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;what-we-gained&quot;&gt;What we gained&lt;/h3&gt;
&lt;p&gt;Now all of the previous “bad” examples we gave are finally
compiler-verified:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb68&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb68-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;t (&lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IZ&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; '[] &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb68-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;interactive&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb68-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    • &lt;span class=&quot;dt&quot;&gt;Couldn't&lt;/span&gt; match &lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; (n0 &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; xs0&lt;/span&gt;
&lt;span id=&quot;cb68-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                     with&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; '[]&lt;/span&gt;
&lt;span id=&quot;cb68-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;Expected&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; '[] (n0 &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb68-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;dt&quot;&gt;Actual&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; ((n0 &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; xs0) (n0 &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb68-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb68-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;t (&lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IZ&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; '[&lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;] &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb68-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;interactive&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb68-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    • &lt;span class=&quot;dt&quot;&gt;Couldn't&lt;/span&gt; match &lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; ‘&lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;’ with ‘&lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;’&lt;/span&gt;
&lt;span id=&quot;cb68-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;Expected&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; '[&lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;] (&lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb68-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;dt&quot;&gt;Actual&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; '[&lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;] (&lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb68-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb68-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;t &lt;span class=&quot;dt&quot;&gt;ECase&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb68-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      (&lt;span class=&quot;dt&quot;&gt;EChoice&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IZ&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;))&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; '[] (&lt;span class=&quot;dt&quot;&gt;TSum&lt;/span&gt; '[&lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&quot;Missing&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;]))&lt;/span&gt;
&lt;span id=&quot;cb68-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      ( &lt;span class=&quot;dt&quot;&gt;EHandler&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IZ&lt;/span&gt;)) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;)))&lt;/span&gt;
&lt;span id=&quot;cb68-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EHandler&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;message&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;Missing&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;IZ&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;)))&lt;/span&gt;
&lt;span id=&quot;cb68-18&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb68-19&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      )&lt;/span&gt;
&lt;span id=&quot;cb68-20&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;interactive&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb68-21&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    • &lt;span class=&quot;dt&quot;&gt;Couldn't&lt;/span&gt; match &lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; (n0 &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; xs0&lt;/span&gt;
&lt;span id=&quot;cb68-22&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;                     with&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; '[]&lt;/span&gt;
&lt;span id=&quot;cb68-23&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;interactive&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb68-24&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb68-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    • &lt;span class=&quot;dt&quot;&gt;Couldn't&lt;/span&gt; match &lt;span class=&quot;kw&quot;&gt;type&lt;/span&gt; ‘&lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;’ with ‘&lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;’&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And using the &lt;code&gt;ListIx&lt;/code&gt; helpers, those same failures show up as
failed index searches:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb69&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb69-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb69-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;t (eVar &lt;span class=&quot;st&quot;&gt;&quot;missing&quot;&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; '[] &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb69-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb69-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;interactive&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb69-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb69-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    • &lt;span class=&quot;dt&quot;&gt;No&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; for ‘&lt;span class=&quot;dt&quot;&gt;ListIx&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;missing&quot;&lt;/span&gt; '[] &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;’&lt;/span&gt;
&lt;span id=&quot;cb69-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb69-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb69-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb69-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;t (eVar &lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; '[&lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;] &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb69-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb69-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;interactive&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb69-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb69-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    • &lt;span class=&quot;dt&quot;&gt;No&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; for ‘&lt;span class=&quot;dt&quot;&gt;ListIx&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt; '[] &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;’&lt;/span&gt;
&lt;span id=&quot;cb69-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb69-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb69-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb69-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;t &lt;span class=&quot;dt&quot;&gt;ECase&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb69-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb69-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      (eChoice &lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;))&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; '[] (&lt;span class=&quot;dt&quot;&gt;TSum&lt;/span&gt; '[&lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&quot;Missing&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;]))&lt;/span&gt;
&lt;span id=&quot;cb69-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb69-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      ( eHandler &lt;span class=&quot;st&quot;&gt;&quot;value&quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;Found&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; (eVar &lt;span class=&quot;st&quot;&gt;&quot;missing&quot;&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;)))&lt;/span&gt;
&lt;span id=&quot;cb69-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb69-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; eHandler &lt;span class=&quot;st&quot;&gt;&quot;message&quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;Missing&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; (eVar &lt;span class=&quot;st&quot;&gt;&quot;message&quot;&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;)))&lt;/span&gt;
&lt;span id=&quot;cb69-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb69-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb69-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb69-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      )&lt;/span&gt;
&lt;span id=&quot;cb69-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb69-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;interactive&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb69-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb69-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    • &lt;span class=&quot;dt&quot;&gt;No&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; for ‘&lt;span class=&quot;dt&quot;&gt;ListIx&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;missing&quot;&lt;/span&gt; '[] &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;’&lt;/span&gt;
&lt;span id=&quot;cb69-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb69-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;&amp;lt;&lt;/span&gt;interactive&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb69-18&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb69-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    • &lt;span class=&quot;dt&quot;&gt;No&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;instance&lt;/span&gt; for ‘&lt;span class=&quot;dt&quot;&gt;ListIx&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;message&quot;&lt;/span&gt; '[] &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;’&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Expressions that are not well-typed in our domain language are now rejected
by GHC!&lt;a class=&quot;footnote-ref&quot; href=&quot;http://feeds.feedburner.com/incodeblog#fn1&quot; id=&quot;fnref1&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;(As an exercise, can understand why those errors are what they are? Why they
all contain &lt;code&gt;ListIx _ '[]&lt;/code&gt;? For more ergonomics there is stuff we can
do with &lt;code&gt;TypeError&lt;/code&gt; machinery to make the messages a little prettier;
the &lt;em&gt;vinyl&lt;/em&gt; library does a lot to make error messages a bit better, like
in &lt;code&gt;HasField&lt;/code&gt; &lt;a href=&quot;https://hackage.haskell.org/package/vinyl/docs/Data-Vinyl-Derived.html#t:FieldType&quot;&gt;instance&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Note that this is sometimes done using straight &lt;a href=&quot;https://en.wikipedia.org/wiki/De_Bruijn_index&quot;&gt;De Bruijn indices&lt;/a&gt;:
&lt;code&gt;Expr :: [Ty] -&amp;gt; Type&lt;/code&gt;, so we don’t use any names but just the
direct index, but the point of this exercise is to be &lt;em&gt;borderline&lt;/em&gt;
unbearable to write, and &lt;em&gt;not&lt;/em&gt; to be &lt;em&gt;actually&lt;/em&gt; unbearable to
write.&lt;/p&gt;
&lt;h3 id=&quot;eval-with-a-typed-environment&quot;&gt;Eval with a typed environment&lt;/h3&gt;
&lt;p&gt;To actually write &lt;em&gt;eval&lt;/em&gt; now, we need to have a type-safe environment
to store these variables. In order to &lt;code&gt;eval&lt;/code&gt; an &lt;code&gt;Expr vs&lt;/code&gt;,
we need &lt;code&gt;EValue&lt;/code&gt;s for each &lt;code&gt;v&lt;/code&gt; in &lt;code&gt;vs&lt;/code&gt;. So for
&lt;code&gt;Expr [&quot;x&quot; ::: TInt, &quot;y&quot; ::: TBool]&lt;/code&gt;, we need to store a
&lt;code&gt;TInt&lt;/code&gt; and a &lt;code&gt;TBool&lt;/code&gt;. We can once again re-purpose
&lt;code&gt;Rec&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb70&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb70-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb70-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage4.hs#L130-L131&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb70-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb70-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb70-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb70-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValueField&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Symbol&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt;) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb70-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb70-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVField&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValueField&lt;/span&gt; '(l, a)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb71&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb71-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb71-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;t (&lt;span class=&quot;dt&quot;&gt;EVField&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVField&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValueField&lt;/span&gt; [&lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&quot;y&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TBool&lt;/span&gt;])&lt;/span&gt;
&lt;span id=&quot;cb71-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb71-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValueField&lt;/span&gt; [&lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;, &lt;span class=&quot;st&quot;&gt;&quot;y&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TBool&lt;/span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And so we can finally write:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb72&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb72-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage4.hs#L122-L271&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb72-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb72-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb72-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Int&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb72-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Bool&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TBool&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb72-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVString&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TString&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb72-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVRecord&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValueField&lt;/span&gt; as &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;TRecord&lt;/span&gt; as)&lt;/span&gt;
&lt;span id=&quot;cb72-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVSum&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Index&lt;/span&gt; as (l &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;TSum&lt;/span&gt; as)&lt;/span&gt;
&lt;span id=&quot;cb72-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVFun&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; a &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; b) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;:-&amp;gt;&lt;/span&gt; b)&lt;/span&gt;
&lt;span id=&quot;cb72-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb72-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;eval ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValueField&lt;/span&gt; vs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs t &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EValue&lt;/span&gt; t&lt;/span&gt;
&lt;span id=&quot;cb72-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;eval env &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb72-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; n) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; n&lt;/span&gt;
&lt;span id=&quot;cb72-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PBool&lt;/span&gt; b) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; b&lt;/span&gt;
&lt;span id=&quot;cb72-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PString&lt;/span&gt; s) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVString&lt;/span&gt; s&lt;/span&gt;
&lt;span id=&quot;cb72-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; i &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; indexRec i env &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb72-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVField&lt;/span&gt; v &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; v&lt;/span&gt;
&lt;span id=&quot;cb72-18&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ELambda&lt;/span&gt; body &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb72-19&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVFun&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; \x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; eval (&lt;span class=&quot;dt&quot;&gt;EVField&lt;/span&gt; x &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; env) body&lt;/span&gt;
&lt;span id=&quot;cb72-20&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EApply&lt;/span&gt; f x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; eval env f &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb72-21&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVFun&lt;/span&gt; g &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; g (eval env x)&lt;/span&gt;
&lt;span id=&quot;cb72-22&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; o x y &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; (o, eval env x, eval env y) &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb72-23&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; a, &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; b) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; b)&lt;/span&gt;
&lt;span id=&quot;cb72-24&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;dt&quot;&gt;OTimes&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; a, &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; b) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; b)&lt;/span&gt;
&lt;span id=&quot;cb72-25&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;dt&quot;&gt;OLte&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; a, &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; b) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;&amp;lt;=&lt;/span&gt; b)&lt;/span&gt;
&lt;span id=&quot;cb72-26&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-26&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;dt&quot;&gt;OAnd&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; a, &lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; b) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVBool&lt;/span&gt; (a &lt;span class=&quot;op&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; b)&lt;/span&gt;
&lt;span id=&quot;cb72-27&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-27&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ERecord&lt;/span&gt; xs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb72-28&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-28&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVRecord&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; mapRec (\(&lt;span class=&quot;dt&quot;&gt;EField&lt;/span&gt; x) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVField&lt;/span&gt; (eval env x)) xs&lt;/span&gt;
&lt;span id=&quot;cb72-29&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-29&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EAccess&lt;/span&gt; e i &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; eval env e &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb72-30&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-30&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVRecord&lt;/span&gt; xs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; indexRec i xs &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb72-31&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-31&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVField&lt;/span&gt; v &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; v&lt;/span&gt;
&lt;span id=&quot;cb72-32&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-32&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EChoice&lt;/span&gt; i x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;EVSum&lt;/span&gt; i (eval env x)&lt;/span&gt;
&lt;span id=&quot;cb72-33&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-33&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ECase&lt;/span&gt; x hs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; eval env x &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb72-34&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-34&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVSum&lt;/span&gt; i y &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; indexRec i hs &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb72-35&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb72-35&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EHandler&lt;/span&gt; h &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; eval (&lt;span class=&quot;dt&quot;&gt;EVField&lt;/span&gt; y &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; env) h&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;At least, we are here. A type-safe EDSL where only AST’s that can be validly
evaluated are legal to represent in Haskell. At least, we can embrace the
freedom of not having to carefully construct your terms. You can relax now. The
compiler and the types have your back.&lt;/p&gt;
&lt;p&gt;Even
&lt;code&gt;EVFun :: (EValue a -&amp;gt; EValue b) -&amp;gt; EValue (a :-&amp;gt; b)&lt;/code&gt; has a
total &lt;code&gt;EValue a -&amp;gt; EValue b&lt;/code&gt;, making the closure evaluation also
fully total.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb73&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb73-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb73-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage4.hs#L145-L147&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb73-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb73-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb73-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb73-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;plusThree ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; '[] (&lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;TInt&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb73-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb73-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;plusThree &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb73-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb73-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  eLambda &lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; (eVar &lt;span class=&quot;st&quot;&gt;&quot;x&quot;&lt;/span&gt;) (&lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;)))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb74&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb74-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb74-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; eval &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt; plusThree &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb74-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb74-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;EVFun&lt;/span&gt; f &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; f (&lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;) &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb74-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb74-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;dt&quot;&gt;EVInt&lt;/span&gt; x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;print&lt;/span&gt; x&lt;/span&gt;
&lt;span id=&quot;cb74-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb74-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;pretty-printing-scoped-expressions&quot;&gt;Pretty-Printing Scoped
Expressions&lt;/h3&gt;
&lt;p&gt;Now to get to the entire utility of this abstraction: inspecting and
consuming the structure. For our new structure, we took out the string name from
&lt;code&gt;EVar&lt;/code&gt; in lieu of an index. This is intentional, so that we keep the
“responsibility” of storing the string name at the &lt;code&gt;ELambda&lt;/code&gt;
constructor and not have &lt;code&gt;EVar&lt;/code&gt; redundantly store it.&lt;/p&gt;
&lt;p&gt;However, this means that for pretty-printing, we will need to track the
variable names in the environment as we descend into lambdas. This is done very
similar to how it was done in &lt;code&gt;eval&lt;/code&gt;, but instead of tracking and
indexing out the evaluated &lt;code&gt;EValue&lt;/code&gt;s, we track and index out the
string names of each variable instead.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb75&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb75-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb75-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage4.hs#L182-L183&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb75-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb75-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb75-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb75-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;NameField&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;Symbol&lt;/span&gt;, &lt;span class=&quot;dt&quot;&gt;Ty&lt;/span&gt;) &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb75-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb75-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;NameField&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt; ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;KnownSymbol&lt;/span&gt; l &lt;span class=&quot;ot&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;NameField&lt;/span&gt; (l &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb76&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb76-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb76-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt;t &lt;span class=&quot;dt&quot;&gt;NameField&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;hello&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;NameField&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&quot;world&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb76-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb76-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;NameField&lt;/span&gt; [&lt;span class=&quot;st&quot;&gt;&quot;hello&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; a, &lt;span class=&quot;st&quot;&gt;&quot;world&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;:::&lt;/span&gt; b]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb77&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb77-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;-- source: https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage4.hs#L185-L245&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-3&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;ppPrim ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Prim&lt;/span&gt; t &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id=&quot;cb77-4&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppPrim &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-5&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;PInt&lt;/span&gt; n &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; PP.pretty n&lt;/span&gt;
&lt;span id=&quot;cb77-6&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;PBool&lt;/span&gt; b &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;if&lt;/span&gt; b &lt;span class=&quot;kw&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;true&quot;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;false&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-7&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;PString&lt;/span&gt; s &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; PP.pretty (&lt;span class=&quot;fu&quot;&gt;show&lt;/span&gt; s)&lt;/span&gt;
&lt;span id=&quot;cb77-8&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-9&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;ppOp ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Op&lt;/span&gt; a b c &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id=&quot;cb77-10&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppOp &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-11&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OPlus&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;+&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-12&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OTimes&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-13&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OLte&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&amp;lt;=&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-14&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;OAnd&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;&amp;amp;&amp;amp;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-15&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-16&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;ppFields ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;NameField&lt;/span&gt; vs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;ExprField&lt;/span&gt; vs) xs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann]&lt;/span&gt;
&lt;span id=&quot;cb77-17&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppFields _ &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; []&lt;/span&gt;
&lt;span id=&quot;cb77-18&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppFields names (&lt;span class=&quot;dt&quot;&gt;EField&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l x &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; xs) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-19&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  (PP.pretty (symbolVal (&lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l)) &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;=&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr names &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt; x) &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; ppFields names xs&lt;/span&gt;
&lt;span id=&quot;cb77-20&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-21&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;ppHandlers ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;NameField&lt;/span&gt; vs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; (&lt;span class=&quot;dt&quot;&gt;ExprHandler&lt;/span&gt; vs b) xs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; [&lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann]&lt;/span&gt;
&lt;span id=&quot;cb77-22&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppHandlers _ &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; []&lt;/span&gt;
&lt;span id=&quot;cb77-23&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppHandlers names (&lt;span class=&quot;dt&quot;&gt;EHandler&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;n &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l body &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; xs) &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-24&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ( PP.pretty (symbolVal (&lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l))&lt;/span&gt;
&lt;span id=&quot;cb77-25&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; PP.pretty (symbolVal (&lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;n))&lt;/span&gt;
&lt;span id=&quot;cb77-26&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-26&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;-&amp;gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-27&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-27&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr (&lt;span class=&quot;dt&quot;&gt;NameField&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;n &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; names) &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt; body&lt;/span&gt;
&lt;span id=&quot;cb77-28&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-28&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  )&lt;/span&gt;
&lt;span id=&quot;cb77-29&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-29&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; ppHandlers names xs&lt;/span&gt;
&lt;span id=&quot;cb77-30&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-30&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-31&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-31&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;ppExpr ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Rec&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;NameField&lt;/span&gt; vs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Bool&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; vs t &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id=&quot;cb77-32&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-32&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ppExpr names paren &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; \&lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-33&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-33&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EPrim&lt;/span&gt; p &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; ppPrim p&lt;/span&gt;
&lt;span id=&quot;cb77-34&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-34&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EVar&lt;/span&gt; i &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;case&lt;/span&gt; indexRec i names &lt;span class=&quot;kw&quot;&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-35&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-35&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;dt&quot;&gt;NameField&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;n &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; PP.pretty (symbolVal (&lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;n))&lt;/span&gt;
&lt;span id=&quot;cb77-36&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-36&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ELambda&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;n body &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-37&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-37&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    wrap &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-38&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-38&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;st&quot;&gt;&quot;\\&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; PP.pretty (symbolVal (&lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;n))&lt;/span&gt;
&lt;span id=&quot;cb77-39&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-39&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;-&amp;gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-40&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-40&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr (&lt;span class=&quot;dt&quot;&gt;NameField&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;n &lt;span class=&quot;op&quot;&gt;:&amp;amp;&lt;/span&gt; names) &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt; body&lt;/span&gt;
&lt;span id=&quot;cb77-41&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-41&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EApply&lt;/span&gt; f x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-42&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-42&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    wrap &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; ppExpr names &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; f &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr names &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; x&lt;/span&gt;
&lt;span id=&quot;cb77-43&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-43&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EOp&lt;/span&gt; o x y &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-44&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-44&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    wrap &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; ppExpr names &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; x &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppOp o &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr names &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; y&lt;/span&gt;
&lt;span id=&quot;cb77-45&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-45&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ERecord&lt;/span&gt; xs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-46&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-46&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    PP.encloseSep &lt;span class=&quot;st&quot;&gt;&quot;{ &quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot; }&quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;, &quot;&lt;/span&gt; (ppFields names xs)&lt;/span&gt;
&lt;span id=&quot;cb77-47&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-47&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EAccess&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l e _ &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-48&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-48&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    ppExpr names &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; e &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;.&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; PP.pretty (symbolVal (&lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l))&lt;/span&gt;
&lt;span id=&quot;cb77-49&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-49&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;EChoice&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l _ x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-50&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-50&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    wrap &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt; PP.pretty (symbolVal (&lt;span class=&quot;dt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;@&lt;/span&gt;l)) &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr names &lt;span class=&quot;dt&quot;&gt;True&lt;/span&gt; x&lt;/span&gt;
&lt;span id=&quot;cb77-51&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-51&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;dt&quot;&gt;ECase&lt;/span&gt; x hs &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-52&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-52&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    wrap &lt;span class=&quot;op&quot;&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-53&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-53&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      PP.sep&lt;/span&gt;
&lt;span id=&quot;cb77-54&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-54&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        [ &lt;span class=&quot;st&quot;&gt;&quot;case&quot;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr names &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt; x &lt;span class=&quot;op&quot;&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;of&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-55&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-55&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        , PP.encloseSep &lt;span class=&quot;st&quot;&gt;&quot;{ &quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot; }&quot;&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;; &quot;&lt;/span&gt; (ppHandlers names hs)&lt;/span&gt;
&lt;span id=&quot;cb77-56&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-56&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        ]&lt;/span&gt;
&lt;span id=&quot;cb77-57&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-57&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-58&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-58&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    wrap&lt;/span&gt;
&lt;span id=&quot;cb77-59&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-59&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; paren &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; PP.parens&lt;/span&gt;
&lt;span id=&quot;cb77-60&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-60&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;op&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;otherwise&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;id&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-61&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-61&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb77-62&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-62&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;prettyExpr ::&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Expr&lt;/span&gt; '[] t &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id=&quot;cb77-63&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb77-63&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;prettyExpr &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ppExpr &lt;span class=&quot;dt&quot;&gt;RNil&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;False&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb78&quot;&gt;&lt;pre class=&quot;sourceCode haskell&quot;&gt;&lt;code class=&quot;sourceCode haskell&quot;&gt;&lt;span id=&quot;cb78-1&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb78-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;ghci&lt;span class=&quot;op&quot;&gt;&amp;gt;&lt;/span&gt; prettyExpr fifteen&lt;/span&gt;
&lt;span id=&quot;cb78-2&quot;&gt;&lt;a href=&quot;http://feeds.feedburner.com/incodeblog#cb78-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;(\x &lt;span class=&quot;ot&quot;&gt;-&amp;gt;&lt;/span&gt; x &lt;span class=&quot;op&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;) &lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;the-next-step&quot;&gt;The Next Step&lt;/h2&gt;
&lt;p&gt;Well, we set out with a simple goal: an expression language that lives within
Haskell that we can inspect and interrogate within the language, but where it
was impossible to construct (in Haskell) a term that did not type-check (in the
domain language).&lt;/p&gt;
&lt;p&gt;But, honestly, why does it matter that our expression language has to reject
invalid domain-level terms at the Haskell level? Why couldn’t we go the way of
other expression DSLs in Haskell, where we settle with “untyped” terms being
expressible in Haskell, and validated using a separate &lt;code&gt;typeCheck&lt;/code&gt;
function to validate terms at runtime?&lt;/p&gt;
&lt;p&gt;I don’t know. But really, maybe this is another way of taking the old &lt;a href=&quot;https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/&quot;&gt;Parse,
Don’t Validate&lt;/a&gt; adage to the extreme. Why allow yourself to construct invalid
terms of your domain inside Haskell? Why use a “validate” function
(&lt;code&gt;isValid&lt;/code&gt;) when you can just make invalid terms impossible to
construct?&lt;/p&gt;
&lt;p&gt;But…no. There is no other choice. We CANNOT allow invalid domain terms to be
constructible. If we have the ability to do better, we MUST. With great power
comes great responsibility. And if we compromise here, how can we trust
ourselves not to compromise when it really matters?&lt;/p&gt;
&lt;p&gt;One must imagine the stubborn typer happy.&lt;/p&gt;
&lt;p&gt;In Part 2, we’ll use our new EDSL to specify visualizable state machines and
programs within Haskell that are type-checked to be correct, and what it looks
like to actually &lt;em&gt;use&lt;/em&gt; these within Haskell. And in Part 3, we’ll start
“compiling” them to different language targets and different backends, with the
assurance that our generated programs are all synchronized and
self-consistent.&lt;/p&gt;
&lt;h3 id=&quot;a-note-on-ai-coding&quot;&gt;A Note on AI Coding&lt;/h3&gt;
&lt;p&gt;I guess I’m going to have to start mentioning this in every post.
&lt;em&gt;But&lt;/em&gt;, I really do feel like this “extreme type safety” approach is more
critical than ever, in the age of agentic coding and LLM. I’ve been using LLMs
in my daily coding for many months now at this point, and one common pattern
I’ve noticed: when I start with a design with very clear, very strict types,
LLMs excel. They make much fewer errors, and the type system provides more
immediate feedback on their progress, without needing hundreds of defensive
&lt;code&gt;x != null&lt;/code&gt;-style guard pollution.&lt;/p&gt;
&lt;p&gt;Once I can express what I want in the language of extreme “invalid states
unrepresentable” types, LLM agents no longer feel like agents of chaotic
spaghetti extruding unmaintainable code. Instead, it feels like…seeding a
crystal and watching it grow into a beautiful, shimmering lattice. It feels like
the language they yearn to speak. And the more expressive your types, the more
beautiful the crystalline structure in the end.&lt;/p&gt;
&lt;p&gt;Honestly, humans might have problems writing and using this code, but LLMs
definitely don’t, if properly scaffolded! Since early 2026, at least, for me.
We’ll explore a bit more about this once we have more to work with in Part
2.&lt;/p&gt;
&lt;h2 id=&quot;special-thanks&quot;&gt;Special Thanks&lt;/h2&gt;
&lt;p&gt;I am very humbled to be supported by an amazing community, who make it
possible for me to devote time to researching and writing these posts. Very
special thanks to my supporter at the “Amazing” level on &lt;a href=&quot;https://www.patreon.com/justinle/overview&quot;&gt;patreon&lt;/a&gt;, Josh Vera! :)&lt;/p&gt;
&lt;section class=&quot;footnotes footnotes-end-of-document&quot; id=&quot;footnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;&lt;p&gt;Excluding &lt;code&gt;_|_&lt;/code&gt; in Haskell-land (recursion or
&lt;code&gt;undefined&lt;/code&gt;), unfortunately.&lt;a class=&quot;footnote-back&quot; href=&quot;http://feeds.feedburner.com/incodeblog#fnref1&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description>
	<pubDate>Tue, 07 Jul 2026 17:11:34 +0000</pubDate>
</item>
<item>
	<title>Gabriella Gonzalez: Mechanized type inference for record concatenation</title>
	<guid isPermaLink="true">https://haskellforall.com/2026/07/mechanized-type-inference-for-record-concatenation</guid>
	<link>https://haskellforall.com/2026/07/mechanized-type-inference-for-record-concatenation</link>
	<description>Type inference algorithm for biased record concatenation</description>
	<pubDate>Tue, 07 Jul 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Joey Hess: no LLM code in dependencies</title>
	<guid isPermaLink="true">http://joeyh.name/blog/entry/no_LLM_code_in_dependencies/</guid>
	<link>http://joeyh.name/blog/entry/no_LLM_code_in_dependencies/</link>
	<description>&lt;p&gt;I've spent about 100 hours of work over the past month to make sure
git-annex can build without dependencies that contain LLM generated code.
At least so far.&lt;/p&gt;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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



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



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



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



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



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

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

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

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

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

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

&lt;a href=&quot;https://share.joinmastodon.org/#text=Proving the Fundamental Theorem of Arithmetic in Agda https://byorgey.github.io/blog/posts/2026/06/26/FTA.lagda.html&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Share on &lt;/a&gt;
&lt;section&gt;
&lt;p&gt;&lt;strong&gt;tl;dr&lt;/strong&gt;: This is a fully commentated, from-scratch proof of the
Fundamental Theorem of Arithmetic in
&lt;a href=&quot;https://wiki.portal.chalmers.se/agda/pmwiki.php?n=Main.HomePage&quot;&gt;Agda&lt;/a&gt;,
intended for those who already know a bit of Agda but might benefit
from reading and working through a larger example. See the
Introduction and the &lt;a href=&quot;https://byorgey.github.io/blog/rss#table-of-contents&quot;&gt;Table of Contents&lt;/a&gt; below for more details.&lt;/p&gt;
&lt;section class=&quot;level2&quot; id=&quot;introduction&quot;&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Earlier this spring, I was idly brainstorming potential final projects
for my &lt;a href=&quot;https://hendrix-cs.github.io/csci365/&quot;&gt;Functional Programming&lt;/a&gt;
students. Having just &lt;a href=&quot;http://ozark.hendrix.edu/~yorgey/forest/00EG/index.xml&quot;&gt;taught my Discrete Math students the
Fundamental Theorem of
Arithmetic&lt;/a&gt;, I
wondered whether formalizing&lt;span class=&quot;sidenote-wrapper&quot;&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;sn-0&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;sn-0&quot; type=&quot;checkbox&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;I mean formalizing it &lt;em&gt;from scratch&lt;/em&gt;: of
course, the FTA is &lt;a href=&quot;https://agda.github.io/agda-stdlib/v2.3/Data.Nat.Primality.Factorisation.html&quot;&gt;already in the Agda standard library&lt;/a&gt;. As I later
learned, it was added to the standard library by &lt;a href=&quot;https://github.com/Taneb&quot;&gt;Nathan van Doorn,
aka Taneb&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt; it in
&lt;a href=&quot;https://wiki.portal.chalmers.se/agda/pmwiki.php?n=Main.HomePage&quot;&gt;Agda&lt;/a&gt;
could make a nice project.&lt;/p&gt;
&lt;p&gt;So I decided to spend about an hour trying to prove it in Agda,
to gauge the level of the project. At the end of an hour, I had
learned two things: (1) proving the Fundamental Theorem of Arithmetic is &lt;em&gt;not&lt;/em&gt; an appropriate project for
my students (who had only had a few weeks’ practice with Agda); (2) I
was not going to be able to stop until I finished the proof myself!&lt;/p&gt;
&lt;p&gt;Over the next week or so, I finished the proof completely from
scratch—without using anything from the standard library, and without
looking up any reference material. I based it only on my experience
in Agda, knowledge of the relevant proofs on an informal level, and
Agda techniques I’ve picked up along the way (from &lt;em&gt;e.g.&lt;/em&gt; Conor McBride, Jacques
Carette, colleagues at Penn, and elsewhere).&lt;/p&gt;
&lt;p&gt;I decided to publish the proof, with extra commentary, in the hopes
that it can be useful as an intermediate-level reference. That is,
perhaps you’ve learned some basic Agda (if not, I suggest &lt;a href=&quot;https://agda.readthedocs.io/en/latest/getting-started/a-taste-of-agda.html&quot;&gt;this
tutorial to
start&lt;/a&gt;)
and have some basic familiarity
with the Curry-Howard correspondence, but would benefit from seeing an
example of a fully worked out, medium-sized proof.&lt;span class=&quot;sidenote-wrapper&quot;&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;sn-1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;sn-1&quot; type=&quot;checkbox&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;Another good
source of information along these lines is &lt;a href=&quot;https://jesper.sikanda.be/posts/formalize-all-the-things.html&quot;&gt;this post by Jesper
Cockx&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt; The resulting blog
post is extremely long, but I make no apologies for that—if you want
an entertaining 5-minute read, you should look elsewhere!&lt;/p&gt;
&lt;p&gt;The entire blog post and proof is &lt;a href=&quot;https://github.com/byorgey/blog/blob/main/posts/2026/06/26/FTA.lagda.md&quot;&gt;available as a literate Agda
document&lt;/a&gt;. &lt;strong&gt;Even better, I have also published &lt;a href=&quot;http://ozark.hendrix.edu/~yorgey/pub/FTA-holes.lagda.md&quot;&gt;another version of this
blog post with holes in place of almost all the proofs&lt;/a&gt;.&lt;/strong&gt; For a
maximal learning experience, I suggest downloading it and trying to
fill in the holes yourself as you go along.&lt;/p&gt;
&lt;p&gt;Below is a table of contents. Depending on your background, you may
of course choose to skip some sections. For example, if you have
already had a good deal of practice dealing with basic natural number
arithmetic, equality, and inequality in Agda, you might wish to skip
over those sections.&lt;/p&gt;
&lt;/section&gt;
&lt;section class=&quot;level2&quot; id=&quot;table-of-contents&quot;&gt;
&lt;h2&gt;Table of Contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#half-of-the-fundamental-theorem-of-arithmetic-constructively&quot;&gt;(Half of) The Fundamental Theorem of Arithmetic (Constructively)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#preliminaries&quot;&gt;Preliminaries&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#basic-logic&quot;&gt;Basic logic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#equality&quot;&gt;Equality&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#natural-numbers&quot;&gt;Natural numbers&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#no-confusion&quot;&gt;No confusion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#decidable-equality&quot;&gt;Decidable equality&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#addition&quot;&gt;Addition&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#multiplication&quot;&gt;Multiplication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#inequality&quot;&gt;Inequality&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#relationships-among-equality-and-inequality&quot;&gt;Relationships among equality and inequality&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#arithmetic-and-inequality&quot;&gt;Arithmetic and inequality&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#divisibility-primes-and-composites&quot;&gt;Divisibility, primes, and composites&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#nontrivial-divisors-come-in-pairs&quot;&gt;Nontrivial divisors come in pairs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#division&quot;&gt;Division&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#absolute-difference&quot;&gt;Absolute difference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#quotient-and-remainder-are-unique&quot;&gt;Quotient and remainder are unique&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#the-division-algorithm-take-1&quot;&gt;The division algorithm, take 1&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#construct-the-evidence-you-would-like-to-pattern-match-on&quot;&gt;Construct the evidence you would like to pattern-match on&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#well-founded-induction&quot;&gt;Well-founded induction&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#accessibility&quot;&gt;Accessibility&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#well-founded-induction-defined&quot;&gt;Well-founded induction, defined&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#less-than-is-well-founded&quot;&gt;Less-than is well-founded&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#the-division-algorithm&quot;&gt;The division algorithm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#primality-testing&quot;&gt;Primality testing&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#counting-up&quot;&gt;Counting up&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#primality-testing-by-trial-division&quot;&gt;Primality testing by trial division&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#lists&quot;&gt;Lists&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#the-fundamental-theorem-of-arithmetic&quot;&gt;The Fundamental Theorem of Arithmetic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#further-directions&quot;&gt;Further Directions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section class=&quot;level2&quot; id=&quot;half-of-the-fundamental-theorem-of-arithmetic-constructively&quot;&gt;
&lt;h2&gt;(Half of) The Fundamental Theorem of Arithmetic (Constructively)&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://en.wikipedia.org/wiki/Fundamental_theorem_of_arithmetic&quot;&gt;Fundamental Theorem of
Arithmetic&lt;/a&gt;
(&lt;em&gt;FTA&lt;/em&gt; for short) states that any natural number &lt;span class=&quot;math inline&quot;&gt;\(n \geq 1\)&lt;/span&gt; can be
written as a product of zero or more primes, and moreover that this
product is unique up to permutation.&lt;/p&gt;
&lt;p&gt;For now, we are only going to prove the &lt;em&gt;existence&lt;/em&gt; part (I may write
another blog post with the uniqueness proof later). Since a &lt;em&gt;constructive&lt;/em&gt;
existence proof is really an algorithm for constructing the thing that
is claimed to exist, this can also be seen as a &lt;em&gt;formally verified
factorization program&lt;/em&gt;: put any number in, get a prime factorization
out. Writing a prime factorization program is not hard, of course;
it’s the formal verification part that is interesting!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Stop!&lt;/strong&gt; Before reading on, if you want to get the most out of this tutorial, I
&lt;strong&gt;strongly recommend &lt;a href=&quot;http://ozark.hendrix.edu/~yorgey/pub/FTA-holes.lagda.md&quot;&gt;downloading the version with
holes&lt;/a&gt;&lt;/strong&gt;
and trying to complete as many of the proofs as you can before reading mine!&lt;/p&gt;
&lt;/section&gt;
&lt;section class=&quot;level2&quot; id=&quot;preliminaries&quot;&gt;
&lt;h2&gt;Preliminaries&lt;/h2&gt;
&lt;p&gt;We will often make use of &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;B&lt;/code&gt; to stand for arbitrary
sets/types, so we use a &lt;code&gt;variable&lt;/code&gt; declaration to tell Agda that it
should implicitly quantify them whenever they show up as free
variables. That way we don’t have to write &lt;code&gt;{A B : Set} → ...&lt;/code&gt; all the time.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb1-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;variable&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb1-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  A B &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;level2&quot; id=&quot;basic-logic&quot;&gt;
&lt;h2&gt;Basic logic&lt;/h2&gt;
&lt;p&gt;Since we’re building this completely from scratch, we start with some
types to represent basic logical building blocks (via the
&lt;a href=&quot;https://en.wikipedia.org/wiki/Curry%E2%80%93Howard_correspondence&quot;&gt;Curry-Howard correspondence&lt;/a&gt;). First, the “top” type &lt;code&gt;⊤&lt;/code&gt; to stand for truth, &lt;em&gt;i.e.&lt;/em&gt; a proposition with trivial evidence:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb2-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb2-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; ⊤ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb2-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  tt &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ⊤&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;tt&lt;/code&gt; is declared to be the one and only value of type &lt;code&gt;⊤&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Note that some things we define here—such as &lt;code&gt;⊤&lt;/code&gt;—will have the same
names as they do in the &lt;a href=&quot;https://agda.github.io/agda-stdlib/v2.3/&quot;&gt;Agda standard library&lt;/a&gt;. However, many things
won’t, since I either didn’t know the standard name and made up my
own, or (in a few cases) did know the standard name but didn’t like
it, and made up my own anyway.&lt;/p&gt;
&lt;p&gt;Next, the “bottom” type &lt;code&gt;⊥&lt;/code&gt; with no constructors, representing
falsity, along with a corresponding elimination principle, &lt;code&gt;absurd&lt;/code&gt;. The elimination
principle says that anything follows from &lt;code&gt;⊥&lt;/code&gt; (“&lt;em&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Principle_of_explosion&quot;&gt;ex falso
quodlibet&lt;/a&gt;&lt;/em&gt;”), and is implemented using Agda’s absurd pattern,
written &lt;code&gt;()&lt;/code&gt;. If Agda can tell that there are no possible
constructors which could give rise to a value of a certain type, we
can pattern-match on it with &lt;code&gt;()&lt;/code&gt;, and are absolved of providing a right-hand side for the definition in that case.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb3&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb3-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb3-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; ⊥ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb3-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb3-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;absurd &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ⊥ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; A&lt;/span&gt;
&lt;span id=&quot;cb3-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb3-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;absurd &lt;span class=&quot;ot&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can now define negation as an implication to &lt;code&gt;⊥&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb4&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb4-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb4-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;¬ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb4-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb4-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;¬ P &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; P &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ⊥&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Dependent pairs are next: a pair of values where the &lt;em&gt;type&lt;/em&gt; of the
second component can depend on the &lt;em&gt;value&lt;/em&gt; of the first. That is, a value of type &lt;code&gt;Σ A B&lt;/code&gt; is a value &lt;code&gt;a&lt;/code&gt; of type
&lt;code&gt;A&lt;/code&gt; paired with a value of type &lt;code&gt;B a&lt;/code&gt;. Via Curry-Howard, this is used
to represent existential quantification: a (constructive) proof of
&lt;span class=&quot;math inline&quot;&gt;\(\exists a : A.\; B(a)\)&lt;/span&gt; is a value &lt;span class=&quot;math inline&quot;&gt;\(a\)&lt;/span&gt; of type &lt;span class=&quot;math inline&quot;&gt;\(A\)&lt;/span&gt; (the &lt;em&gt;witness&lt;/em&gt;)
paired with a proof that &lt;span class=&quot;math inline&quot;&gt;\(a\)&lt;/span&gt; has property &lt;span class=&quot;math inline&quot;&gt;\(B\)&lt;/span&gt; (&lt;em&gt;i.e.&lt;/em&gt; a value of type &lt;span class=&quot;math inline&quot;&gt;\(B(a)\)&lt;/span&gt;).&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb5&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb5-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb5-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;infixr&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;,&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb5-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; Σ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;A &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;B &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb5-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;,&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;a &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; B a &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Σ A B&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We also define a projection function (we only end up needing &lt;code&gt;fst&lt;/code&gt;;
defining &lt;code&gt;snd&lt;/code&gt; is left as an exercise for the reader&lt;span class=&quot;sidenote-wrapper&quot;&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;sn-2&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;sn-2&quot; type=&quot;checkbox&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;The &lt;em&gt;definition&lt;/em&gt;
of &lt;code&gt;snd&lt;/code&gt; is trivial; writing down its &lt;em&gt;type&lt;/em&gt; is a worthwhile
exercise.&lt;br /&gt;
&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt;), along with a type of non-dependent pairs, corresponding
to logical conjunction (and).&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb6&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb6-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb6-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;fst &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;∀&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;A B&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Σ A B &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; A&lt;/span&gt;
&lt;span id=&quot;cb6-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb6-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;fst &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;a , &lt;span class=&quot;ot&quot;&gt;_)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; a&lt;/span&gt;
&lt;span id=&quot;cb6-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb6-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb6-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;infixr&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;×&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb6-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;×&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;A B &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb6-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;A × B &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; Σ A &lt;span class=&quot;ot&quot;&gt;(λ&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; B&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally, we define a disjoint (tagged) union type corresponding to
logical disjunction (or).&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb7&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb7-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb7-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;infixr&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;⊎&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb7-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;⊎&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;A B &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb7-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  inj₁ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; A ⊎ B&lt;/span&gt;
&lt;span id=&quot;cb7-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb7-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  inj₂ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; B &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; A ⊎ B&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;level2&quot; id=&quot;equality&quot;&gt;
&lt;h2&gt;Equality&lt;/h2&gt;
&lt;p&gt;Next, we write down the standard equality (&lt;em&gt;aka&lt;/em&gt; identity, &lt;em&gt;aka&lt;/em&gt; path) type, with a single
constructor &lt;code&gt;refl&lt;/code&gt; that witnesses when its two arguments are
identical.&lt;span class=&quot;sidenote-wrapper&quot;&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;sn-3&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;sn-3&quot; type=&quot;checkbox&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;It still seems somewhat magical to me that this seemingly
too-simple definition encapsulates everything we want in an equality
relation (well, &lt;a href=&quot;https://martinescardo.github.io/TypeTopology/UnivalenceFromScratch.html&quot;&gt;almost everything&lt;/a&gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt; We also define a convenient
synonym for inequality.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb8&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb8-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb8-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;infix&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≡&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb8-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≡&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;a &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb8-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  refl &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; a ≡ a&lt;/span&gt;
&lt;span id=&quot;cb8-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb8-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb8-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≢&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; A &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb8-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb8-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;x ≢ y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ¬ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x ≡ y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Besides reflexivity, equality enjoys various properties that we will
need: symmetry, transitivity, and congruence (&lt;em&gt;i.e.&lt;/em&gt;, we can apply any
function to both sides of an equation).&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb9&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb9-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb9-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sym &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≡ y &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; y ≡ x&lt;/span&gt;
&lt;span id=&quot;cb9-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb9-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sym refl &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb9-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb9-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb9-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;trans &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≡ y &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; y ≡ z &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≡ z&lt;/span&gt;
&lt;span id=&quot;cb9-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb9-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;trans refl y≡z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; y≡z&lt;/span&gt;
&lt;span id=&quot;cb9-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb9-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb9-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;cong &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;f &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; B&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≡ y &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; f x ≡ f y&lt;/span&gt;
&lt;span id=&quot;cb9-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb9-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;cong &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; refl &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Since we will spend a good amount of time reasoning about equality, it
is worthwhile building up some machinery for writing more readable
equality proofs. Instead of writing, say,&lt;/p&gt;
&lt;pre class=&quot;text&quot;&gt;&lt;code&gt;trans p (trans q (trans (sym r) s))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;we will be able to instead write equality proofs like so:&lt;/p&gt;
&lt;pre class=&quot;text&quot;&gt;&lt;code&gt;begin
  v      ≡[ p ⟩≡
  w      ≡[ q ⟩≡
  x      ≡⟨ r ]≡
  y      ≡[ s ⟩≡
  z      ∎&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The intention is that this proof shows &lt;code&gt;v ≡ z&lt;/code&gt;, by first using &lt;code&gt;p&lt;/code&gt; to
show that &lt;code&gt;v ≡ w&lt;/code&gt;, then &lt;code&gt;q&lt;/code&gt; to show &lt;code&gt;w ≡ x&lt;/code&gt;, and so on. This notation
is one of my favorite applications of Agda’s &lt;a href=&quot;https://agda.readthedocs.io/en/latest/language/mixfix-operators.html&quot;&gt;mixfix operator
syntax&lt;/a&gt;,
and has several benefits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We can avoid nested parentheses when chaining uses of transitivity.&lt;/li&gt;
&lt;li&gt;We can automatically apply symmetry by using a left-pointing
instead of right-pointing operator.&lt;/li&gt;
&lt;li&gt;We get to explicitly mention (and have Agda check for us) all the
intermediate values, making it easier to write the proof
incrementally, and much easier for humans to read.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is one of the places where I deliberately chose different
operator names than the standard library, which uses &lt;code&gt;_≡⟨_⟩_&lt;/code&gt; and
&lt;code&gt;_≡⟨_⟨_&lt;/code&gt;. The operator names I decided to use are &lt;a href=&quot;https://personal.cis.strath.ac.uk/conor.mcbride/PolyTest.pdf&quot;&gt;inspired by Conor
McBride&lt;/a&gt;. I just like the way they look better.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb12&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb12-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb12-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;infix&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt; begin&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb12-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;begin&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≡ y &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≡ y&lt;/span&gt;
&lt;span id=&quot;cb12-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb12-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;begin x≡y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; x≡y&lt;/span&gt;
&lt;span id=&quot;cb12-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb12-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb12-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;infixr&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≡[&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;⟩≡&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb12-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≡[&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;⟩≡&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;y z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x ≡ y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y ≡ z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x ≡ z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb12-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ≡[ x≡y ⟩≡ y≡z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; trans x≡y y≡z&lt;/span&gt;
&lt;span id=&quot;cb12-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb12-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-9&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb12-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;infixr&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≡⟨&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;]≡&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-10&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb12-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≡⟨&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;]≡&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;y z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y ≡ x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y ≡ z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x ≡ z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-11&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb12-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ≡⟨ y≡x ]≡ y≡z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sym y≡x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; y≡z&lt;/span&gt;
&lt;span id=&quot;cb12-12&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb12-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb12-13&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb12-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;infixr&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;∎&lt;/span&gt;
&lt;span id=&quot;cb12-14&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb12-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;∎ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≡ x&lt;/span&gt;
&lt;span id=&quot;cb12-15&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb12-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ∎ &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally, a few &lt;a href=&quot;https://hackage-content.haskell.org/package/base-4.22.0.0/docs/Prelude.html#t:Applicative&quot;&gt;Applicative&lt;/a&gt;-like operators for more conveniently
writing common forms of congruence. For example, instead of writing
&lt;code&gt;cong f x≡y&lt;/code&gt;, we can write &lt;code&gt;f $≡ x≡y&lt;/code&gt;; or to use congruence on both
arguments of a two-place function at once, we can write &lt;code&gt;f $≡ x≡y ≡$≡ z≡w&lt;/code&gt;. (These operators were also inspired by Conor.)&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb13&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb13-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb13-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;infixl&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;$≡&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb13-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;$≡&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;f &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; B&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≡ y &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; f x ≡ f y&lt;/span&gt;
&lt;span id=&quot;cb13-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb13-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;f $≡ x≡y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; cong f x≡y&lt;/span&gt;
&lt;span id=&quot;cb13-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb13-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb13-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;infixl&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≡$&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb13-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≡$&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;f g &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; B&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; f ≡ g &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; f x ≡ g x&lt;/span&gt;
&lt;span id=&quot;cb13-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb13-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;f≡g ≡$ x &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; cong &lt;span class=&quot;ot&quot;&gt;(λ&lt;/span&gt; h &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; h x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; f≡g&lt;/span&gt;
&lt;span id=&quot;cb13-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb13-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-9&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb13-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;infixl&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≡$≡&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb13-10&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb13-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≡$≡&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;f g &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; B&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; f ≡ g &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≡ y &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; f x ≡ g y&lt;/span&gt;
&lt;span id=&quot;cb13-11&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb13-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;f≡g ≡$≡ x≡y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;f≡g ≡$ &lt;span class=&quot;ot&quot;&gt;_)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(_&lt;/span&gt; $≡ x≡y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;level2&quot; id=&quot;natural-numbers&quot;&gt;
&lt;h2&gt;Natural numbers&lt;/h2&gt;
&lt;p&gt;Of course, we will need a type to represent the natural numbers. We
can also tell Agda that our natural number type should correspond to its
built-in notion of natural numbers, so we can use numeric literals
like &lt;code&gt;2 : ℕ&lt;/code&gt; instead of having to write &lt;code&gt;suc (suc zero)&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb14&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb14-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb14-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb14-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb14-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  zero &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;/span&gt;
&lt;span id=&quot;cb14-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb14-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  suc &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ℕ&lt;/span&gt;
&lt;span id=&quot;cb14-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb14-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;pp&quot;&gt;{-# BUILTIN NATURAL ℕ #-}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;section class=&quot;level3&quot; id=&quot;no-confusion&quot;&gt;
&lt;h3&gt;No confusion&lt;/h3&gt;
&lt;p&gt;For our natural number type—and often, for any algebraic data type—we
need to know that the constructors are&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;&lt;em&gt;disjoint&lt;/em&gt;, meaning that different constructors always generate
different values (so it’s a contradiction to have an equality
between values built with different constructors); and&lt;/li&gt;
&lt;li&gt;&lt;em&gt;injective&lt;/em&gt;, meaning that if we have an equality between values built
with the same constructor, we can decompose it into equalities between
the components.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We can prove both of these simultaneously using a property called “no
confusion”. This property and its name is well-known in the
literature; for example, see
&lt;a href=&quot;http://strictlypositive.org/concon.ps.gz&quot;&gt;McBridge&lt;/a&gt; or &lt;a href=&quot;https://link.springer.com/chapter/10.1007/3-540-61780-9_64&quot;&gt;Cornes +
Terrasse&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For natural numbers &lt;code&gt;m&lt;/code&gt; and &lt;code&gt;n&lt;/code&gt;, the type &lt;code&gt;NoConf m n&lt;/code&gt; should be
thought of as the type of evidence that &lt;code&gt;m ≡ n&lt;/code&gt;, based on looking at
the top-level constructors of &lt;code&gt;m&lt;/code&gt; and &lt;code&gt;n&lt;/code&gt;. If &lt;code&gt;m&lt;/code&gt; and &lt;code&gt;n&lt;/code&gt; have different
constructors, then no evidence can possibly show that they are equal,
so &lt;code&gt;NoConf m n = ⊥&lt;/code&gt; in that case. If &lt;code&gt;m&lt;/code&gt; and &lt;code&gt;n&lt;/code&gt; are both zero, then
they are evidently equal, so &lt;code&gt;NoConf 0 0 = ⊤&lt;/code&gt;. Otherwise, if &lt;code&gt;m&lt;/code&gt; and
&lt;code&gt;n&lt;/code&gt; are both successors, &lt;code&gt;NoConf m n&lt;/code&gt; reduces to a proof of equality
between their predecessors.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb15&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb15-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb15-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;NoConf &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb15-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb15-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;NoConf zero zero &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ⊤&lt;/span&gt;
&lt;span id=&quot;cb15-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb15-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;NoConf zero &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ⊥&lt;/span&gt;
&lt;span id=&quot;cb15-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb15-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;NoConf &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc m&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; zero &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ⊥&lt;/span&gt;
&lt;span id=&quot;cb15-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb15-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;NoConf &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc m&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; m ≡ n&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we can prove the no confusion lemma for our natural number type,
which says that &lt;code&gt;NoConf m n&lt;/code&gt; always holds whenever &lt;code&gt;m ≡ n&lt;/code&gt;.
Since &lt;code&gt;m ≡ n&lt;/code&gt;, we only have to deal with the cases when &lt;code&gt;m&lt;/code&gt; and &lt;code&gt;n&lt;/code&gt;
are both zero or both a successor—but this also justifies assigning a
type of &lt;code&gt;⊥&lt;/code&gt; to the cases when the constructors do not match. &lt;code&gt;noConf&lt;/code&gt;
can therefore be used to strip &lt;code&gt;suc&lt;/code&gt; from both sides of an equation,
&lt;em&gt;or&lt;/em&gt; to derive a contradiction when we have an equation between
non-matching constructors.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb16&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb16-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb16-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;noConf &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;m n &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; m ≡ n &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; NoConf m n&lt;/span&gt;
&lt;span id=&quot;cb16-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb16-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;noConf &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;zero&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; refl &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; tt&lt;/span&gt;
&lt;span id=&quot;cb16-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb16-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;noConf &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc m&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; refl &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As an aside, this definition of the no confusion property uses a
technique I like: defining a &lt;em&gt;type&lt;/em&gt; starting with a capital letter,
then defining a &lt;em&gt;term&lt;/em&gt; that returns that type starting with a
lowercase letter. This pattern will come up again later. Sometimes
we define named types in this way just for convenience, say, to be
able to refer to the type multiple times in a concise way; or, as in
the above case, sometimes the type is actually defined via some
nontrivial computation.&lt;/p&gt;
&lt;/section&gt;
&lt;section class=&quot;level3&quot; id=&quot;decidable-equality&quot;&gt;
&lt;h3&gt;Decidable equality&lt;/h3&gt;
&lt;p&gt;We can now show how to decide equality of natural numbers. We first
define a simple type representing decidability in general: &lt;code&gt;Dec P&lt;/code&gt; represents
either a proof of &lt;code&gt;P&lt;/code&gt;, or a proof of &lt;code&gt;¬ P&lt;/code&gt;.&lt;span class=&quot;sidenote-wrapper&quot;&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;sn-4&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;sn-4&quot; type=&quot;checkbox&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;You may be aware that the
&lt;a href=&quot;https://en.wikipedia.org/wiki/Law_of_excluded_middle&quot;&gt;law of excluded middle&lt;/a&gt;, which
says that &lt;span class=&quot;math inline&quot;&gt;\(P \lor \neg P\)&lt;/span&gt; for all propositions &lt;span class=&quot;math inline&quot;&gt;\(P\)&lt;/span&gt;, is rejected in constructive logic. However, even
though &lt;span class=&quot;math inline&quot;&gt;\(P \lor \neg P\)&lt;/span&gt; does not hold for &lt;em&gt;all&lt;/em&gt; &lt;span class=&quot;math inline&quot;&gt;\(P\)&lt;/span&gt;, it can still hold
for certain specific propositions. Propositions &lt;span class=&quot;math inline&quot;&gt;\(P\)&lt;/span&gt; for which &lt;span class=&quot;math inline&quot;&gt;\(P \lor
\neg P\)&lt;/span&gt; holds constructively are called &lt;em&gt;decidable&lt;/em&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt; (The &lt;a href=&quot;https://agda.github.io/agda-stdlib/v2.3/Relation.Nullary.Decidable.Core.html#1966&quot;&gt;standard library
version is much more sophisticated&lt;/a&gt;, but this simple version will do
just fine.)&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb17&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb17-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb17-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; Dec &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;P &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb17-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb17-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  yes &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; P &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Dec P&lt;/span&gt;
&lt;span id=&quot;cb17-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb17-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  no &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ¬ P &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Dec P&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can then prove that for any natural numbers &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt;, we can decide
whether &lt;code&gt;x ≡ y&lt;/code&gt;. Notice the several different uses of the no
confusion lemma: two to handle impossible situations, and one to strip
&lt;code&gt;suc&lt;/code&gt; off both sides of an equality.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb18&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb18-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb18-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≟&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Dec &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x ≡ y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb18-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb18-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;zero ≟ zero &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; yes refl&lt;/span&gt;
&lt;span id=&quot;cb18-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb18-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;zero ≟ suc y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; no noConf&lt;/span&gt;
&lt;span id=&quot;cb18-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb18-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;suc x ≟ zero &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; no noConf&lt;/span&gt;
&lt;span id=&quot;cb18-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb18-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;suc x ≟ suc y &lt;span class=&quot;kw&quot;&gt;with&lt;/span&gt; x ≟ y&lt;/span&gt;
&lt;span id=&quot;cb18-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb18-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;|&lt;/span&gt; yes x≡y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; yes &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc $≡ x≡y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb18-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb18-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;|&lt;/span&gt; no x≢y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; no &lt;span class=&quot;ot&quot;&gt;(λ&lt;/span&gt; sx≡sy &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x≢y &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;noConf sx≡sy&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section class=&quot;level2&quot; id=&quot;addition&quot;&gt;
&lt;h2&gt;Addition&lt;/h2&gt;
&lt;p&gt;We next turn to defining addition (by pattern-matching on the
left-hand argument), along with several properties of
addition we will need: zero is a right identity for addition; we can
pull out a &lt;code&gt;suc&lt;/code&gt; from the right-hand argument; and addition is
commutative, associative, and left-cancellable.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb19&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb19-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;infixl&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;+&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;+&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ℕ&lt;/span&gt;
&lt;span id=&quot;cb19-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;zero + y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; y&lt;/span&gt;
&lt;span id=&quot;cb19-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;suc x + y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; suc &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x + y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;+0 &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n + &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; ≡ n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;zero +0 &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb19-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; +0 &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; suc $≡ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n +0&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-9&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-10&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;+suc&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x + suc y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; ≡ suc &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x + y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-11&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;zero +suc y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb19-12&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; +suc y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; suc $≡ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x +suc y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-13&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-14&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;+-comm &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x + y ≡ y + x&lt;/span&gt;
&lt;span id=&quot;cb19-15&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;+-comm zero y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sym &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y +0&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-16&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;+-comm &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc $≡ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;+-comm x y&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sym &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y +suc x&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-17&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-18&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;+-assoc &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x y z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x + y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; + z ≡ x + &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y + z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-19&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;+-assoc zero y z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb19-20&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;+-assoc &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; y z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; suc $≡ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;+-assoc x y z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-21&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb19-22&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;+-cancelˡ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x y z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x + y ≡ x + z &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; y ≡ z&lt;/span&gt;
&lt;span id=&quot;cb19-23&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;+-cancelˡ zero y z x+y≡x+z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; x+y≡x+z&lt;/span&gt;
&lt;span id=&quot;cb19-24&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb19-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;+-cancelˡ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; y z x+y≡x+z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; +-cancelˡ x y z &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;noConf x+y≡x+z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;level2&quot; id=&quot;multiplication&quot;&gt;
&lt;h2&gt;Multiplication&lt;/h2&gt;
&lt;p&gt;Multiplication is next: we start by defining the multiplication
operation (by pattern-matching on the left-hand argument) and proving
a few lemmas about multiplying by known arguments on the right. The
proof of &lt;code&gt;*suc&lt;/code&gt; is the most involved proof we have seen yet, but it
ultimately just comes down to algebra, and we can make good use of our
notation for writing chained equality proofs.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb20&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb20-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;infixl&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;*&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;*&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ℕ&lt;/span&gt;
&lt;span id=&quot;cb20-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;zero * y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; zero&lt;/span&gt;
&lt;span id=&quot;cb20-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;suc x * y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; y + x * y&lt;/span&gt;
&lt;span id=&quot;cb20-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;*0 &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n * &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; ≡ &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;zero *0 &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb20-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; *0 &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; n *0&lt;/span&gt;
&lt;span id=&quot;cb20-9&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-10&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;*1 &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n * &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt; ≡ n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-11&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; *1 &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb20-12&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; *1 &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; suc $≡ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n *1&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-13&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-14&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;*suc&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x * suc y ≡ x + x * y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-15&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;zero *suc y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb20-16&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; *suc y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; suc $≡ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb20-17&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  begin&lt;/span&gt;
&lt;span id=&quot;cb20-18&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  y + x * suc y               ≡[ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y +&lt;span class=&quot;ot&quot;&gt;_)&lt;/span&gt; $≡ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x *suc y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb20-19&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  y + &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x + x * y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;             ≡⟨ +-assoc y x &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x * y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; ]≡&lt;/span&gt;
&lt;span id=&quot;cb20-20&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y + x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; + x * y             ≡[ &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;+&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; $≡ +-comm y x ≡$ x * y ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb20-21&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x + y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; + x * y             ≡[ +-assoc x &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb20-22&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb20-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  x + &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y + x * y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;             ∎&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We prove some standard properties of multiplication: commutativity,
distributivity over addition, associativity. Again, the proofs mostly
consist of a whole bunch of algebra, using the special notation for
building chained equality proofs.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb21&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb21-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*-comm &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x * y ≡ y * x&lt;/span&gt;
&lt;span id=&quot;cb21-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*-comm zero y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sym &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y *0&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*-comm &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; begin&lt;/span&gt;
&lt;span id=&quot;cb21-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  y + x * y                   ≡[ y +&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; $≡ *-comm x y ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb21-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  y + y * x                   ≡⟨ y *suc x ]≡&lt;/span&gt;
&lt;span id=&quot;cb21-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  y * suc x                   ∎&lt;/span&gt;
&lt;span id=&quot;cb21-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*-distribˡ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x y z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x * &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y + z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; ≡ x * y + x * z&lt;/span&gt;
&lt;span id=&quot;cb21-9&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*-distribˡ zero y z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb21-10&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*-distribˡ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; y z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; begin&lt;/span&gt;
&lt;span id=&quot;cb21-11&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  y + z + x * &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y + z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;         ≡[ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y + z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; +&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; $≡ *-distribˡ x y z ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb21-12&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  y + z + &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x * y + x * z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;     ≡[ +-assoc y &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb21-13&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  y + &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;z + &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x * y + x * z&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt;   ≡⟨ y +&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; $≡ +-assoc z &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ]≡&lt;/span&gt;
&lt;span id=&quot;cb21-14&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  y + &lt;span class=&quot;ot&quot;&gt;((&lt;/span&gt;z + x * y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; + x * z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;   ≡[ y +&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; $≡ &lt;span class=&quot;ot&quot;&gt;(_&lt;/span&gt;+&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; $≡ +-comm z &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ≡$ x * z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb21-15&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  y + &lt;span class=&quot;ot&quot;&gt;((&lt;/span&gt;x * y + z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; + x * z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;   ≡[ y +&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; $≡ +-assoc &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x * y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb21-16&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  y + &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x * y + &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;z + x * z&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt;   ≡⟨ +-assoc y &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ]≡&lt;/span&gt;
&lt;span id=&quot;cb21-17&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  y + x * y + &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;z + x * z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;     ∎&lt;/span&gt;
&lt;span id=&quot;cb21-18&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-19&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*-distribʳ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x y z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x + y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; * z ≡ x * z + y * z&lt;/span&gt;
&lt;span id=&quot;cb21-20&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*-distribʳ x y z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; begin&lt;/span&gt;
&lt;span id=&quot;cb21-21&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x + y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; * z                 ≡[ *-comm &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x + y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb21-22&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  z * &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x + y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;                 ≡[ *-distribˡ z &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb21-23&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-23&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  z * x + z * y               ≡[ &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;+&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; $≡ *-comm z &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ≡$≡ *-comm z &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb21-24&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-24&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  x * z + y * z               ∎&lt;/span&gt;
&lt;span id=&quot;cb21-25&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-25&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-26&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-26&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*-assoc &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x y z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x * y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; * z ≡ x * &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y * z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb21-27&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-27&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*-assoc zero y z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb21-28&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-28&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*-assoc &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; y z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; begin&lt;/span&gt;
&lt;span id=&quot;cb21-29&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-29&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y + x * y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; * z             ≡[ *-distribʳ y &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb21-30&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-30&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  y * z + &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x * y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; * z         ≡[ y * z +&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; $≡ *-assoc x &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb21-31&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb21-31&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  y * z + x * &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y * z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;         ∎&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally, we prove that multiplication is left-cancellative. This
proof is somewhat tricky—in the case that &lt;code&gt;x&lt;/code&gt;, &lt;code&gt;y&lt;/code&gt;, and &lt;code&gt;z&lt;/code&gt; are all
successors, we need to use the induction hypothesis (&lt;em&gt;i.e.&lt;/em&gt; a
recursive call to &lt;code&gt;*-cancelˡ&lt;/code&gt;) on &lt;code&gt;x&lt;/code&gt; and the
predecessors of &lt;code&gt;y&lt;/code&gt; and &lt;code&gt;z&lt;/code&gt;, using the fact that + is
left-cancellative to construct the required input equality.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb22&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb22-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb22-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*-cancelˡ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x y z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; ≢ x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x * y ≡ x * z &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; y ≡ z&lt;/span&gt;
&lt;span id=&quot;cb22-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb22-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*-cancelˡ zero y z x≢0 xy≡xz &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; absurd &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x≢0 refl&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb22-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb22-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*-cancelˡ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; zero zero x≢0 xy≡xz &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb22-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb22-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*-cancelˡ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; zero &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; x≢0 xy≡xz &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; absurd &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;noConf &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sym &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x *0&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt; xy≡xz&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb22-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb22-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*-cancelˡ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; zero x≢0 xy≡xz &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; absurd &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;noConf &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;trans xy≡xz &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x *0&lt;span class=&quot;ot&quot;&gt;)))&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb22-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb22-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*-cancelˡ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; x≢0 xy≡xz &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; suc $≡&lt;/span&gt;
&lt;span id=&quot;cb22-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb22-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt; *-cancelˡ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; y z x≢0&lt;/span&gt;
&lt;span id=&quot;cb22-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb22-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt; +-cancelˡ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x * y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x * z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb22-9&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb22-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt; begin&lt;/span&gt;
&lt;span id=&quot;cb22-10&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb22-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          suc x + suc x * y   ≡⟨ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; *suc y ]≡&lt;/span&gt;
&lt;span id=&quot;cb22-11&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb22-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          suc x * suc y       ≡[ xy≡xz ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb22-12&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb22-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          suc x * suc z       ≡[ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; *suc z ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb22-13&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb22-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          suc x + suc x * z   ∎&lt;/span&gt;
&lt;span id=&quot;cb22-14&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb22-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb22-15&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb22-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb22-16&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb22-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;level2&quot; id=&quot;inequality&quot;&gt;
&lt;h2&gt;Inequality&lt;/h2&gt;
&lt;p&gt;Next, we give a standard definition of the “less than or equal to”
relation on natural numbers. Note that the structure of a proof of &lt;span class=&quot;math inline&quot;&gt;\(x \leq
y\)&lt;/span&gt; exactly matches the structure of &lt;span class=&quot;math inline&quot;&gt;\(x\)&lt;/span&gt; itself.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb23&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb23-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb23-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≤&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb23-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb23-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  zle &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;n &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; zero ≤ n&lt;/span&gt;
&lt;span id=&quot;cb23-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb23-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  sle &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;m n &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; m ≤ n &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; suc m ≤ suc n&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We also prove some standard properties of &lt;span class=&quot;math inline&quot;&gt;\(\leq\)&lt;/span&gt;: it is reflexive and
transitive, and is related to &lt;code&gt;suc&lt;/code&gt; in various ways.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb24&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb24-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb24-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤-refl &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;m &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; m ≤ m&lt;/span&gt;
&lt;span id=&quot;cb24-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb24-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤-refl &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;zero&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; zle&lt;/span&gt;
&lt;span id=&quot;cb24-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb24-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤-refl &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc m&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sle ≤-refl&lt;/span&gt;
&lt;span id=&quot;cb24-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb24-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb24-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤-trans &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≤ y &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; y ≤ z &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≤ z&lt;/span&gt;
&lt;span id=&quot;cb24-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb24-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤-trans zle y≤z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; zle&lt;/span&gt;
&lt;span id=&quot;cb24-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb24-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤-trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle x≤y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle y≤z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sle &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;≤-trans x≤y y≤z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb24-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-9&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb24-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤-sucr &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;m n &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; m ≤ n &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; m ≤ suc n&lt;/span&gt;
&lt;span id=&quot;cb24-10&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb24-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤-sucr zle &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; zle&lt;/span&gt;
&lt;span id=&quot;cb24-11&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb24-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤-sucr &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle m≤n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sle &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;≤-sucr m≤n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-12&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb24-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-13&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb24-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤-sucl &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;m n &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; suc m ≤ n &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; m ≤ n&lt;/span&gt;
&lt;span id=&quot;cb24-14&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb24-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤-sucl &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle sm≤n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ≤-sucr sm≤n&lt;/span&gt;
&lt;span id=&quot;cb24-15&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb24-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb24-16&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb24-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤-pred &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; suc x ≤ suc y &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≤ y&lt;/span&gt;
&lt;span id=&quot;cb24-17&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb24-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤-pred &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle sx≤sy&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sx≤sy&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For convenience, we define &lt;span class=&quot;math inline&quot;&gt;\(&amp;lt;\)&lt;/span&gt; in terms of &lt;span class=&quot;math inline&quot;&gt;\(\leq\)&lt;/span&gt;, and prove a few
properties: any number is less than its successor, and &lt;span class=&quot;math inline&quot;&gt;\(&amp;lt;\)&lt;/span&gt; is
transitive and non-reflexive.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb25&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb25-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb25-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&amp;lt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb25-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb25-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;x &amp;lt; y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; suc x ≤ y&lt;/span&gt;
&lt;span id=&quot;cb25-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb25-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb25-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb25-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&amp;lt;suc &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x &amp;lt; suc x&lt;/span&gt;
&lt;span id=&quot;cb25-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb25-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&amp;lt;suc zero &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sle zle&lt;/span&gt;
&lt;span id=&quot;cb25-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb25-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;&amp;lt;suc &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sle &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x &amp;lt;suc&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb25-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb25-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb25-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb25-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&amp;lt;-trans &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x &amp;lt; y &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; y &amp;lt; z &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x &amp;lt; z&lt;/span&gt;
&lt;span id=&quot;cb25-9&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb25-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&amp;lt;-trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle x&amp;lt;y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle y&amp;lt;z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ≤-trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle x&amp;lt;y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;≤-sucr y&amp;lt;z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb25-10&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb25-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb25-11&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb25-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;x≮x &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ¬ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x &amp;lt; x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb25-12&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb25-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;x≮x &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;zero&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb25-13&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb25-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;x≮x &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle x&amp;lt;x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x≮x x&amp;lt;x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;section class=&quot;level3&quot; id=&quot;relationships-among-equality-and-inequality&quot;&gt;
&lt;h3&gt;Relationships among equality and inequality&lt;/h3&gt;
&lt;p&gt;Of course, equality, &lt;span class=&quot;math inline&quot;&gt;\(&amp;lt;\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(\leq\)&lt;/span&gt; have various relationships that we
will need. First, equality implies &lt;span class=&quot;math inline&quot;&gt;\(\leq\)&lt;/span&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb26&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb26-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb26-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≡→≤ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≡ y &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≤ y&lt;/span&gt;
&lt;span id=&quot;cb26-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb26-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≡→≤ refl &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ≤-refl&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next, &lt;span class=&quot;math inline&quot;&gt;\(x &amp;lt; y\)&lt;/span&gt; implies that &lt;span class=&quot;math inline&quot;&gt;\(x\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(y\)&lt;/span&gt; are &lt;em&gt;not&lt;/em&gt; related by &lt;span class=&quot;math inline&quot;&gt;\(\equiv\)&lt;/span&gt; or
&lt;span class=&quot;math inline&quot;&gt;\(\geq\)&lt;/span&gt;. The first lemma in particular—that &lt;span class=&quot;math inline&quot;&gt;\(&amp;lt;\)&lt;/span&gt; implies &lt;span class=&quot;math inline&quot;&gt;\(\not\equiv\)&lt;/span&gt;—gets used quite a bit. Note that it can be read in two equivalent
ways: on the surface, it is a way to turn a proof of &lt;span class=&quot;math inline&quot;&gt;\(x &amp;lt; y\)&lt;/span&gt; into a
proof of &lt;span class=&quot;math inline&quot;&gt;\(x \not\equiv y\)&lt;/span&gt;; but
since &lt;span class=&quot;math inline&quot;&gt;\(x \not\equiv y\)&lt;/span&gt; is really an abbreviation for &lt;span class=&quot;math inline&quot;&gt;\((x \equiv y) \to \bot\)&lt;/span&gt;, it can be
used to derive a contradiction if we have proofs that &lt;span class=&quot;math inline&quot;&gt;\(x &amp;lt; y\)&lt;/span&gt; and
also &lt;span class=&quot;math inline&quot;&gt;\(x \equiv y\)&lt;/span&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb27&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb27-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb27-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&amp;lt;→≢ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x &amp;lt; y &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≢ y&lt;/span&gt;
&lt;span id=&quot;cb27-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb27-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&amp;lt;→≢ x&amp;lt;y refl &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; x≮x x&amp;lt;y&lt;/span&gt;
&lt;span id=&quot;cb27-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb27-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb27-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb27-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&amp;lt;→≱ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x &amp;lt; y &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ¬ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y ≤ x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb27-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb27-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&amp;lt;→≱ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle x&amp;lt;y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle y≤x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &amp;lt;→≱ x&amp;lt;y y≤x&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If &lt;span class=&quot;math inline&quot;&gt;\(x \leq y\)&lt;/span&gt; but they are not equal, then &lt;span class=&quot;math inline&quot;&gt;\(x &amp;lt; y\)&lt;/span&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb28&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb28-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb28-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤≢→&amp;lt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≤ y &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≢ y &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x &amp;lt; y&lt;/span&gt;
&lt;span id=&quot;cb28-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb28-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤≢→&amp;lt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; zero&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; zle x≢y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; absurd &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x≢y refl&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb28-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb28-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤≢→&amp;lt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; suc y&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; zle x≢y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sle zle&lt;/span&gt;
&lt;span id=&quot;cb28-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb28-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤≢→&amp;lt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle x≤y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; x≢y &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sle &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;≤≢→&amp;lt; x≤y &lt;span class=&quot;ot&quot;&gt;(λ&lt;/span&gt; m≡n &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x≢y &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc $≡ m≡n&lt;span class=&quot;ot&quot;&gt;)))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We will need a form of transitivity that says if &lt;span class=&quot;math inline&quot;&gt;\(x \leq y\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(y &amp;lt;
z\)&lt;/span&gt;, then &lt;span class=&quot;math inline&quot;&gt;\(x &amp;lt; z\)&lt;/span&gt;, as well as the other way around.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb29&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb29-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb29-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤-&amp;lt;-trans &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≤ y &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; y &amp;lt; z &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x &amp;lt; z&lt;/span&gt;
&lt;span id=&quot;cb29-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb29-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤-&amp;lt;-trans x≤y &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle y&amp;lt;z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ≤-trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle x≤y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle y&amp;lt;z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb29-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb29-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb29-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb29-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&amp;lt;-≤-trans &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x &amp;lt; y &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; y ≤ z &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x &amp;lt; z&lt;/span&gt;
&lt;span id=&quot;cb29-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb29-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&amp;lt;-≤-trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle x&amp;lt;y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; y≤z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ≤-trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle x&amp;lt;y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; y≤z&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally, a very specific lemma we will need: if a number is not
equal to either 0 or 1, then it must be greater than or equal to 2.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb30&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb30-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb30-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;¬01-is-≥2 &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;a &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;a ≢ &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;a ≢ &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; ≤ a&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb30-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb30-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;¬01-is-≥2 zero a≢0 a≢1 &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; absurd &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;a≢0 refl&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb30-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb30-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;¬01-is-≥2 &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc zero&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; a≢0 a≢1 &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; absurd &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;a≢1 refl&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb30-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb30-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;¬01-is-≥2 &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc a&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt; a≢0 a≢1 &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sle &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle zle&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;level3&quot; id=&quot;arithmetic-and-inequality&quot;&gt;
&lt;h3&gt;Arithmetic and inequality&lt;/h3&gt;
&lt;p&gt;The last lemmas we need relate arithmetic operations and inequality.
First, adding and multiplying cannot make anything smaller (unless we
multiply by zero, of course).&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb31&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb31-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb31-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤+ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≤ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x + y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb31-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb31-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤+ &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;zero&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; zle&lt;/span&gt;
&lt;span id=&quot;cb31-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb31-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤+ &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sle ≤+&lt;/span&gt;
&lt;span id=&quot;cb31-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb31-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb31-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb31-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤* &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x ≢ &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; y ≤ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x * y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb31-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb31-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤* &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;zero&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; x≢0 &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; absurd &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x≢0 refl&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb31-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb31-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;≤* &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; x≢0 &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ≤+&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As a result, if we know that one thing is equal to a sum or product of
other things, we can conclude something about their relative sizes.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb32&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb32-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb32-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;+→≤ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x + y ≡ z &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≤ z&lt;/span&gt;
&lt;span id=&quot;cb32-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb32-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;+→≤ refl &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ≤+&lt;/span&gt;
&lt;span id=&quot;cb32-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb32-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb32-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;+→&amp;lt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; &amp;lt; y &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x + y ≡ z &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x &amp;lt; z&lt;/span&gt;
&lt;span id=&quot;cb32-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb32-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;+→&amp;lt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc y&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; x+y≡z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; +→≤ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sym &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x +suc y&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt; x+y≡z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb32-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb32-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb32-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*→≤ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y ≢ &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; y * x ≡ z &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≤ z&lt;/span&gt;
&lt;span id=&quot;cb32-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb32-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;*→≤ &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;y&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; y≢0 refl &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ≤* y≢0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section class=&quot;level2&quot; id=&quot;divisibility-primes-and-composites&quot;&gt;
&lt;h2&gt;Divisibility, primes, and composites&lt;/h2&gt;
&lt;p&gt;With the preliminaries out of the way, we can finally get on with the
meat of the problem—and we finally get to make use of a dependent pair! A &lt;em&gt;constructive&lt;/em&gt; proof that &lt;code&gt;a&lt;/code&gt; divides
&lt;code&gt;b&lt;/code&gt; is a specific natural number witness &lt;code&gt;k&lt;/code&gt;, along with a proof that &lt;code&gt;k * a ≡ b&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb33&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb33-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb33-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;∣&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb33-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb33-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;a ∣ b &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; Σ ℕ &lt;span class=&quot;ot&quot;&gt;(λ&lt;/span&gt; k &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; k * a ≡ b&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Proofs of divisibility are unique—that is, for given &lt;span class=&quot;math inline&quot;&gt;\(a\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(b\)&lt;/span&gt; there
is at most one value of &lt;span class=&quot;math inline&quot;&gt;\(k\)&lt;/span&gt; such that &lt;span class=&quot;math inline&quot;&gt;\(ka = b\)&lt;/span&gt;. We won’t need this,
but it follows easily from the fact that multiplication is
cancellative. More interesting is the fact that divisibility is
&lt;em&gt;decidable&lt;/em&gt;—that is, for given numbers &lt;span class=&quot;math inline&quot;&gt;\(a\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(b\)&lt;/span&gt; we can calculate
either a proof that &lt;span class=&quot;math inline&quot;&gt;\(a \mid b\)&lt;/span&gt;, or a proof that &lt;span class=&quot;math inline&quot;&gt;\(\neg (a \mid b)\)&lt;/span&gt;.
This will play a starring role later on—to factor a number we need to
be able to try potential divisors and find out whether they work—but proving it is not easy!
It will take us several hundred more lines of Agda to get there.&lt;/p&gt;
&lt;p&gt;In any case, using this notion of divisibility, we can now define prime and
composite numbers. A number &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; is defined to be prime if it is at
least two, and every &lt;span class=&quot;math inline&quot;&gt;\(2 \leq d &amp;lt; n\)&lt;/span&gt; does &lt;em&gt;not&lt;/em&gt; divide &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb34&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb34-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb34-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;Prime &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb34-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb34-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;Prime n &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; ≤ n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; × &lt;span class=&quot;ot&quot;&gt;(∀&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;d &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;d &amp;lt; n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; ≤ d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ¬ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;d ∣ n&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;One could equivalently define primality by saying that any divisor of
&lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; must be equal to &lt;span class=&quot;math inline&quot;&gt;\(1\)&lt;/span&gt; or &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt;; I just decided I liked this
formulation better, especially because it directly matches up with the
way we will test a number for primality later.&lt;/p&gt;
&lt;p&gt;A composite number is one that has a nontrivial divisor—that is, a number &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt;
such that &lt;span class=&quot;math inline&quot;&gt;\(2 \leq d &amp;lt; n\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt; divides &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt;.&lt;span class=&quot;sidenote-wrapper&quot;&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;sn-5&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;sn-5&quot; type=&quot;checkbox&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;Note
that we could easily prove that if &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; is prime then &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; is not
composite, and likewise if &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; is composite then it is not prime, but
we won’t end up needing these lemmas.&lt;br /&gt;
&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb35&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb35-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb35-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;Composite &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb35-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb35-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;Composite n &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; Σ ℕ &lt;span class=&quot;ot&quot;&gt;(λ&lt;/span&gt; d &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; ≤ d × d &amp;lt; n × d ∣ n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Unlike proofs of divisibility, proofs of &lt;code&gt;Composite n&lt;/code&gt; are &lt;em&gt;not&lt;/em&gt;
unique. For example, we could prove &lt;code&gt;Composite 12&lt;/code&gt; by showing that
&lt;span class=&quot;math inline&quot;&gt;\(2\)&lt;/span&gt; is a nontrivial divisor of &lt;span class=&quot;math inline&quot;&gt;\(12\)&lt;/span&gt;, or by showing that &lt;span class=&quot;math inline&quot;&gt;\(3\)&lt;/span&gt; is.
Although this does not matter from a purely logical point of view, it
matters computationally; in general, we care which specific proof of
&lt;code&gt;Composite n&lt;/code&gt; we have.&lt;/p&gt;
&lt;section class=&quot;level3&quot; id=&quot;nontrivial-divisors-come-in-pairs&quot;&gt;
&lt;h3&gt;Nontrivial divisors come in pairs&lt;/h3&gt;
&lt;p&gt;Before moving on to other things, we will prove a lemma about
composite numbers. If &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; is composite, by definition it has a
nontrivial divisor &lt;span class=&quot;math inline&quot;&gt;\(a\)&lt;/span&gt;; but this means it must also have a second
nontrivial divisor &lt;span class=&quot;math inline&quot;&gt;\(b\)&lt;/span&gt; such that &lt;span class=&quot;math inline&quot;&gt;\(ab = n\)&lt;/span&gt;. This fact seems almost
trivial to us. Indeed, it’s easy to show that if &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; has a divisor
&lt;span class=&quot;math inline&quot;&gt;\(a\)&lt;/span&gt;, then it must have another divisor &lt;span class=&quot;math inline&quot;&gt;\(b\)&lt;/span&gt; such that &lt;span class=&quot;math inline&quot;&gt;\(ab = n\)&lt;/span&gt;. The
tricky part is showing that if &lt;span class=&quot;math inline&quot;&gt;\(a\)&lt;/span&gt; is a &lt;em&gt;nontrivial&lt;/em&gt; divisor, then &lt;span class=&quot;math inline&quot;&gt;\(b\)&lt;/span&gt;
is &lt;em&gt;also&lt;/em&gt; nontrivial. The proof relies on much of the infrastructure
we have built up about natural numbers, multiplication, and
inequality.&lt;/p&gt;
&lt;p&gt;First, we define a type representing two factors of a number &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt;: a
pair of proofs that &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; is composite (&lt;em&gt;i.e.&lt;/em&gt; two nontrivial divisors
of &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt;), along with a proof that the product of those divisors is &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb36&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb36-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb36-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;FactorsOf &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb36-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb36-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;FactorsOf n &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; Σ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;Composite n × Composite n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(λ&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{(&lt;/span&gt;f₁ , f₂&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; fst f₁ * fst f₂ ≡ n&lt;span class=&quot;ot&quot;&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now, we prove that if &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; is composite, then it has two nontrivial
factors. We begin by pattern-matching on the proof that &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; is
composite, which consists of a divisor &lt;span class=&quot;math inline&quot;&gt;\(a\)&lt;/span&gt;, evidence that &lt;span class=&quot;math inline&quot;&gt;\(a\)&lt;/span&gt; is
nontrivial (&lt;em&gt;i.e.&lt;/em&gt; &lt;span class=&quot;math inline&quot;&gt;\(2 \leq a\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(a &amp;lt; n\)&lt;/span&gt;), and a proof that &lt;span class=&quot;math inline&quot;&gt;\(a\)&lt;/span&gt; is a
divisor of &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt;, which itself consists of a number &lt;span class=&quot;math inline&quot;&gt;\(b\)&lt;/span&gt; paired with a
proof that &lt;span class=&quot;math inline&quot;&gt;\(ba = n\)&lt;/span&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb37&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb37-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb37-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;factorsOf &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Composite n &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; FactorsOf n&lt;/span&gt;
&lt;span id=&quot;cb37-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb37-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;factorsOf n &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;a , 2≤a , a&amp;lt;n , b , ba≡n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To construct the proof of &lt;code&gt;FactorsOf n&lt;/code&gt;, we need two proofs of
&lt;code&gt;Composite n&lt;/code&gt; along with a proof that the product of the two divisors
is &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt;. We already have a proof that &lt;span class=&quot;math inline&quot;&gt;\(ba = n\)&lt;/span&gt;, so we use that, with
&lt;span class=&quot;math inline&quot;&gt;\(a\)&lt;/span&gt; as the second divisor (replicating the corresponding proof of
&lt;code&gt;Composite n&lt;/code&gt;), and &lt;span class=&quot;math inline&quot;&gt;\(b\)&lt;/span&gt; as the first. Proving that &lt;span class=&quot;math inline&quot;&gt;\(b\)&lt;/span&gt; is a divisor of
&lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; is easy: &lt;span class=&quot;math inline&quot;&gt;\(a\)&lt;/span&gt; is the witness, and proving that &lt;span class=&quot;math inline&quot;&gt;\(ab = n\)&lt;/span&gt; is easy
since we already know &lt;span class=&quot;math inline&quot;&gt;\(ba = n\)&lt;/span&gt; and multiplication is commutative. The
only thing left is to prove that &lt;span class=&quot;math inline&quot;&gt;\(b\)&lt;/span&gt; is nontrivial, &lt;em&gt;i.e.&lt;/em&gt; that &lt;span class=&quot;math inline&quot;&gt;\(2
\leq b\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(b &amp;lt; n\)&lt;/span&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb38&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb38-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb38-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;((&lt;/span&gt;b , 2≤b , b&amp;lt;n , a , trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;*-comm a b&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; ba≡n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; , &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;a , 2≤a , a&amp;lt;n , b , ba≡n&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt; , ba≡n&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;First, we need a lemma that &lt;span class=&quot;math inline&quot;&gt;\(0 &amp;lt; n\)&lt;/span&gt;, which follows because &lt;span class=&quot;math inline&quot;&gt;\(0 &amp;lt; 1 &amp;lt; a
&amp;lt; n\)&lt;/span&gt; (remember that a proof of &lt;span class=&quot;math inline&quot;&gt;\(1 &amp;lt; a\)&lt;/span&gt; is actually defined to be the
same thing as a proof of &lt;span class=&quot;math inline&quot;&gt;\(2 \leq a\)&lt;/span&gt;).&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb39&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb39-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb39-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb39-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb39-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  0&amp;lt;n &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; &amp;lt; n&lt;/span&gt;
&lt;span id=&quot;cb39-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb39-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  0&amp;lt;n &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &amp;lt;-trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle zle&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;&amp;lt;-trans 2≤a a&amp;lt;n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next, we tackle &lt;span class=&quot;math inline&quot;&gt;\(2 \leq b\)&lt;/span&gt;, by showing that &lt;span class=&quot;math inline&quot;&gt;\(b\)&lt;/span&gt; can’t possibly be &lt;span class=&quot;math inline&quot;&gt;\(0\)&lt;/span&gt;
or &lt;span class=&quot;math inline&quot;&gt;\(1\)&lt;/span&gt; (using our previous lemma that anything not equal to 0 or 1
must be greater than or equal to 2).&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb40&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb40-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb40-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  2≤b &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt; ≤ b&lt;/span&gt;
&lt;span id=&quot;cb40-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb40-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  2≤b &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ¬01-is-≥2 b&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If &lt;span class=&quot;math inline&quot;&gt;\(b\)&lt;/span&gt; were &lt;span class=&quot;math inline&quot;&gt;\(0\)&lt;/span&gt;, then &lt;span class=&quot;math inline&quot;&gt;\(ba = n\)&lt;/span&gt; would imply &lt;span class=&quot;math inline&quot;&gt;\(0 = n\)&lt;/span&gt;, but we know
&lt;span class=&quot;math inline&quot;&gt;\(0 &amp;lt; n\)&lt;/span&gt;, so this is a contradiction.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb41&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb41-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb41-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;(λ&lt;/span&gt; b≡0 &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &amp;lt;→≢ 0&amp;lt;n&lt;/span&gt;
&lt;span id=&quot;cb41-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb41-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;begin&lt;/span&gt;
&lt;span id=&quot;cb41-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb41-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;                     ≡[ refl ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb41-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb41-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; * a                 ≡⟨ &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;*&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; $≡ b≡0 ≡$ a ]≡&lt;/span&gt;
&lt;span id=&quot;cb41-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb41-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        b * a                 ≡[ ba≡n ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb41-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb41-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        n                     ∎&lt;/span&gt;
&lt;span id=&quot;cb41-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb41-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb41-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb41-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If &lt;span class=&quot;math inline&quot;&gt;\(b\)&lt;/span&gt; were &lt;span class=&quot;math inline&quot;&gt;\(1\)&lt;/span&gt;, then &lt;span class=&quot;math inline&quot;&gt;\(ba = n\)&lt;/span&gt; would imply &lt;span class=&quot;math inline&quot;&gt;\(a = n\)&lt;/span&gt;, but we know
&lt;span class=&quot;math inline&quot;&gt;\(a &amp;lt; n\)&lt;/span&gt;, so this is also a contradiction.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb42&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb42-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb42-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;(λ&lt;/span&gt; b≡1 &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &amp;lt;→≢ a&amp;lt;n&lt;/span&gt;
&lt;span id=&quot;cb42-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb42-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;begin&lt;/span&gt;
&lt;span id=&quot;cb42-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb42-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        a                     ≡⟨ a *1 ]≡&lt;/span&gt;
&lt;span id=&quot;cb42-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb42-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        a * &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;                 ≡[ *-comm a &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt; ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb42-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb42-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt; * a                 ≡⟨ &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;*&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; $≡ b≡1 ≡$ a ]≡&lt;/span&gt;
&lt;span id=&quot;cb42-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb42-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        b * a                 ≡[ ba≡n ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb42-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb42-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        n                     ∎&lt;/span&gt;
&lt;span id=&quot;cb42-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb42-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb42-9&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb42-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally, we prove &lt;span class=&quot;math inline&quot;&gt;\(b &amp;lt; n\)&lt;/span&gt;, by showing &lt;span class=&quot;math inline&quot;&gt;\(b \leq n\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(b \neq n\)&lt;/span&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb43&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb43-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb43-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  b&amp;lt;n &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; b &amp;lt; n&lt;/span&gt;
&lt;span id=&quot;cb43-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb43-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  b&amp;lt;n &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ≤≢→&amp;lt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;span class=&quot;math inline&quot;&gt;\(b \leq n\)&lt;/span&gt; since &lt;span class=&quot;math inline&quot;&gt;\(ba = n\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(a\)&lt;/span&gt; is not zero (if &lt;span class=&quot;math inline&quot;&gt;\(a\)&lt;/span&gt; were zero it
would contradict the fact that &lt;span class=&quot;math inline&quot;&gt;\(2 \leq a\)&lt;/span&gt;).&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb44&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb44-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb44-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;*→≤ &lt;span class=&quot;ot&quot;&gt;(λ&lt;/span&gt; a≡0 &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &amp;lt;→≢ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;&amp;lt;-trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle zle&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; 2≤a&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sym a≡0&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;*-comm a b&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; ba≡n&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;span class=&quot;math inline&quot;&gt;\(b \neq n\)&lt;/span&gt;, since &lt;span class=&quot;math inline&quot;&gt;\(b = n\)&lt;/span&gt; together with &lt;span class=&quot;math inline&quot;&gt;\(ba = n\)&lt;/span&gt; would imply &lt;span class=&quot;math inline&quot;&gt;\(a = 1\)&lt;/span&gt;
(since multiplication is cancellative), but &lt;span class=&quot;math inline&quot;&gt;\(2 \leq a\)&lt;/span&gt; so it cannot
equal 1.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb45&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb45-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb45-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;(λ&lt;/span&gt; b≡n &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &amp;lt;→≢ 2≤a&lt;/span&gt;
&lt;span id=&quot;cb45-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb45-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sym&lt;/span&gt;
&lt;span id=&quot;cb45-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb45-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;*-cancelˡ n a &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;&amp;lt;→≢ 0&amp;lt;n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb45-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb45-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;begin&lt;/span&gt;
&lt;span id=&quot;cb45-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb45-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            n * a             ≡⟨ &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;*&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; $≡ b≡n ≡$ a ]≡&lt;/span&gt;
&lt;span id=&quot;cb45-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb45-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            b * a             ≡[ ba≡n ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb45-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb45-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            n                 ≡⟨ n *1 ]≡&lt;/span&gt;
&lt;span id=&quot;cb45-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb45-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;            n * &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;             ∎&lt;/span&gt;
&lt;span id=&quot;cb45-9&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb45-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;          &lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb45-10&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb45-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb45-11&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb45-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      &lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb45-12&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb45-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section class=&quot;level2&quot; id=&quot;division&quot;&gt;
&lt;h2&gt;Division&lt;/h2&gt;
&lt;p&gt;Let’s start working our way towards proving that divisibility is
decidable. To check whether &lt;span class=&quot;math inline&quot;&gt;\(d \mid n\)&lt;/span&gt;, the usual idea would be to
divide &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; by &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt; and check whether we get a remainder of zero. So we
need to formalize this notion of division with remainder.&lt;/p&gt;
&lt;p&gt;Specifically, when we divide &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; by &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt;, we expect to get a &lt;em&gt;quotient&lt;/em&gt; &lt;span class=&quot;math inline&quot;&gt;\(q\)&lt;/span&gt;
and a &lt;em&gt;remainder&lt;/em&gt; &lt;span class=&quot;math inline&quot;&gt;\(r\)&lt;/span&gt;, such that &lt;span class=&quot;math inline&quot;&gt;\(r + qd = n\)&lt;/span&gt;, and &lt;span class=&quot;math inline&quot;&gt;\(0 \leq r &amp;lt; d\)&lt;/span&gt;.
The first condition, &lt;span class=&quot;math inline&quot;&gt;\(r + qd = n\)&lt;/span&gt;, just defines what we mean by division: &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; is
&lt;span class=&quot;math inline&quot;&gt;\(q\)&lt;/span&gt; times &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt;, plus a remainder of &lt;span class=&quot;math inline&quot;&gt;\(r\)&lt;/span&gt;. The second condition will ensure
that the result is unique. We wouldn’t want to divide &lt;span class=&quot;math inline&quot;&gt;\(17\)&lt;/span&gt; by &lt;span class=&quot;math inline&quot;&gt;\(2\)&lt;/span&gt; and
end up with a quotient of &lt;span class=&quot;math inline&quot;&gt;\(6\)&lt;/span&gt; and a remainder of &lt;span class=&quot;math inline&quot;&gt;\(5\)&lt;/span&gt;; the remainder should be as small as possible.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;DivMod&lt;/code&gt; type simply encodes these requirements.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb46&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb46-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb46-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; DivMod &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n d q r &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb46-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb46-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  DM &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;r + q * d ≡ n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;r &amp;lt; d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; DivMod n d q r&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can prove a few lemmas about &lt;code&gt;DivMod&lt;/code&gt;. First, whenever we have
&lt;code&gt;DivMod n d q r&lt;/code&gt;, then &lt;code&gt;d&lt;/code&gt; must be positive, since &lt;span class=&quot;math inline&quot;&gt;\(r &amp;lt; d\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(r\)&lt;/span&gt; is
a natural number.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb47&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb47-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb47-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;divMod→0&amp;lt;d &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;n d q r &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; DivMod n d q r &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; &amp;lt; d&lt;/span&gt;
&lt;span id=&quot;cb47-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb47-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;divMod→0&amp;lt;d &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;DM &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; r&amp;lt;d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ≤-&amp;lt;-trans zle r&amp;lt;d&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can also show that for nonzero &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt;, the remainder is zero if and only if &lt;span class=&quot;math inline&quot;&gt;\(d
\mid n\)&lt;/span&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb48&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb48-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb48-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;mod0→divides &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n d &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;q &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; DivMod n d q &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; d ∣ n&lt;/span&gt;
&lt;span id=&quot;cb48-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb48-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;mod0→divides n d &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;q&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;DM eq &lt;span class=&quot;ot&quot;&gt;_)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; q , eq&lt;/span&gt;
&lt;span id=&quot;cb48-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb48-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb48-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb48-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;divides→mod0 &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n d &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; &amp;lt; d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; d ∣ n &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Σ ℕ &lt;span class=&quot;ot&quot;&gt;(λ&lt;/span&gt; q &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; DivMod n d q &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb48-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb48-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;divides→mod0 n d 0&amp;lt;d &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;q , qd≡n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; q , &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;DM qd≡n 0&amp;lt;d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We would also like to show that if the remainder when dividing &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; by
&lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt; is &lt;em&gt;not&lt;/em&gt; zero, then &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt; does &lt;em&gt;not&lt;/em&gt; divide &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt;. This is &lt;em&gt;almost&lt;/em&gt;
the contrapositive of &lt;code&gt;divides→mod0&lt;/code&gt;—which would be trivial to
show—but not quite: I said “the” remainder, but actually we don’t yet
know that the quotient and remainder are unique! Perhaps we could get
a remainder of 0 and some other remainder for the same &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt;, by
choosing different quotients?&lt;/p&gt;
&lt;p&gt;Of course, quotients and remainders &lt;em&gt;are&lt;/em&gt; unique: that is, if &lt;span class=&quot;math inline&quot;&gt;\(q_1,
r_1\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(q_2, r_2\)&lt;/span&gt; both satisfy the properties to be the quotient and
remainder of &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; divided by &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt;, then in fact &lt;span class=&quot;math inline&quot;&gt;\(q_1 = q_2\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(r_1 =
r_2\)&lt;/span&gt;. But how can we prove this? The usual idea is to look at the
difference &lt;span class=&quot;math inline&quot;&gt;\(r_1 - r_2 = dq_1 - dq_2\)&lt;/span&gt;, which is divisible by &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt;; but
since &lt;span class=&quot;math inline&quot;&gt;\(r_1 &amp;lt; d\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(r_2 &amp;lt; d\)&lt;/span&gt;, the only way for the difference &lt;span class=&quot;math inline&quot;&gt;\(r_1 -
r_2\)&lt;/span&gt; to be divisible by &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt; is if in fact &lt;span class=&quot;math inline&quot;&gt;\(r_1 - r_2 = 0\)&lt;/span&gt;. From here
we can also derive &lt;span class=&quot;math inline&quot;&gt;\(q_1 = q_2\)&lt;/span&gt; via algebra.&lt;/p&gt;
&lt;p&gt;Subtraction, eh? In order to formalize this, it seems as though we might
need to define the integers… but there is a better way!&lt;/p&gt;
&lt;/section&gt;
&lt;section class=&quot;level2&quot; id=&quot;absolute-difference&quot;&gt;
&lt;h2&gt;Absolute difference&lt;/h2&gt;
&lt;p&gt;The previous informal argument mentioned the difference &lt;span class=&quot;math inline&quot;&gt;\(r_1 - r_2\)&lt;/span&gt;.
But we could just as easily have talked about &lt;span class=&quot;math inline&quot;&gt;\(r_2 - r_1\)&lt;/span&gt; instead, and
the same argument would work just as well. This observation shows
that we do not actually care about the (signed) &lt;em&gt;difference&lt;/em&gt; between
&lt;span class=&quot;math inline&quot;&gt;\(r_1\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(r_2\)&lt;/span&gt;, but only the &lt;em&gt;distance&lt;/em&gt; between them. This means we
can just stick to our well-loved natural numbers, and define a commutative
&lt;em&gt;absolute difference&lt;/em&gt; function which computes the nonnegative distance
between its two arguments, like so:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb49&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb49-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb49-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;∥&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;-&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;∥ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ℕ&lt;/span&gt;
&lt;span id=&quot;cb49-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb49-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;∥ zero - y ∥ &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; y&lt;/span&gt;
&lt;span id=&quot;cb49-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb49-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;∥ suc x - zero ∥ &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; suc x&lt;/span&gt;
&lt;span id=&quot;cb49-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb49-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;∥ suc x - suc y ∥ &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ∥ x - y ∥&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Of course, we will need a lot of small lemmas about the properties of
this operation. We can start by proving that the distance between two
numbers is 0 if and only if they are equal:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb50&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb50-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb50-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff0 &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; ≡ ∥ x - x ∥&lt;/span&gt;
&lt;span id=&quot;cb50-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb50-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff0 zero &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb50-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb50-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff0 &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; diff0 x&lt;/span&gt;
&lt;span id=&quot;cb50-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb50-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb50-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb50-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff0→≡ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; ≡ ∥ x - y ∥ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≡ y&lt;/span&gt;
&lt;span id=&quot;cb50-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb50-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff0→≡ &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;zero&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;zero&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; eq &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; eq&lt;/span&gt;
&lt;span id=&quot;cb50-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb50-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff0→≡ &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc y&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; eq &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; suc $≡ diff0→≡ eq&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next, the distance between any number and 0 is the number itself, and
the distance function is commutative.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb51&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb51-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb51-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;∥x-0∥≡x &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ∥ x - &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; ∥ ≡ x&lt;/span&gt;
&lt;span id=&quot;cb51-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb51-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;∥x-0∥≡x zero &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb51-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb51-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;∥x-0∥≡x &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb51-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb51-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb51-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb51-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff-comm &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ∥ x - y ∥ ≡ ∥ y - x ∥&lt;/span&gt;
&lt;span id=&quot;cb51-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb51-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff-comm &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;zero&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;zero&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb51-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb51-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff-comm &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;zero&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc y&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb51-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb51-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff-comm &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;zero&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb51-9&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb51-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff-comm &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc y&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; diff-comm &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;y&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A key lemma supporting the argument outlined in the previous section
is that if &lt;span class=&quot;math inline&quot;&gt;\(x\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(y\)&lt;/span&gt; are both less than &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt;, so is their absolute difference.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb52&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb52-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb52-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff-&amp;lt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y d &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x &amp;lt; d &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; y &amp;lt; d &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ∥ x - y ∥ &amp;lt; d&lt;/span&gt;
&lt;span id=&quot;cb52-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb52-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff-&amp;lt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;zero&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;y&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; x&amp;lt;d y&amp;lt;d &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; y&amp;lt;d&lt;/span&gt;
&lt;span id=&quot;cb52-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb52-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff-&amp;lt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;zero&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; x&amp;lt;d y&amp;lt;d &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; x&amp;lt;d&lt;/span&gt;
&lt;span id=&quot;cb52-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb52-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff-&amp;lt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc y&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; x&amp;lt;d y&amp;lt;d &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; diff-&amp;lt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;y&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;&amp;lt;-trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x &amp;lt;suc&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; x&amp;lt;d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;&amp;lt;-trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y &amp;lt;suc&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; y&amp;lt;d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can also cancel the same thing being added to both sides, or factor out
the same thing being multiplied on both sides.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb53&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb53-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb53-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff-cancelˡ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;a b c &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ∥ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;a + b&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; - &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;a + c&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; ∥ ≡ ∥ b - c ∥&lt;/span&gt;
&lt;span id=&quot;cb53-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb53-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff-cancelˡ zero b c &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb53-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb53-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff-cancelˡ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc a&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; b c &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; diff-cancelˡ a b c&lt;/span&gt;
&lt;span id=&quot;cb53-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb53-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb53-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb53-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff-distribʳ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x y d &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ∥ x * d - y * d ∥ ≡ ∥ x - y ∥ * d&lt;/span&gt;
&lt;span id=&quot;cb53-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb53-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff-distribʳ zero y d &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb53-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb53-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff-distribʳ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; zero d &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ∥x-0∥≡x &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;d + x * d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb53-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb53-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;diff-distribʳ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; d &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; begin&lt;/span&gt;
&lt;span id=&quot;cb53-9&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb53-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ∥ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;d + x * d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; - &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;d + y * d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; ∥         ≡[ diff-cancelˡ d &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x * d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;y * d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb53-10&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb53-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ∥ x * d - y * d ∥                     ≡[ diff-distribʳ x y d ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb53-11&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb53-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  ∥ x - y ∥ * d                         ∎&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Another key lemma is that if &lt;span class=&quot;math inline&quot;&gt;\(w + x = y + z\)&lt;/span&gt;, then &lt;span class=&quot;math inline&quot;&gt;\(\|w - y\| = \|x -
z\|\)&lt;/span&gt; (&lt;code&gt;sub₂&lt;/code&gt; below). Personally, I found this quite tricky to prove.
The best approach I found was to first prove the simpler lemma that
&lt;span class=&quot;math inline&quot;&gt;\(x + y = z\)&lt;/span&gt; implies &lt;span class=&quot;math inline&quot;&gt;\(x = \| z - y \|\)&lt;/span&gt; (&lt;code&gt;sub₁&lt;/code&gt;), which can then be used
in several places in the proof of &lt;code&gt;sub₂&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb54&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb54-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb54-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sub₁ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x y z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x + y ≡ z &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x ≡ ∥ z - y ∥&lt;/span&gt;
&lt;span id=&quot;cb54-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb54-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sub₁ &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;zero&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;y&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;z&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; refl &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; diff0 y&lt;/span&gt;
&lt;span id=&quot;cb54-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb54-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sub₁ &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;zero&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc z&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; x+y≡z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb54-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb54-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  begin&lt;/span&gt;
&lt;span id=&quot;cb54-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb54-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    suc x                     ≡⟨ suc $≡ x +0 ]≡&lt;/span&gt;
&lt;span id=&quot;cb54-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb54-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    suc &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x + &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;               ≡[ x+y≡z ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb54-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb54-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    suc z                     ∎&lt;/span&gt;
&lt;span id=&quot;cb54-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb54-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sub₁ &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc y&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc z&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; x+y≡z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb54-9&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb54-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  sub₁ &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;y&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;z&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb54-10&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb54-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;noConf &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc $≡ sym &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x +suc y&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt; x+y≡z&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb54-11&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb54-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb54-12&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb54-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sub₂ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;w x y z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; w + x ≡ y + z &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ∥ w - y ∥ ≡ ∥ x - z ∥&lt;/span&gt;
&lt;span id=&quot;cb54-13&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb54-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sub₂ &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;zero&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;y&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;z&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; w+x≡y+z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sub₁ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sym w+x≡y+z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb54-14&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb54-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sub₂ &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc w&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;zero&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;z&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; w+x≡y+z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sub₁ w+x≡y+z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;diff-comm &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;z&lt;span class=&quot;ot&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb54-15&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb54-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;sub₂ &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc w&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;suc y&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;z&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; w+x≡y+z &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sub₂ &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;w&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;noConf w+x≡y+z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;level2&quot; id=&quot;quotient-and-remainder-are-unique&quot;&gt;
&lt;h2&gt;Quotient and remainder are unique&lt;/h2&gt;
&lt;p&gt;We can now return to prove that quotient and remainder are unique.
First, we show that zero is the only multiple of &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt; which is less than &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb55&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb55-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb55-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;∣&amp;lt;→0 &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;d x &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; d ∣ x &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; x &amp;lt; d &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; ≡ x&lt;/span&gt;
&lt;span id=&quot;cb55-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb55-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;∣&amp;lt;→0 &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;zero , ad≡x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; x&amp;lt;d &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ad≡x&lt;/span&gt;
&lt;span id=&quot;cb55-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb55-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;∣&amp;lt;→0 &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc a , ad≡x&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; x&amp;lt;d &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; absurd &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;&amp;lt;→≱ x&amp;lt;d &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;+→≤ ad≡x&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And now for the main event: if we have both &lt;code&gt;DivMod n d q₁ r₁&lt;/code&gt; and
&lt;code&gt;DivMod n d q₂ r₂&lt;/code&gt;, then in fact the &lt;code&gt;q&lt;/code&gt;s and &lt;code&gt;r&lt;/code&gt;s must be the same.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb56&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb56-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb56-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;divModUnique &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;n d q₁ r₁ q₂ r₂ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; DivMod n d q₁ r₁ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; DivMod n d q₂ r₂ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;q₁ ≡ q₂&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; × &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;r₁ ≡ r₂&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb56-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb56-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;divModUnique &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;n&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;d&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;q₁&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;r₁&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;q₂&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;r₂&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; dm&lt;span class=&quot;ot&quot;&gt;@(&lt;/span&gt;DM r₁+q₁d≡n r₁&amp;lt;d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;DM r₂+q₂d≡n r₂&amp;lt;d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; q₁≡q₂ , r₁≡r₂&lt;/span&gt;
&lt;span id=&quot;cb56-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb56-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Since &lt;span class=&quot;math inline&quot;&gt;\(r_1 + q_1d = n\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(r_2 + q_2d = n\)&lt;/span&gt;, by transitivity and
symmetry we have &lt;span class=&quot;math inline&quot;&gt;\(r_1 + q_1d = r_2 + q_2d\)&lt;/span&gt;; then by the &lt;code&gt;sub₂&lt;/code&gt; lemma,
&lt;span class=&quot;math inline&quot;&gt;\(\|r_1 - r_2\| = \|q_1d - q_2d\|\)&lt;/span&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb57&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb57-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb57-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  rem-diff &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ∥ r₁ - r₂ ∥ ≡ ∥ q₁ * d - q₂ * d ∥&lt;/span&gt;
&lt;span id=&quot;cb57-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb57-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  rem-diff &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; sub₂ &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;r₁&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;trans r₁+q₁d≡n &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sym r₂+q₂d≡n&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next, we can show that &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt; divides the absolute difference &lt;span class=&quot;math inline&quot;&gt;\(\|r_1 -
  r_2\|\)&lt;/span&gt;, by factoring it out of &lt;span class=&quot;math inline&quot;&gt;\(\|q_1 d - q_2 d\|\)&lt;/span&gt;.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb58&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb58-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb58-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  d∣r₁-r₂ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; d ∣ ∥ r₁ - r₂ ∥&lt;/span&gt;
&lt;span id=&quot;cb58-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb58-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  d∣r₁-r₂ &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; ∥ q₁ - q₂ ∥ ,&lt;/span&gt;
&lt;span id=&quot;cb58-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb58-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;begin&lt;/span&gt;
&lt;span id=&quot;cb58-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb58-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      ∥ q₁ - q₂ ∥ * d         ≡⟨ diff-distribʳ q₁ q₂ d ]≡&lt;/span&gt;
&lt;span id=&quot;cb58-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb58-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      ∥ q₁ * d - q₂ * d ∥     ≡⟨ rem-diff ]≡&lt;/span&gt;
&lt;span id=&quot;cb58-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb58-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      ∥ r₁ - r₂ ∥             ∎&lt;/span&gt;
&lt;span id=&quot;cb58-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb58-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can then put three lemmas together to conclude &lt;span class=&quot;math inline&quot;&gt;\(r_1 = r_2\)&lt;/span&gt;: first,
since &lt;span class=&quot;math inline&quot;&gt;\(r_1\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(r_2\)&lt;/span&gt; are both less than &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt;, so is their absolute
difference; since &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt; also divides the absolute difference, the
absolute difference must be zero; and finally, an absolute difference
of zero means &lt;span class=&quot;math inline&quot;&gt;\(r_1\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(r_2\)&lt;/span&gt; must be equal.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb59&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb59-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb59-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  r₁≡r₂ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; r₁ ≡ r₂&lt;/span&gt;
&lt;span id=&quot;cb59-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb59-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  r₁≡r₂ &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; diff0→≡ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;∣&amp;lt;→0 d∣r₁-r₂ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;diff-&amp;lt; r₁&amp;lt;d r₂&amp;lt;d&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;From here, proving &lt;span class=&quot;math inline&quot;&gt;\(q_1 = q_2\)&lt;/span&gt; just requires some algebra.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb60&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb60-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb60-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  dq₁≡dq₂ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; d * q₁ ≡ d * q₂&lt;/span&gt;
&lt;span id=&quot;cb60-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb60-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  dq₁≡dq₂ &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; +-cancelˡ r₁ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;d * q₁&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;d * q₂&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb60-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;begin&lt;/span&gt;
&lt;span id=&quot;cb60-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb60-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      r₁ + d * q₁             ≡[ r₁ +&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; $≡ *-comm d q₁ ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb60-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb60-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      r₁ + q₁ * d             ≡[ r₁+q₁d≡n ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb60-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb60-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      n                       ≡⟨ r₂+q₂d≡n ]≡&lt;/span&gt;
&lt;span id=&quot;cb60-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb60-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      r₂ + q₂ * d             ≡[ &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;+&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; $≡ sym r₁≡r₂ ≡$≡ *-comm q₂ d ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb60-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb60-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;      r₁ + d * q₂             ∎&lt;/span&gt;
&lt;span id=&quot;cb60-9&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb60-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-10&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb60-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb60-11&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb60-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  q₁≡q₂ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; q₁ ≡ q₂&lt;/span&gt;
&lt;span id=&quot;cb60-12&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb60-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  q₁≡q₂ &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; *-cancelˡ d q₁ q₂ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;&amp;lt;→≢ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;divMod→0&amp;lt;d dm&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt; dq₁≡dq₂&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally, we can use uniqueness of quotients and remainders to show the
lemma we wanted about divisibility and remainders: if &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; divided by
&lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt; has some nonzero number as remainder, then &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt; does not divide
&lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt;. If &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt; did divide &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt;, then we know we would get a remainder of
&lt;span class=&quot;math inline&quot;&gt;\(0\)&lt;/span&gt;; but since remainders are unique, we can’t have both a zero and
nonzero remainder.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb61&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb61-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb61-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;modS→¬divides &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n d &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;q r &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; DivMod n d q &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc r&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ¬ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;d ∣ n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb61-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb61-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;modS→¬divides n d dm d∣n &lt;span class=&quot;kw&quot;&gt;with&lt;/span&gt; divides→mod0 n d &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;divMod→0&amp;lt;d dm&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; d∣n&lt;/span&gt;
&lt;span id=&quot;cb61-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb61-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;|&lt;/span&gt; q₂ , dm₂ &lt;span class=&quot;kw&quot;&gt;with&lt;/span&gt; divModUnique dm dm₂&lt;/span&gt;
&lt;span id=&quot;cb61-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb61-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;|&lt;/span&gt; q₁≡q₂ , &lt;span class=&quot;ot&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/section&gt;
&lt;section class=&quot;level2&quot; id=&quot;the-division-algorithm-take-1&quot;&gt;
&lt;h2&gt;The division algorithm, take 1&lt;/h2&gt;
&lt;p&gt;So, given natural numbers &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt;, how do we compute the quotient
and remainder? We can write down a type &lt;code&gt;DivAlg&lt;/code&gt; that expresses what
we want: given some &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt;, &lt;code&gt;DivAlg n d&lt;/code&gt; represents the result of
the division algorithm, that is, a pair of numbers &lt;span class=&quot;math inline&quot;&gt;\((q,r)\)&lt;/span&gt; such that
&lt;code&gt;DivMod n d q r&lt;/code&gt; holds.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb62&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb62-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb62-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;DivAlg &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; ℕ &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb62-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb62-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;DivAlg n d &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; Σ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;ℕ × ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(λ&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;q , r&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; DivMod n d q r &lt;span class=&quot;ot&quot;&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then we want a function with a type something like &lt;code&gt;(n d : ℕ) → DivAlg n d&lt;/code&gt; (actually this type is not quite correct—can you see why?).
How can we write something with this type?&lt;/p&gt;
&lt;p&gt;One simple idea, expressed imperatively, is to start with &lt;span class=&quot;math inline&quot;&gt;\(q = 0\)&lt;/span&gt;.
Now, as long as &lt;span class=&quot;math inline&quot;&gt;\(n \geq d\)&lt;/span&gt;, subtract &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt; from &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; and add one to
&lt;span class=&quot;math inline&quot;&gt;\(q\)&lt;/span&gt;—if we can find &lt;span class=&quot;math inline&quot;&gt;\(q\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(r\)&lt;/span&gt; such that &lt;span class=&quot;math inline&quot;&gt;\(r + qd = n - d\)&lt;/span&gt;, then &lt;span class=&quot;math inline&quot;&gt;\(r +
(q+1)d = n\)&lt;/span&gt;. Eventually, &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; must land in the range &lt;span class=&quot;math inline&quot;&gt;\(0 \leq n &amp;lt; d\)&lt;/span&gt;,
in which case it will be the remainder, and the current value of &lt;span class=&quot;math inline&quot;&gt;\(q\)&lt;/span&gt;
will be the quotient.&lt;/p&gt;
&lt;section class=&quot;level3&quot; id=&quot;construct-the-evidence-you-would-like-to-pattern-match-on&quot;&gt;
&lt;h3&gt;Construct the evidence you would like to pattern-match on&lt;/h3&gt;
&lt;p&gt;That’s the idea, but turning this into a verified constructive algorithm will take some
work. First, let’s formalize the idea of testing whether &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; is less
than &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt;, and decreasing it by &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt; if not. We’d rather not actually
deal with subtraction, so the idea is to generate either a proof that
&lt;span class=&quot;math inline&quot;&gt;\(n &amp;lt; d\)&lt;/span&gt;, or another number &lt;span class=&quot;math inline&quot;&gt;\(n'\)&lt;/span&gt; along with a proof that &lt;span class=&quot;math inline&quot;&gt;\(n' + d = n\)&lt;/span&gt;.
We encapsulate this in the following type &lt;code&gt;Cmp&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb63&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb63-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb63-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; Cmp &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n d &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb63-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb63-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  LT &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; n &amp;lt; d &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Cmp n d&lt;/span&gt;
&lt;span id=&quot;cb63-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb63-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  GE &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n′ &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n′ + d ≡ n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Cmp n d&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;Cmp n d&lt;/code&gt; represents the result of comparing &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt;, and is
equivalent to having either &lt;span class=&quot;math inline&quot;&gt;\(n &amp;lt; d\)&lt;/span&gt; or &lt;span class=&quot;math inline&quot;&gt;\(n \geq d\)&lt;/span&gt;, but expressed in a
form that is more directly useful to us. &lt;strong&gt;Construct the evidence you
would like to pattern-match on!&lt;/strong&gt; That is, in general, evidence for a
proposition &lt;span class=&quot;math inline&quot;&gt;\(P\)&lt;/span&gt; can take many logically equivalent forms, and you
should pick the form that will make your life easiest at the &lt;em&gt;use
site&lt;/em&gt;, even if it means you have to work harder to &lt;em&gt;construct&lt;/em&gt; it in
the first place. You can write standalone lemmas for constructing
your evidence; but pattern-matching it will happen in the middle of
some bigger proof which ought not to be cluttered by calls to
conversion lemmas.&lt;/p&gt;
&lt;p&gt;To construct evidence for &lt;code&gt;Cmp n d&lt;/code&gt;, we write the function
&lt;code&gt;decreaseBy?&lt;/code&gt; which decides whether we can decrease &lt;code&gt;n&lt;/code&gt; by &lt;code&gt;d&lt;/code&gt; or not.
Writing this function is a bit more work than writing something
of type &lt;code&gt;(n d : ℕ) → (n &amp;lt; d) ⊎ (d ≤ n)&lt;/code&gt;, but our work will pay off later!&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb64&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb64-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb64-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;decreaseBy?&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n d &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Cmp n d&lt;/span&gt;
&lt;span id=&quot;cb64-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb64-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;zero decreaseBy? zero &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; GE &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; refl&lt;/span&gt;
&lt;span id=&quot;cb64-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb64-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;zero decreaseBy? suc d &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; LT &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle zle&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb64-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb64-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;suc n decreaseBy? zero &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; GE &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;((&lt;/span&gt;suc n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; +0&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb64-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb64-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;suc n decreaseBy? suc d &lt;span class=&quot;kw&quot;&gt;with&lt;/span&gt; n decreaseBy? d&lt;/span&gt;
&lt;span id=&quot;cb64-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb64-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;|&lt;/span&gt; LT n&amp;lt;d &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; LT &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;sle n&amp;lt;d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb64-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb64-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ot&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;|&lt;/span&gt; GE n′ n′+d≡n &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; GE n′ &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;trans &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n′ +suc d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc $≡ n′+d≡n&lt;span class=&quot;ot&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can also write a helper function &lt;code&gt;incDivMod&lt;/code&gt; which encodes the
observation from before, that if &lt;span class=&quot;math inline&quot;&gt;\(r + qd = n-d\)&lt;/span&gt;, then &lt;span class=&quot;math inline&quot;&gt;\(r + (q+1)d =
n\)&lt;/span&gt;. Of course we don’t actually want to use subtraction, so instead
of writing &lt;span class=&quot;math inline&quot;&gt;\(n-d\)&lt;/span&gt;, we work in terms of an &lt;span class=&quot;math inline&quot;&gt;\(n'\)&lt;/span&gt; such that &lt;span class=&quot;math inline&quot;&gt;\(n' + d = n\)&lt;/span&gt;.
Proving this requires only some straightforward algebra.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb65&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb65-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb65-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;incDivMod &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;n′ n d q r &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; n′ + d ≡ n &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; DivMod n′ d q r &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; DivMod n d &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc q&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; r&lt;/span&gt;
&lt;span id=&quot;cb65-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb65-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;incDivMod &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;n′&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;n&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;d&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;q&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;r&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; n′+d≡n &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;DM r+qd≡n′ r&amp;lt;d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; DM r+d+qd≡n r&amp;lt;d&lt;/span&gt;
&lt;span id=&quot;cb65-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb65-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb65-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb65-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  r+d+qd≡n &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; r + &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;d + q * d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; ≡ n&lt;/span&gt;
&lt;span id=&quot;cb65-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb65-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  r+d+qd≡n &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; begin&lt;/span&gt;
&lt;span id=&quot;cb65-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb65-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    r + &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;d + q * d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;           ≡⟨ +-assoc r &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ]≡&lt;/span&gt;
&lt;span id=&quot;cb65-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb65-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;r + d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; + q * d           ≡[ &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;+&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; $≡ +-comm r &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ≡$ q * d ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb65-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb65-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;d + r&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; + q * d           ≡[ +-assoc d &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb65-9&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb65-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    d + &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;r + q * d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;           ≡[ d +&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; $≡ r+qd≡n′ ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb65-10&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb65-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    d + n′                    ≡[ +-comm d &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb65-11&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb65-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    n′ + d                    ≡[ n′+d≡n ⟩≡&lt;/span&gt;
&lt;span id=&quot;cb65-12&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb65-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;    n                         ∎&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now it seems like we have everything we need to write the division
algorithm as a recursive algorithm: given &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; and &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt;, check whether
&lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; can be decreased by &lt;span class=&quot;math inline&quot;&gt;\(d\)&lt;/span&gt; or not. If not, we can return &lt;span class=&quot;math inline&quot;&gt;\(q = 0\)&lt;/span&gt; and
&lt;span class=&quot;math inline&quot;&gt;\(r = n\)&lt;/span&gt;. Otherwise, recurse on &lt;span class=&quot;math inline&quot;&gt;\(n - d\)&lt;/span&gt;, returning the same remainder
and an incremented quotient from whatever the recursive call returns, using
&lt;code&gt;incDivMod&lt;/code&gt; to discharge the proof obligation. It’s just a few lines
of code, right?&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb66&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb66-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb66-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;module&lt;/span&gt; DivModBad &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb66-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-3&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb66-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;pp&quot;&gt;{-# NON_TERMINATING #-}&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-4&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb66-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  divAlg &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n d &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; ℕ&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; DivAlg n d&lt;/span&gt;
&lt;span id=&quot;cb66-5&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb66-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  divAlg n d &lt;span class=&quot;kw&quot;&gt;with&lt;/span&gt; n decreaseBy? d&lt;/span&gt;
&lt;span id=&quot;cb66-6&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb66-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;|&lt;/span&gt; LT n&amp;lt;d &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt; , n&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; , &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;DM &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;n +0&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; n&amp;lt;d&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb66-7&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb66-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;|&lt;/span&gt; GE n′ n′+d≡n &lt;span class=&quot;kw&quot;&gt;with&lt;/span&gt; divAlg n′ d&lt;/span&gt;
&lt;span id=&quot;cb66-8&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb66-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;q , r&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; , dm &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;suc q , r&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; , &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;incDivMod n′+d≡n dm&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Well, as you can see, it &lt;em&gt;is&lt;/em&gt; just a few lines of code, but all is not
well: although this function typechecks, Agda can’t tell that it is
terminating! (I added the &lt;code&gt;NON_TERMINATING&lt;/code&gt; pragma so I could include
this bad version of &lt;code&gt;divAlg&lt;/code&gt; in the code without causing an error.)
The problem is that the recursive call to &lt;code&gt;divAlg&lt;/code&gt; is on &lt;code&gt;n′&lt;/code&gt;,
which is not a subterm of &lt;code&gt;n&lt;/code&gt;, but instead comes from the call to
&lt;code&gt;decreaseBy?&lt;/code&gt;. Agda has no way of knowing whether the result from
some random function call is going to end up being smaller than the
original input.&lt;/p&gt;
&lt;p&gt;Now, you and I can both see that this function does indeed terminate,
but we just need a way to convince Agda of this fact… right?&lt;/p&gt;
&lt;p&gt;…have you spotted the flaw? Remember how I mentioned that the type &lt;code&gt;(n d : ℕ) → DivAlg n d&lt;/code&gt; is not quite right? In fact, the above bad
implementation of &lt;code&gt;divMod&lt;/code&gt; is &lt;em&gt;not&lt;/em&gt; terminating, and Agda is quite right to
be worried! In particular, the function recurses infinitely when given an input of &lt;span class=&quot;math inline&quot;&gt;\(d
= 0\)&lt;/span&gt;, since it will keep subtracting &lt;span class=&quot;math inline&quot;&gt;\(0\)&lt;/span&gt; from &lt;span class=&quot;math inline&quot;&gt;\(n\)&lt;/span&gt; forever. This makes sense, of
course: everyone knows you can’t divide by zero &lt;em&gt;because it makes the
universe go into infinite recursion&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The correct type for &lt;code&gt;divAlg&lt;/code&gt; is &lt;code&gt;(n d : ℕ) → (0 &amp;lt; d) → DivAlg n d&lt;/code&gt;,
but we’re still going to have trouble convincing Agda that our
algorithm is terminating. In order to do so, we need to take a detour
through &lt;em&gt;well-founded induction&lt;/em&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section class=&quot;level2&quot; id=&quot;well-founded-induction&quot;&gt;
&lt;h2&gt;Well-founded induction&lt;/h2&gt;
&lt;p&gt;Normally, Agda only allows functions that are &lt;em&gt;structurally
recursive&lt;/em&gt;—that is, functions which make recursive calls on syntactic
subterms of their inputs. (Agda’s termination checking is a bit more
sophisticated than that, but that’s the basic idea.) However, we can
use basic structural induction to bootstrap our way into more exotic
forms. In particular, we are going to define something called
&lt;em&gt;well-founded induction&lt;/em&gt;.&lt;span class=&quot;sidenote-wrapper&quot;&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;sn-6&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;sn-6&quot; type=&quot;checkbox&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;Note that I will use the terms “recursion”
and “induction” more or less interchangeably. In some contexts, people
make a distinction between the terms (typically a &lt;em&gt;recursion
principle&lt;/em&gt; is a less-dependently-typed version of an &lt;em&gt;induction
principle&lt;/em&gt;), but in this context, &lt;em&gt;inductive proofs&lt;/em&gt; correspond, via
Curry-Howard, to (suitably restricted) &lt;em&gt;recursive functions&lt;/em&gt;, so
“induction” and “recursion” describe the same thing from a logical and
computational viewpoint, respectively.&lt;br /&gt;
&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The idea of well-founded induction starts with the general idea of a
&lt;em&gt;relation&lt;/em&gt;. A relation on &lt;code&gt;A&lt;/code&gt; is just a function that takes two
values of type &lt;code&gt;A&lt;/code&gt; and produces a type, representing evidence that the
two values are related (according to whatever kind of relationship we
have in mind).&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb67&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb67-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb67-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;Rel &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set₁&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb67-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb67-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;Rel A &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; A &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; A &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We have already seen quite a few relations, such as equality, &lt;span class=&quot;math inline&quot;&gt;\(&amp;lt;\)&lt;/span&gt;,
&lt;span class=&quot;math inline&quot;&gt;\(\leq\)&lt;/span&gt;, and divisibility.&lt;/p&gt;
&lt;p&gt;Suppose we’re writing a recursive function, with some relation &lt;span class=&quot;math inline&quot;&gt;\(\prec\)&lt;/span&gt;
in mind, and for a given input &lt;span class=&quot;math inline&quot;&gt;\(x\)&lt;/span&gt; we’re only allowed to make
recursive calls on values &lt;span class=&quot;math inline&quot;&gt;\(y\)&lt;/span&gt; such that &lt;span class=&quot;math inline&quot;&gt;\(y \prec x\)&lt;/span&gt;. If &lt;span class=&quot;math inline&quot;&gt;\(\prec\)&lt;/span&gt; is the
“is a syntactic subterm of” relation, then we get structural
recursion as usual. But what if &lt;span class=&quot;math inline&quot;&gt;\(\prec\)&lt;/span&gt; is some other relation? What
needs to be true about &lt;span class=&quot;math inline&quot;&gt;\(\prec\)&lt;/span&gt; for this to make sense? In particular, how
can we be sure that the function won’t get stuck in infinite recursion?&lt;/p&gt;
&lt;p&gt;One’s first instinct might be to say that &lt;span class=&quot;math inline&quot;&gt;\(y \prec x\)&lt;/span&gt; needs to imply that
&lt;span class=&quot;math inline&quot;&gt;\(y\)&lt;/span&gt; is “smaller than” &lt;span class=&quot;math inline&quot;&gt;\(x\)&lt;/span&gt; somehow. But what does “smaller than” mean?
And in fact, “smaller than” doesn’t always work: for example, if we are
writing a function over the rational numbers, or even just the
integers, the usual “smaller than” relation does &lt;em&gt;not&lt;/em&gt; guarantee our
function will terminate; it’s possible to continue choosing smaller
and smaller rational numbers or integers forever.&lt;/p&gt;
&lt;p&gt;The key idea is exactly that this can’t happen: it’s not possible to
have an infinite chain of values where each is related to the
previous. That is, there should be no left-infinite chains &lt;span class=&quot;math inline&quot;&gt;\(\dots
\prec y_3 \prec y_2 \prec y_1 \prec x\)&lt;/span&gt;. Then we are guaranteed that if we keep making
recursive calls on values that are related by &lt;span class=&quot;math inline&quot;&gt;\(\prec\)&lt;/span&gt; to the previous
value, we will have to stop eventually: after some finite number of calls
we will hit a value with nothing else related to it.&lt;/p&gt;
&lt;p&gt;A relation &lt;span class=&quot;math inline&quot;&gt;\(\prec\)&lt;/span&gt; with this “no left-infinite chains” property is
called &lt;em&gt;well-founded&lt;/em&gt;. But how do we encode this idea in Agda?&lt;/p&gt;
&lt;section class=&quot;level3&quot; id=&quot;accessibility&quot;&gt;
&lt;h3&gt;Accessibility&lt;/h3&gt;
&lt;p&gt;Instead of thinking negatively (&lt;em&gt;no&lt;/em&gt; left-infinite
chains), the key is to think positively: &lt;em&gt;all&lt;/em&gt; chains to the left of
&lt;em&gt;every&lt;/em&gt; value are finite. Call a value &lt;em&gt;accessible&lt;/em&gt; if all chains
leading to it are finite. Another way to say this is that a value is
accessible if every value related to it is also accessible:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb68&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb68-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb68-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;data&lt;/span&gt; Acc &lt;span class=&quot;ot&quot;&gt;(_&lt;/span&gt;≺&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; Rel A&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb68-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb68-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  acc &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;x &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;((&lt;/span&gt;y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; y ≺ x &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Acc &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≺&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Acc &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≺&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; x&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;Acc _≺_ x&lt;/code&gt; defines what it means for a particular value &lt;code&gt;x&lt;/code&gt; to be
accessible with respect to a relation &lt;span class=&quot;math inline&quot;&gt;\(\prec\)&lt;/span&gt;. There is only one
constructor, &lt;code&gt;acc&lt;/code&gt;, which requires &lt;code&gt;(y : A) → y ≺ x → Acc _≺_ y&lt;/code&gt;—that
is, for every value &lt;code&gt;y&lt;/code&gt; of type &lt;code&gt;A&lt;/code&gt;, if &lt;code&gt;y&lt;/code&gt; is related to &lt;code&gt;x&lt;/code&gt;, then
&lt;code&gt;y&lt;/code&gt; is accessible. In other words, &lt;code&gt;x&lt;/code&gt; is accessible if and only if every &lt;code&gt;y ≺ x&lt;/code&gt;
is accessible.&lt;/p&gt;
&lt;p&gt;This is definitely tricky to wrap your head around! At this point
you may have two objections:&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;&lt;p&gt;What about base cases? Shouldn’t we have another constructor which
says &lt;code&gt;x&lt;/code&gt; is accessible if &lt;em&gt;nothing&lt;/em&gt; is related to it? Actually,
the &lt;code&gt;acc&lt;/code&gt; constructor already says that! If nothing is related to
&lt;code&gt;x&lt;/code&gt;, then &lt;code&gt;(y : A) → y ≺ x → Acc _≺_ y&lt;/code&gt; is trivially true: we can
easily promise anything we want as the output of a function if we
know it can never be called. Every natural number less than zero is a
purple flying weasel.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Doesn’t this just run into the same problem as before with
left-infinite chains? If we consider the “is one less than”
relation on the integers, isn’t &lt;span class=&quot;math inline&quot;&gt;\(2\)&lt;/span&gt; accessible because &lt;span class=&quot;math inline&quot;&gt;\(1\)&lt;/span&gt; is
accessible because &lt;span class=&quot;math inline&quot;&gt;\(0\)&lt;/span&gt; is accessible because &lt;span class=&quot;math inline&quot;&gt;\(-1\)&lt;/span&gt; is accessible
because … ?&lt;/p&gt;
&lt;p&gt;There is something a bit subtle going on here: recursive data types
in Agda (unlike Haskell) are interpreted according to a
&lt;em&gt;least fixed point&lt;/em&gt; semantics. Put in plain terms, the only values
of a data type are those which can be built by applications of a
&lt;em&gt;finite&lt;/em&gt; number of constructors. So in fact, the “no left-infinite
chain” condition is foundationally built into the way Agda data
types work!&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The idea is that we can turn well-founded induction into structural
induction by &lt;em&gt;pattern-matching on &lt;code&gt;Acc&lt;/code&gt; proofs&lt;/em&gt;! Starting with some
&lt;span class=&quot;math inline&quot;&gt;\(x\)&lt;/span&gt;, any &lt;span class=&quot;math inline&quot;&gt;\(y \prec x\)&lt;/span&gt; has an accessibility proof which is a subterm of
the accessibility proof for &lt;span class=&quot;math inline&quot;&gt;\(x\)&lt;/span&gt;. This is a bit exotic though: if we
pattern-match on the &lt;code&gt;acc&lt;/code&gt; for &lt;span class=&quot;math inline&quot;&gt;\(x\)&lt;/span&gt; we get a &lt;em&gt;function&lt;/em&gt; that yields an
accessibility proof for each &lt;span class=&quot;math inline&quot;&gt;\(y \prec x\)&lt;/span&gt;; calling that function
produces another accessibility proof, which &lt;em&gt;counts as a structural
subterm of the original&lt;/em&gt;. This seems a bit strange until you think of
a value of type &lt;code&gt;Acc&lt;/code&gt; like an big, arbitrarily-branching tree of
finite depth; each node contains a function which really just stores
all the subtrees. In other words, a function of type &lt;code&gt;(y : A) → y ≺ x → Acc _≺_ y&lt;/code&gt; can be thought of as a giant tuple of &lt;code&gt;Acc&lt;/code&gt; values, one
for each &lt;code&gt;y \prec x&lt;/code&gt;.&lt;span class=&quot;sidenote-wrapper&quot;&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;sn-7&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;sn-7&quot; type=&quot;checkbox&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;I am not sure exactly how Agda handles this
internally, but I assume this is well-trodden ground for designers of
proof assistants.&lt;br /&gt;
&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;section class=&quot;level3&quot; id=&quot;well-founded-induction-defined&quot;&gt;
&lt;h3&gt;Well-founded induction, defined&lt;/h3&gt;
&lt;p&gt;Given the definition of accessible elements, we can now give the
definition of a well-founded relation: a relation on &lt;code&gt;A&lt;/code&gt; is well-founded if
&lt;em&gt;every&lt;/em&gt; value of type &lt;code&gt;A&lt;/code&gt; is accessible.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb69&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb69-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb69-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;WellFounded &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; Rel A &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb69-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb69-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;WellFounded &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;A&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≺&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;a &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; Acc &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≺&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; a&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can now write down the &lt;em&gt;principle of well-founded induction&lt;/em&gt;. This
is also quite tricky to wrap your brain around, so we’ll go through it
slowly. Previously, we were just talking about whether functions terminated or
not; but the reason this is important is that a function might be
calculating a &lt;em&gt;proof&lt;/em&gt;. A function which purports to calculate a proof
but sometimes goes into infinite recursion is a charlatan, and not
really a proof at all.&lt;/p&gt;
&lt;p&gt;So instead of thinking about termination, let’s switch to thinking
about proofs. Given a proposition &lt;span class=&quot;math inline&quot;&gt;\(P\)&lt;/span&gt;, we want to prove that
&lt;span class=&quot;math inline&quot;&gt;\(P\)&lt;/span&gt; holds for every value of type &lt;span class=&quot;math inline&quot;&gt;\(A\)&lt;/span&gt;. The idea is that when trying to
prove &lt;span class=&quot;math inline&quot;&gt;\(P(y)\)&lt;/span&gt; for a particular &lt;span class=&quot;math inline&quot;&gt;\(y\)&lt;/span&gt;, we get to assume that &lt;span class=&quot;math inline&quot;&gt;\(P(z)\)&lt;/span&gt; holds
(&lt;em&gt;i.e.&lt;/em&gt; we get to make recursive calls) for all &lt;span class=&quot;math inline&quot;&gt;\(z \prec y\)&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Here, then, is the statement of the principle of well-founded induction, with
each argument broken out on a separate line so we can explain them as
we go.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb70&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb70-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb70-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;wf-ind &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb70-2&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb70-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;{&lt;/span&gt;P &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;P&lt;/code&gt; represents an arbitrary proposition on &lt;code&gt;A&lt;/code&gt;; our goal is to show &lt;code&gt;P&lt;/code&gt; holds for
every value of type &lt;code&gt;A&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb71&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb71-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb71-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;{_&lt;/span&gt;≺&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; Rel A&lt;span class=&quot;ot&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;An arbitrary relation.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb72&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb72-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb72-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  WellFounded &lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt;≺&lt;span class=&quot;ot&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;A proof that &lt;code&gt;≺&lt;/code&gt; is a well-founded relation.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb73&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb73-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb73-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;((&lt;/span&gt;y &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;((&lt;/span&gt;z &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; z ≺ y &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; P z&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; P y&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;This is the trickiest
argument to understand. Intuitively, it says “For any
&lt;code&gt;y&lt;/code&gt;, if we know &lt;code&gt;P z&lt;/code&gt; holds for all &lt;code&gt;z ≺ y&lt;/code&gt;, then we can show &lt;code&gt;P y&lt;/code&gt;
also holds.”&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb74&quot;&gt;&lt;pre class=&quot;sourceCode agda&quot;&gt;&lt;code class=&quot;sourceCode agda&quot;&gt;&lt;span id=&quot;cb74-1&quot;&gt;&lt;a href=&quot;https://byorgey.github.io/blog/rss#cb74-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ot&quot;&gt;(&lt;/span&gt;x &lt;span class=&quot;ot&quot;&gt;:&lt;/span&gt; A&lt;span class=&quot;ot&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ot&quot;&gt;→&lt;/span&gt; P x&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;The principle of well-founded induction says that all of this is
enough to show that &lt;code&gt;P x&lt;/code&gt; holds for &lt;em&gt;all&lt;/em&gt; &lt;code&gt;x : A&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, how do we implement this? If we try something
straightforward, as in &lt;code&gt;wf-ind-bad&lt;/code&gt; below—just call &lt;code&gt;ind&lt;/code&gt; on &lt;code&gt;x&lt;/code&gt;, then call &lt;code&gt;wf-ind&lt;/code&gt; recursively
to fill in the proofs for &lt;code&gt;P z&lt;/code&gt;—of course it does not work; Agda cannot
tell that this is terminating.&lt;span class=&quot;sidenote-wrapper&quot;&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;sn-8&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;sn-8&quot; type=&quot;checkbox&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;As an aside, Agda complains that this definition of &lt;code&gt;wf-ind-bad&lt;/code&gt;
is not terminating—which makes sense—but it continues to complain even
when I include the &lt;code&gt;NON_TERMINATING&lt;/code&gt; pragma, which I don’t
understand. Perhaps this has been fixed in a more recent version of Agda.&lt;br /&gt;
&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt; And this makes sense, because we are
not even using the fact that the relation is well-founded at all!&lt;/p&gt;
&lt;pre class=&quot;plain&quot;&gt;&lt;code&gt;module WFIndBad where

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

&lt;/section&gt;


&lt;section id=&quot;isso-thread&quot;&gt;
  &amp;lt;noscript&amp;gt;Javascript needs to be activated to view comments.&amp;lt;/noscript&amp;gt;
&lt;/section&gt;</description>
	<pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Philip Wadler: Crank GPT</title>
	<guid isPermaLink="false">tag:blogger.com,1999:blog-9757377.post-457312131270879658</guid>
	<link>https://wadler.blogspot.com/2026/06/crank-gpt.html</link>
	<description>&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEhw65gFzQ1T5o8PGOi0MfNtNDB5E1th9uZyXgPwDwpqhZM8h79NKXUM6_11g1RlSFi3cuUpDMQcAR2qRhDx7tYxjrfQdGmZ80g_WjRIPXqr0yxQJLh_LeliasFp7YaQMMZuYJCT-4cN9QwY5fNXCQUvIHXvBAX37mevRc0XwystJx7Nm4OrdTpO&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; height=&quot;372&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEhw65gFzQ1T5o8PGOi0MfNtNDB5E1th9uZyXgPwDwpqhZM8h79NKXUM6_11g1RlSFi3cuUpDMQcAR2qRhDx7tYxjrfQdGmZ80g_WjRIPXqr0yxQJLh_LeliasFp7YaQMMZuYJCT-4cN9QwY5fNXCQUvIHXvBAX37mevRc0XwystJx7Nm4OrdTpO=w640-h372&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt; Not a &lt;a href=&quot;https://crankgpt.com/&quot;&gt;crank&lt;/a&gt; project! Spotted via &lt;a href=&quot;https://www.robinsloan.com/winter-garden/june/&quot;&gt;Robin Sloan&lt;/a&gt;.&lt;p&gt;&lt;/p&gt;</description>
	<pubDate>Wed, 24 Jun 2026 20:01:41 +0000</pubDate>
	<author>noreply@blogger.com (Philip Wadler)</author>
</item>
<item>
	<title>GHC Developer Blog: GHC 9.12.5-rc2 is now available</title>
	<guid isPermaLink="true">http://haskell.org/ghc/blog/20260624-ghc-9.12.5-rc2-released.html</guid>
	<link>http://haskell.org/ghc/blog/20260624-ghc-9.12.5-rc2-released.html</link>
	<description>&lt;h1&gt;GHC 9.12.5-rc2 is now available&lt;/h1&gt;
&lt;h4 class=&quot;text-muted&quot;&gt;mangoiv - 2026-06-24&lt;/h4&gt;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Output log

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

[snip]

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

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

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

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

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

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

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

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

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

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

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

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

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

&lt;span class=&quot;token comment&quot;&gt;-- | Split a 'Diff' list at consecutive 'Both'-'Both' boundaries.&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;{-@ splitBothBoth :: {ds:[ValidListDiff c c] | noFFSS ds} -&amp;gt; [Hunk c] @-}&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;splitBothBoth&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Diff&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Hunk&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;splitBothBoth&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;where&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;{-@ go
          :: g:Hunk c
          -&amp;gt; {xs : [ValidListDiff c c] | noFFSS xs &amp;amp;&amp;amp; not (headAlike g xs) }
          -&amp;gt; [Hunk c] / [len xs]
      @-}&lt;/span&gt;
    &lt;span class=&quot;token hvariable&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Hunk&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Diff&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Hunk&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token hvariable&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Both&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Both&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;xs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;reverse&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;xs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;where&lt;/span&gt;
        &lt;span class=&quot;token hvariable&quot;&gt;lemma&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;lemmaReverseNoStuttering&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token hvariable&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;xs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;xs&lt;/span&gt;
    &lt;span class=&quot;token hvariable&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;reverse&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;where&lt;/span&gt;
        &lt;span class=&quot;token hvariable&quot;&gt;lemma&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;lemmaReverseNoStuttering&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;g&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This binding ultimately gets optimized away by GHC, but LH requires it to satisfy the static checks.
LH didn’t have a means to know that &lt;code class=&quot;language-text&quot;&gt;reverse&lt;/code&gt; preserves the &lt;code class=&quot;language-text&quot;&gt;noStuttering&lt;/code&gt; of a &lt;code class=&quot;language-text&quot;&gt;PolyDiff&lt;/code&gt; list,
so I provided it.&lt;/p&gt;
&lt;p&gt;I decided to &lt;code class=&quot;language-text&quot;&gt;assume&lt;/code&gt; the lemma above on the rationale that its validity is straight-forward,
while its proof would probably not be,
making the disease not worth the medicine.&lt;/p&gt;
&lt;h2 id=&quot;lifting-a-dam&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#lifting-a-dam&quot;&gt;&lt;/a&gt;Lifting a dam&lt;/h2&gt;
&lt;p&gt;After this work I’m flooded with many thoughts and feelings about LH from the user perspective,
but also ideas for important future developments.&lt;/p&gt;
&lt;p&gt;One particular source of difficulty I found is differentiating between the existing means of &lt;em&gt;lifting&lt;/em&gt; a Haskell function into the logic:
&lt;code class=&quot;language-text&quot;&gt;reflect&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;inline&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;measure&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;define&lt;/code&gt;.
By default, Haskell functions like &lt;code class=&quot;language-text&quot;&gt;wfDiag&lt;/code&gt; cannot be used in the refinement type predicates.
They have to be accompanied by an annotation that indicates how to make them available in the predicates,
which I omitted in my examples for the sake of argument.&lt;/p&gt;
&lt;p&gt;Existing documentation does a good job at explaining their requirements and purpose.
Nevertheless, subtle differences in constraint generation and logical expression unfolding aren’t documented,
and these details matter when choosing between them in certain cases.
Addressing this could lead to unifying or deprecating some functionality,
but at least specifying them at a finer grain and adding some use case examples could go a long way.&lt;/p&gt;
&lt;p&gt;A more salient difficulty are the error messages.
They can be baffling,
featuring not very human friendly variable names spread across enormous lists of bindings forming their “context”.
Skimming through this context is a skill that I would love to deprecate.
Looking first at the “inferred type” and the “required type” part at the start of the message is a useful technique,
which can provide a lead to the source of the problem.&lt;/p&gt;
&lt;p&gt;I find refinement types appealing because they are powerful yet non-sophisticated enough to be intuitive.
Nevertheless, getting a function specification checked can become intricate,
requiring additional proving machinery like
function definitions exclusively intended for refinement predicates,
lemmas in dead bindings to pass additional constraints
or even heavy refactoring.
However,
I think the upfront cost of entry can be easily balanced out by using the escape hatches to focus the effort investment.
In the &lt;code class=&quot;language-text&quot;&gt;Diff&lt;/code&gt; package, for instance,
some low hanging fruit could be picked right away after disabling the checks on error triggering functions,
e.g. refining integer values to naturals or enforcing clear-cut relations between record fields,
adding immediate value without additional machinery.&lt;/p&gt;
&lt;p&gt;A drawback is that polymorphism seems at odds with the simplicity of refinements:
the more we want to specify about a value or function, the more we narrow its type.
That said,
there seems to be a correlation between code complexity and LH verification complexity that is worth investigating further:
changes that simplified the verification of an invariant tended to benefit the code quality independently of it.&lt;/p&gt;
&lt;p&gt;Choosing between fight or flight for a given invariant is ultimately about balancing safety gains with added complexity,
and in my experience the code structure is what tips the scale:
it determined both the refactorings I needed and the checks I had to forgo.
My guess is that the whole equation changes when refinement types are a first class consideration during design.&lt;/p&gt;
&lt;h2 id=&quot;clearing-up-the-waters&quot;&gt;&lt;a class=&quot;anchor before&quot; href=&quot;https://www.tweag.io/rss.xml#clearing-up-the-waters&quot;&gt;&lt;/a&gt;Clearing up the waters&lt;/h2&gt;
&lt;p&gt;Hopefully this little epic amounts to a useful case study that,
by showing what using LH is like today,
encourages you to add static checks to an existing codebase
or experiment in your next project with LH in your toolbox,
and the techniques I’ve shared help prioritize the approach.&lt;/p&gt;
&lt;p&gt;I discussed some of LH pain points to offer a balanced view and propose further DX improvements.
There’s much to be done, but it’s steadily getting there.
My opinion is that Liquid Haskell is a viable option today to add formal guarantees to an unsuspecting codebase at a reasonable cost,
as long as the palette of shapes and extent this can take is kept in mind during design.
Know that you’re welcome to contribute to LH development and that we’re ready to help strengthen your codebase.
Just reach out!&lt;/p&gt;
&lt;p&gt;Finally, I would like to express my gratitude to Aleksandr Vershilov, Arnaud Spiwack and Christopher Harrison for reviewing this text,
and notably to Facundo Domínguez whose close collaboration was instrumental to streamline this work.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn-1&quot;&gt;At the time of writing, the static checks are about to be proposed for upstream integration. But they can be found in the &lt;a href=&quot;https://github.com/ucsd-progsys/liquidhaskell/tree/5e043ad25987fed9d11c8df365ac7fae396262d6/tests/Diff&quot;&gt;Liquid Haskell test suite&lt;/a&gt; as well.&lt;a class=&quot;footnote-backref&quot; href=&quot;https://www.tweag.io/rss.xml#fnref-1&quot;&gt;↩&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn-2&quot;&gt;A nice perk of working at Tweag is being supported to do open source contributions during or in-between client projects.&lt;a class=&quot;footnote-backref&quot; href=&quot;https://www.tweag.io/rss.xml#fnref-2&quot;&gt;↩&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn-3&quot;&gt;Found in &lt;a href=&quot;https://github.com/seereason/Diff/pull/21&quot;&gt;https://github.com/seereason/Diff/pull/21&lt;/a&gt; and &lt;a href=&quot;https://github.com/seereason/Diff/pull/23&quot;&gt;https://github.com/seereason/Diff/pull/23&lt;/a&gt;&lt;a class=&quot;footnote-backref&quot; href=&quot;https://www.tweag.io/rss.xml#fnref-3&quot;&gt;↩&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn-4&quot;&gt;Found in &lt;a href=&quot;https://github.com/seereason/Diff/pull/24&quot;&gt;https://github.com/seereason/Diff/pull/24&lt;/a&gt;, &lt;a href=&quot;https://github.com/seereason/Diff/pull/25&quot;&gt;https://github.com/seereason/Diff/pull/25&lt;/a&gt;, &lt;a href=&quot;https://github.com/seereason/Diff/pull/26&quot;&gt;https://github.com/seereason/Diff/pull/26&lt;/a&gt; and &lt;a href=&quot;https://github.com/seereason/Diff/pull/27&quot;&gt;https://github.com/seereason/Diff/pull/27&lt;/a&gt;.&lt;a class=&quot;footnote-backref&quot; href=&quot;https://www.tweag.io/rss.xml#fnref-4&quot;&gt;↩&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn-5&quot;&gt;The coordinates of a node in the edit grid represent the size of the prefix consumed from the first input and the size of the produced prefix of the other input, respectively. Thus, the endpoint has coordinates matching both input lengths. The grid’s most relevant feature is that, in addition to vertical and horizontal edges (corresponding to deletions and additions, respectively), there are “free” diagonal edges wherever both inputs have matching elements.&lt;a class=&quot;footnote-backref&quot; href=&quot;https://www.tweag.io/rss.xml#fnref-5&quot;&gt;↩&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description>
	<pubDate>Thu, 11 Jun 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Stackage Blog: Stackage talk at Haskell Ecosystem Workshop 2026</title>
	<guid isPermaLink="true">https://www.stackage.org/blog/2026/06/hashell-ecosystem-ws-2026-talk</guid>
	<link>https://www.stackage.org/blog/2026/06/hashell-ecosystem-ws-2026-talk</link>
	<description>&lt;h2&gt;Stackage talk at Haskell Ecosystem Workshop 2026&lt;/h2&gt;
&lt;p&gt;Jens Petersen gave a talk about Stackage at
the Haskell Ecosystem Workshop 2026 (4th June),
organized by the Haskell Foundation before Zurihac.&lt;/p&gt;
&lt;p&gt;Here are the html &lt;a href=&quot;https://petersen.fedorapeople.org/talks/hew-2026-stackage.html&quot;&gt;slides&lt;/a&gt; (&lt;a href=&quot;https://petersen.fedorapeople.org/talks/hew-2026-stackage-single.html&quot;&gt;single page html&lt;/a&gt;).&lt;/p&gt;</description>
	<pubDate>Mon, 08 Jun 2026 16:00:00 +0000</pubDate>
</item>
<item>
	<title>Gabriella Gonzalez: Ergonomic overrides for Nixpkgs</title>
	<guid isPermaLink="true">https://haskellforall.com/2026/06/ergonomic-overrides-for-nixpkgs</guid>
	<link>https://haskellforall.com/2026/06/ergonomic-overrides-for-nixpkgs</link>
	<description>Announcement post for the override-utils Nix package</description>
	<pubDate>Sat, 06 Jun 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Well-Typed.Com: Faster Cabal Haskell builds by eliminating redundant work</title>
	<guid isPermaLink="false">http://www.well-typed.com/blog/2026/05/faster-haskell-builds</guid>
	<link>https://well-typed.com/blog/2026/05/faster-haskell-builds</link>
	<description>&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; Build your Haskell projects 10-15% faster with this one simple trick!
(Spoiler: the simple trick is to wait for the next major &lt;code&gt;cabal-install&lt;/code&gt; release.)&lt;/p&gt;
&lt;p&gt;In &lt;a href=&quot;https://well-typed.com/blog/2023/10/sovereign-tech-fund-invests-in-cabal/&quot;&gt;previous work&lt;/a&gt; (paid for by the Sovereign Tech Fund) we
did a lot of heavy lifting to make a major architectural change to &lt;code&gt;Cabal&lt;/code&gt;. That
work is now paying off with practical benefits. This post covers follow-on
architectural improvements to &lt;code&gt;cabal-install&lt;/code&gt; which then enable us to eliminate
redundant work in the &lt;code&gt;configure&lt;/code&gt; phase, yielding significant reductions in
build times.&lt;/p&gt;
&lt;p&gt;The changes will be available to everyone in the next major &lt;code&gt;cabal-install&lt;/code&gt;
release. For a large project like &lt;code&gt;pandoc&lt;/code&gt; (including all of its dependencies)
we measure a 10% (std.dev. 0.6pp) reduction in wall clock time for a 16-way
parallel build with &lt;code&gt;--semaphore&lt;/code&gt;. No user changes are needed to take advantage
of this improvement.&lt;/p&gt;

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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;/p&gt;</description>
	<pubDate>Fri, 22 May 2026 15:51:36 +0000</pubDate>
</item>
<item>
	<title>Haskell Interlude: 82: Fraser Tweedale</title>
	<guid isPermaLink="false">Buzzsprout-19202127</guid>
	<link></link>
	<description>&lt;p&gt;We talked to Fraser Tweedale. Fraser works at Red Hat, and is on the Haskell Security Response Team. We talked about security in the context of Haskell, both technical and organizational issues, and also the political issues involved. Fraser's work is both really important and not well-known in the Haskell ecosystem, so it was high time for him to come on the show.&lt;/p&gt;</description>
	<pubDate>Tue, 19 May 2026 12:00:00 +0000</pubDate>
        <enclosure url="https://www.buzzsprout.com/1817535/episodes/19202127-82-fraser-tweedale.mp3" length="34957725" type="audio/mpeg"/>
</item>
<item>
	<title>Gabriella Gonzalez: Type out the code</title>
	<guid isPermaLink="true">https://haskellforall.com/2026/05/type-out-the-code</guid>
	<link>https://haskellforall.com/2026/05/type-out-the-code</link>
	<description>Freecoding improves broader programming proficiency</description>
	<pubDate>Tue, 19 May 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Eric Kidd: Redoubtful: Linux agent sandbox progress</title>
	<guid isPermaLink="true">http://www.randomhacks.net/2026/05/17/redoubtful-agent-sandbox-progress/</guid>
	<link>http://www.randomhacks.net/2026/05/17/redoubtful-agent-sandbox-progress/</link>
	<description>&lt;p&gt;I’ve also been experimenting with agent sandboxes lately. &lt;a href=&quot;https://github.com/emk/redoubtful&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;redoubtful&lt;/code&gt;&lt;/a&gt; is a work-in-progress sandbox that supports:&lt;/p&gt;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

&lt;p&gt;After that, it’s just packaging everything up nicely and writing some docs, so that other people (or agents) can easily configure it for different purposes.&lt;/p&gt;</description>
	<pubDate>Sun, 17 May 2026 18:50:36 +0000</pubDate>
</item>
<item>
	<title>Eric Kidd: Lab notebook: Edit completion #1</title>
	<guid isPermaLink="true">http://www.randomhacks.net/2026/05/16/lab-notebook-edit-completion-1/</guid>
	<link>http://www.randomhacks.net/2026/05/16/lab-notebook-edit-completion-1/</link>
	<description>&lt;p&gt;I &lt;a href=&quot;https://www.randomhacks.net/2026/05/13/edit-completion-with-qwen36/&quot;&gt;continue to be interested&lt;/a&gt; in late-2024-era edit completion, the “Fill in the Middle” (FIM) models. You know, what Copilot used to do, back before it started generating “mini diffs.” Why?&lt;/p&gt;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

{SUF}{suffix}{PRE}{prefix}{MID}
&lt;/code&gt;&lt;/pre&gt;

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

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

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

&lt;p&gt;I also notice that FIM-style models are &lt;em&gt;notoriously&lt;/em&gt; bad at choosing a good stopping place. This can be fixed with a lot of regexes. But what if our fine-tuning data took care to demonstrate &lt;em&gt;good&lt;/em&gt; stopping places?&lt;/p&gt;</description>
	<pubDate>Sat, 16 May 2026 15:49:55 +0000</pubDate>
</item>
<item>
	<title>Oskar Wickström: Coding on Paper</title>
	<guid isPermaLink="true">https://wickstrom.tech/2026-05-16-coding-on-paper.html</guid>
	<link>https://wickstrom.tech/2026-05-16-coding-on-paper.html</link>
	<description>&lt;p&gt;About three months ago, I bought the &lt;a href=&quot;https://shop.boox.com/products/boox-mira-procolor-version&quot;&gt;Onyx BOOX 25.3” Mira Pro Color&lt;/a&gt;, an e-ink monitor for desktop use. I’ve used it as my primary monitor since, and I’ve had a lot of questions about it. This is my experience report, from the perspective of a working, still mostly typing, programmer.&lt;/p&gt; &lt;p&gt;This is &lt;em&gt;not&lt;/em&gt; a sponsored post, and it is &lt;em&gt;not&lt;/em&gt; a product review. I wrote a very similar post about the &lt;a href=&quot;https://wickstrom.tech/2025-10-10-programming-in-the-sun-a-year-with-the-daylight-computer.html&quot;&gt;Daylight DC-1&lt;/a&gt; last year.&lt;/p&gt; &lt;figure&gt; &lt;img alt=&quot;Neovim in the morning sunlight.&quot; src=&quot;https://wickstrom.tech/assets/mira-pro-1.webp&quot; /&gt; &lt;figcaption&gt;Neovim in the morning sunlight.&lt;/figcaption&gt; &lt;/figure&gt; &lt;p&gt;As explained in last year’s post, the reason I persist with these monitors is because it makes me energetic and happy. Sunlight, direct or indirect, helps me stay clear and focused during my workday. I find spaces illuminated by natural light beautiful and inspiring.&lt;/p&gt; &lt;p&gt;I’m not going to recommend that you buy one of these devices. They’re expensive, about $2000, and the experience is quite different from LCD. Even if this looks cool, it seems to me very possible that most people would not like it in practice. With that said, I am happy with it, and I’ll probably keep investing in these tools as they get even better with time.&lt;/p&gt; &lt;figure&gt; &lt;img alt=&quot;Spending a workday in the garden.&quot; src=&quot;https://wickstrom.tech/assets/mira-pro-2.webp&quot; /&gt; &lt;figcaption&gt;Spending a workday in the garden.&lt;/figcaption&gt; &lt;/figure&gt; &lt;p&gt;Using the Mira Pro as a primary monitor is a continuation of the experiments with my e-ink tablets and Termux as coding environments. But now, with far fewer compromises. I’m running my regular NixOS environment on my work laptop. No SSH and tmux needed, no Android terminal emulator to customize.&lt;/p&gt; &lt;p&gt;What I have done, though, is spent quite some time on making my system more suited for this monitor. The Mira Pro does not work well with dark themes. In fact, it only works well with high contrast light themes.&lt;/p&gt; &lt;p&gt;Luckily, I’m bent towards minimalism, so I already used near-monochrome themes, relying more on typographic syntax highlighting rather than coloring. I now have custom themes for Neovim, Zed, and Ghostty with a few vivid colors for things like selection, comments, and constants. Otherwise it’s largely black on white.&lt;/p&gt; &lt;p&gt;It’s trickier with other applications. In Firefox, I’ve started using the high contrast setting. That works pretty much like an inverse of DarkReader. I now run Spotify in the browser in order to avoid its dark theme.&lt;/p&gt; &lt;p&gt;The monitor has a clunky menu system with which you can change rendering modes; things like contrast and speed. I found &lt;a href=&quot;https://github.com/ipodnerd3019/mira-js&quot;&gt;an open-source reverse-engineered NodeJS package&lt;/a&gt; that I use with Hyprland keybindings to easily change rendering modes and manually refresh. No need for the built-in menu.&lt;/p&gt; &lt;p&gt;In practice I use two modes:&lt;/p&gt; &lt;dl&gt; &lt;dt&gt;Reading:&lt;/dt&gt; &lt;dd&gt; &lt;p&gt;This mode renders colors most vividly and text sharply, but typing with it is agony. I use it when reading text documents, web pages, or code diffs.&lt;/p&gt; &lt;/dd&gt; &lt;dt&gt;Writing:&lt;/dt&gt; &lt;dd&gt; &lt;p&gt;This is by far the most commonly used mode, which compromises colors and sharpness for way better latency. I use this for everything in the terminal, chat, general web browsing, and probably most other things not covered by the reading mode.&lt;/p&gt; &lt;/dd&gt; &lt;/dl&gt; &lt;p&gt;See the following photos for a close-up comparison:&lt;/p&gt; &lt;figure&gt; &lt;img alt=&quot;Reading mode, where colored regions are pretty smooth and text looks sharp.&quot; src=&quot;https://wickstrom.tech/assets/mira-pro-5.webp&quot; /&gt; &lt;figcaption&gt;Reading mode, where colored regions are pretty smooth and text looks sharp.&lt;/figcaption&gt; &lt;/figure&gt; &lt;figure&gt; &lt;img alt=&quot;Writing mode, where colored regions (light gray, red, green) are grainy and text is a bit blurry.&quot; src=&quot;https://wickstrom.tech/assets/mira-pro-6.webp&quot; /&gt; &lt;figcaption&gt;Writing mode, where colored regions (light gray, red, green) are grainy and text is a bit blurry.&lt;/figcaption&gt; &lt;/figure&gt; &lt;p&gt;What about latency? Here’s the two short clips of me typing with the reading and writing modes:&lt;/p&gt; &lt;figure&gt; &lt;video controls=&quot;&quot; src=&quot;https://wickstrom.tech/assets/mira-pro-slow.mp4&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/assets/mira-pro-slow.mp4&quot;&gt;Reading mode, with horrible latency for typing.&lt;/a&gt;&lt;/video&gt; &lt;figcaption&gt;Reading mode, with horrible latency for typing.&lt;/figcaption&gt; &lt;/figure&gt; &lt;figure&gt; &lt;video controls=&quot;&quot; src=&quot;https://wickstrom.tech/assets/mira-pro-fast.mp4&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/assets/mira-pro-fast.mp4&quot;&gt;Writing mode, with some but acceptable latency.&lt;/a&gt;&lt;/video&gt; &lt;figcaption&gt;Writing mode, with some but acceptable latency.&lt;/figcaption&gt; &lt;/figure&gt; &lt;p&gt;Ghosting? In my writing mode it’s minimal. It really doesn’t bother me.&lt;/p&gt; &lt;p&gt;About the color panel: I don’t like it very much to be honest. It was the only version of the Mira Pro available from the Swedish retailer at the time, so I went with it. I think I would’ve been happier with a monochrome panel, because the coloring technology makes it considerably darker.&lt;/p&gt; &lt;p&gt;Here’s a comparison between the Palma 2 Pro (using a similar but smaller Kaleido color panel) and my old Tab Ultra (with a monochrome panel):&lt;/p&gt; &lt;figure&gt; &lt;img alt=&quot;Color vs Monochrome e-ink panels without backlight.&quot; src=&quot;https://wickstrom.tech/assets/mira-pro-7.webp&quot; /&gt; &lt;figcaption&gt;Color vs Monochrome e-ink panels without backlight.&lt;/figcaption&gt; &lt;/figure&gt; &lt;p&gt;Unless the room has great diffuse lighting, natural or otherwise, the color panel does require &lt;em&gt;some&lt;/em&gt; backlight. In direct sunlight or outdoors it works without. I might spend more time optimizing the lighting in my office to make this work during the winter months.&lt;/p&gt; &lt;p&gt;So, what’s to make of it? Personally, I enjoy using this monitor a lot, even if it’s not perfect. Should you buy an expensive 25” e-ink monitor? I cannot say. But if you do, let me know how it works out.&lt;/p&gt; &lt;p&gt;My custom themes and keybindings can be found &lt;a href=&quot;https://github.com/owickstrom/nixos/tree/master&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;</description>
	<pubDate>Fri, 15 May 2026 22:00:00 +0000</pubDate>
</item>
<item>
	<title>Eric Kidd: I should blog more</title>
	<guid isPermaLink="true">http://www.randomhacks.net/2026/05/13/i-should-blog-more/</guid>
	<link>http://www.randomhacks.net/2026/05/13/i-should-blog-more/</link>
	<description>&lt;p&gt;This blog is ancient, in blog years. The first post was on June 30, 1998, and it featured a &lt;a href=&quot;https://www.randomhacks.net/1998/06/30/randomhacks-online-mathmap/&quot;&gt;randomized emboss for MathMap&lt;/a&gt;. Back in those days, it was a mix of neat little snippets like that and interesting links. The site was a single, hand-edited HTML file in reverse chronological order. It ran on a Linux mini-tower built from parts from &lt;a href=&quot;https://w1mx.mit.edu/flea-at-mit/&quot;&gt;the MIT Swapfest&lt;/a&gt;, and it lived under my desk.&lt;/p&gt;

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

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

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

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

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

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

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

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

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

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

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

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

&lt;p&gt;But this is an actual, working, 100% local autocomplete. And it’s &lt;em&gt;close&lt;/em&gt; to being actually good.&lt;/p&gt;</description>
	<pubDate>Wed, 13 May 2026 05:04:52 +0000</pubDate>
</item>
<item>
	<title>Oskar Wickström: Catching Typos on My Website with Browser Testing</title>
	<guid isPermaLink="true">https://wickstrom.tech/2026-05-13-catching-typos-website-browser-testing.html</guid>
	<link>https://wickstrom.tech/2026-05-13-catching-typos-website-browser-testing.html</link>
	<description>&lt;p&gt;One neat thing about &lt;a href=&quot;https://antithesishq.github.io/bombadil/3-specification-language.html#specification-language&quot;&gt;Bombadil’s specification language&lt;/a&gt; is that it’s plain TypeScript, with access to external NPM packages. I’ve written a specification that spell-checks my website — what you’re reading now — and I want to share how that turned out.&lt;/p&gt; &lt;dl&gt; &lt;dt&gt;The inner loop (spell-checking):&lt;/dt&gt; &lt;dd&gt; &lt;p&gt;Bombadil randomly walks the website and collects misspelled words as property violations. The specification uses &lt;a href=&quot;https://github.com/wooorm/nspell&quot;&gt;nspell&lt;/a&gt; with &lt;a href=&quot;https://github.com/wooorm/dictionaries/tree/main/dictionaries/en&quot;&gt;American and British English dictionaries&lt;/a&gt; and a personal word list in the repository. This is &lt;em&gt;fast&lt;/em&gt; and &lt;em&gt;strict&lt;/em&gt;.&lt;/p&gt; &lt;/dd&gt; &lt;dt&gt;The outer loop (triage):&lt;/dt&gt; &lt;dd&gt; &lt;p&gt;I’m running Claude Code with a spell-checking skill, a triage loop that goes something like this:&lt;/p&gt; &lt;ol type=&quot;1&quot;&gt; &lt;li&gt;Run Bombadil against the local development server for 5 minutes and capture the output. If no words flagged, we’re done.&lt;/li&gt; &lt;li&gt;Collect each flagged word and the URL it appeared on.&lt;/li&gt; &lt;li&gt;Triage each word into one of these buckets: &lt;ul&gt; &lt;li&gt;Real typo: fix the markdown source&lt;/li&gt; &lt;li&gt;Legitimate common word: add to the custom dictionary&lt;/li&gt; &lt;li&gt;Legitimate uncommon or very technical word: mark inline with &lt;code&gt;spellcheck=&quot;false&quot;&lt;/code&gt;&lt;/li&gt; &lt;li&gt;Extraction noise: add a unit test and fix the word extractor&lt;/li&gt; &lt;/ul&gt;&lt;/li&gt; &lt;li&gt;Run Bombadil against each failing URL to confirm the corrections.&lt;/li&gt; &lt;li&gt;Go to step 1.&lt;/li&gt; &lt;/ol&gt; &lt;p&gt;This is &lt;em&gt;slow&lt;/em&gt; and &lt;em&gt;loose&lt;/em&gt;.&lt;/p&gt; &lt;/dd&gt; &lt;/dl&gt; &lt;p&gt;The hybrid model seems to work well; it has flagged words in almost every blog post. It has fixed 13 real typos and added 130+ words to my personal dictionary. &lt;span&gt;Example typos include “forseeable”, “similiar”, “perculiar”, “occured”. Some of these were 10 years old.&lt;/span&gt;&lt;/p&gt; &lt;p&gt;Claude doesn’t have to waste tokens spell-checking everything over and over. Right now I’m just running this locally, but you could imagine a more elaborate setup for large websites where the “inner loop” runs as a nightly job, invoking the “outer loop” only on violations. You could involve a human where needed, and build up a domain-specific dictionary over time.&lt;/p&gt; &lt;p&gt;Note that using an LLM is entirely optional. It just saves me some time. You can do triage on your own.&lt;/p&gt; &lt;p&gt;Why not spell-check the sources directly? Yes, that is often preferable, and I use &lt;code&gt;spell&lt;/code&gt; in Neovim all the time. But it’s not always practical. At least in my experience, the tooling trips up on syntax and templating in more complicated setups. Maybe your editor handles this better than mine does, or maybe you’re fine with tools like &lt;a href=&quot;https://crates.io/crates/typos-cli&quot;&gt;typos&lt;/a&gt; and &lt;a href=&quot;https://github.com/codespell-project/codespell&quot;&gt;codespell&lt;/a&gt;, but I like the fact that this approach is external and checks the rendered output. Given that Bombadil interacts with web applications, you could even run this against dynamic applications to spell-check states deep in the UI.&lt;/p&gt; &lt;p&gt;Speaking of source-level checking: since the custom dictionary is a plain word list, I point Neovim’s &lt;code&gt;spellfile&lt;/code&gt; at it and use &lt;code&gt;zg&lt;/code&gt; to add words while I edit. A single source of truth that both tools write to.&lt;/p&gt; &lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode lua&quot;&gt;&lt;code class=&quot;sourceCode lua&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb1-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;va&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;opt&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;spellfile&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;/path/to/custom.utf-8.add&quot;&lt;/span&gt;&lt;/span&gt; &lt;span id=&quot;cb1-2&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/feed.xml#cb1-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;va&quot;&gt;vim&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;opt&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;spelllang&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;en&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; &lt;p&gt;Being able to use NPM packages in specifications has turned out to be more useful than I expected. In addition to &lt;code&gt;nspell&lt;/code&gt;, I’m using &lt;a href=&quot;https://www.npmjs.com/package/tlds&quot;&gt;tlds&lt;/a&gt; to identify URLs. Bombadil is built for property-based testing of web applications, but with a specification language and package ecosystem at hand, its uses might be broader than my original vision.&lt;/p&gt; &lt;p&gt;If you’re interested in setting up something like this on your own, you’ll find the sources in &lt;a href=&quot;https://github.com/owickstrom/bombadil-playground/tree/master/wickstrom.tech&quot;&gt;my Bombadil playground&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;&lt;em&gt;Disclosure: I’m the original author and lead for the Bombadil project at Antithesis.&lt;/em&gt;&lt;/p&gt;</description>
	<pubDate>Tue, 12 May 2026 22:00:00 +0000</pubDate>
</item>
<item>
	<title>Well-Typed.Com: Exception Annotations: Lay of the Land</title>
	<guid isPermaLink="false">http://www.well-typed.com/blog/2026/05/lay-annotation-land</guid>
	<link>https://well-typed.com/blog/2026/05/lay-annotation-land</link>
	<description>&lt;p&gt;Exception annotations were introduced in GHC 9.10, and can be an invaluable tool
for debugging thorny problems. The initial implementation had some important
limitations that made them less useful in practice than one might hope, but
fortunately the situation has since been much improved. In this blog post we
will give a detailed overview of the status quo as of GHC 9.12/9.14, identify
some gotchas you should be aware and provide advise on how to deal with them,
and briefly look ahead to what will change in GHC 10.0. We will also dedicate a
section to discussing the problems in GHC 9.10, for those who cannot yet
upgrade.&lt;/p&gt;

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

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

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

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

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

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

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

&lt;p&gt;
This makes it easier to make a change, fix the errors caused by the change and
then return to where I was.
&lt;/p&gt;
&lt;div class=&quot;taglist&quot;&gt;&lt;a href=&quot;https://magnus.therning.org/tags.html&quot;&gt;&lt;span class=&quot;tag-label&quot;&gt;Tags&lt;/span&gt;&lt;/a&gt;&lt;span class=&quot;tag-separator&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;taglist__tags&quot;&gt;&lt;a class=&quot;tag&quot; href=&quot;https://magnus.therning.org/tag-emacs.html&quot;&gt;emacs&lt;/a&gt; &lt;a class=&quot;tag&quot; href=&quot;https://magnus.therning.org/tag-evil.html&quot;&gt;evil&lt;/a&gt; &lt;/span&gt;&lt;/div&gt;</description>
	<pubDate>Mon, 04 May 2026 06:16:00 +0000</pubDate>
</item>
<item>
	<title>Magnus Therning: Follow-up on switching to eglot</title>
	<guid isPermaLink="true">https://magnus.therning.org/2026-05-02-follow-up-on-switching-to-eglot.html</guid>
	<link>https://magnus.therning.org/2026-05-02-follow-up-on-switching-to-eglot.html</link>
	<description>&lt;p&gt;
Jan G sent me a two-part comment.
&lt;/p&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-org3a78e0b&quot;&gt;
&lt;h2 id=&quot;org3a78e0b&quot;&gt;Part one&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-org3a78e0b&quot;&gt;
&lt;blockquote&gt;
&lt;p&gt;
I was under the impression that when using elpaca you needed to disable
use-package, and that when using elpaca-use-package, you were redefining the
macro. Iâ€™m not 100% sure about this, but the documentation has an example of
use-package and how it actually expands to an elpaca command.
&lt;/p&gt;
&lt;/blockquote&gt;

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

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

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

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

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

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

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

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

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

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

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

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

&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-org&quot;&gt;&lt;code&gt;&lt;span class=&quot;org-org-modern-block-name&quot;&gt;&lt;span class=&quot;org-org-block-begin-line&quot;&gt;SRC&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-org-block-begin-line&quot;&gt; sql-mode :product oracle :dbconnection i3v1e-ro :results raw
&lt;/span&gt;&lt;span class=&quot;org-org-block&quot;&gt;SELECT to_char(sysdate, 'YYYY-MM-DD HH24:ii:ss') AS today,
       to_char(sysdate + 1, 'YYYY-MM-DD HH24:ii:ss') AS tomorrow
FROM dual;
&lt;/span&gt;&lt;span class=&quot;org-org-modern-block-name&quot;&gt;&lt;span class=&quot;org-org-block-end-line&quot;&gt;SRC&lt;/span&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-org6448d06&quot;&gt;
&lt;h2 id=&quot;org6448d06&quot;&gt;Thoughts&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-org6448d06&quot;&gt;
&lt;p&gt;
Both of these feel closer to the intent of &lt;code&gt;sql-mode&lt;/code&gt; in a way. I'll have to try
using &lt;code&gt;sql-connection-alist&lt;/code&gt; at some point.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;taglist&quot;&gt;&lt;a href=&quot;https://magnus.therning.org/tags.html&quot;&gt;Tags&lt;/a&gt;: &lt;a href=&quot;https://magnus.therning.org/tag-emacs.html&quot;&gt;emacs&lt;/a&gt; &lt;/div&gt;</description>
	<pubDate>Sat, 02 May 2026 10:41:00 +0000</pubDate>
</item>
<item>
	<title>Oskar Wickström: The Bombadil Terminal Experiment</title>
	<guid isPermaLink="true">https://wickstrom.tech/2026-04-30-bombadil-terminal-experiment.html</guid>
	<link>https://wickstrom.tech/2026-04-30-bombadil-terminal-experiment.html</link>
	<description>&lt;p&gt;Last week at &lt;a href=&quot;https://antithesis.com/bugbash/conference2026/&quot;&gt;Bug Bash 2026&lt;/a&gt;, I had a bunch of interesting discussions about testing non-web interfaces with &lt;a href=&quot;http://bombadil.bot/&quot;&gt;Bombadil&lt;/a&gt;, our new property-based testing framework for user interfaces. One direction that I already wanted to explore is &lt;em&gt;terminal user interfaces&lt;/em&gt; (TUIs), and the hallway discussions gave me a nudge to get going. I started hacking on the flight back home, and a few days later that embryo of a TUI fuzzer started to emerge.&lt;/p&gt; &lt;figure&gt; &lt;video controls=&quot;&quot; src=&quot;https://wickstrom.tech/assets/tetris-stuck.mp4&quot;&gt;&lt;a href=&quot;https://wickstrom.tech/assets/tetris-stuck.mp4&quot;&gt;The fuzzer in action, finding a bug in vitetris. (CW: flashing!)&lt;/a&gt;&lt;/video&gt; &lt;figcaption&gt;The fuzzer in action, finding a bug in vitetris. (CW: flashing!)&lt;/figcaption&gt; &lt;/figure&gt; &lt;p&gt;It’s built on top of two key crates:&lt;/p&gt; &lt;ol type=&quot;1&quot;&gt; &lt;li&gt;&lt;a href=&quot;https://crates.io/crates/portable-pty&quot;&gt;portable-pty&lt;/a&gt;, a pseudo-teletype in Rust that runs the program under test, and&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://crates.io/crates/libghostty-vt&quot;&gt;libghostty-vt&lt;/a&gt;, a Rust wrapper around the Zig library, which interprets the output of the PTY and provides a virtual terminal API from which you can read cell contents, styles, scroll through the scrollback, etc.&lt;/li&gt; &lt;/ol&gt; &lt;p&gt;With these two in place, I built a &lt;em&gt;very&lt;/em&gt; basic fuzzer for TUIs: it runs the command you give it, polls its output, and writes interleaved random input sequences (printable ASCII characters and ANSI escape sequences). It also scrolls and resizes the terminal occasionally. Timing is a bit tricky, but it seems the current approach works fine: polling reads until the terminal is idle, capture state, then apply new inputs. Regarding speed, it depends a lot on the program being tested, but it looks capable of capturing at least 300 states per second.&lt;/p&gt; &lt;p&gt;I tried finding some basic TUI programs and terminal games to test. Much to my surprise, within the first few days I had found four seemingly real bugs in real software:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a href=&quot;https://github.com/vicgeralds/vitetris&quot;&gt;vitetris&lt;/a&gt; has a bug where if you enter just a number in the host name (e.g. &lt;code&gt;6&lt;/code&gt;) and try to connect to a remote game, the UI freezes.&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://github.com/aristocratos/btop&quot;&gt;btop&lt;/a&gt; has two different bugs, &lt;a href=&quot;https://github.com/aristocratos/btop/issues/1010&quot;&gt;one recently fixed&lt;/a&gt; that I confirmed fixed with the latest version (1.4.6), and &lt;a href=&quot;https://github.com/aristocratos/btop/issues/1627&quot;&gt;one that I just reported&lt;/a&gt;. Both were triggered by this fuzzer.&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://github.com/hanslub42/rlwrap&quot;&gt;rlwrap&lt;/a&gt; got into a segfault which I haven’t yet been able to troubleshoot.&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;Pretty cool. Today, I merged this work to &lt;code&gt;main&lt;/code&gt; in Bombadil. It’s not yet released, but if you’re curious you can try it already by downloading a &lt;code&gt;bombadil-terminal&lt;/code&gt; binary from the &lt;a href=&quot;https://github.com/antithesishq/bombadil/actions/workflows/ci.yml&quot;&gt;CI&lt;/a&gt; artifacts. On macOS you’ll need to remove the quarantine bit to bypass GateKeeper.&lt;/p&gt; &lt;p&gt;Now, the work remains to make this a solid tool. Here are some future goals:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Integrate it with the specification framework in Bombadil, so that you can define custom properties and action generators. It’d be neat to provide an API akin to &lt;code&gt;querySelector&lt;/code&gt; that could parse and traverse panels drawn with box-drawing characters. You probably also want to validate that those borders line up correctly.&lt;/li&gt; &lt;li&gt;Generate a lot more diverse input and terminal actions. For instance, generate sequences from the &lt;a href=&quot;https://sw.kovidgoyal.net/kitty/keyboard-protocol/&quot;&gt;Kitty keyboard protocol&lt;/a&gt;.&lt;/li&gt; &lt;li&gt;Make the test runner’s user interface better. Perhaps a TUI?!&lt;/li&gt; &lt;li&gt;Make this part of the ordinary &lt;code&gt;bombadil&lt;/code&gt; binary, I think. There could be subcommands for &lt;code&gt;browser&lt;/code&gt; and &lt;code&gt;terminal&lt;/code&gt; testing tools.&lt;/li&gt; &lt;li&gt;Run it in Antithesis to see what that fuzzer can find.&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;All right, short post today — I just wanted to share my excitement and early results.&lt;/p&gt; &lt;p&gt;&lt;em&gt;A huge thanks to &lt;a href=&quot;https://github.com/Uzaaft&quot;&gt;Uzair Aftab&lt;/a&gt;, maintainer of &lt;a href=&quot;https://github.com/Uzaaft/libghostty-rs&quot;&gt;libghostty-rs&lt;/a&gt;, for helping me get libghostty-vt building under Nix!&lt;/em&gt;&lt;/p&gt;</description>
	<pubDate>Wed, 29 Apr 2026 22:00:00 +0000</pubDate>
</item>
<item>
	<title>Donnacha Oisín Kidney: Tries for Polynomials</title>
	<guid isPermaLink="true">https://doisinkidney.com/posts/2026-04-28-poly-trie.html</guid>
	<link>https://doisinkidney.com/posts/2026-04-28-poly-trie.html</link>
	<description>&lt;div class=&quot;info&quot;&gt;
    Posted on April 28, 2026
&lt;/div&gt;
&lt;div class=&quot;info&quot;&gt;
    
&lt;/div&gt;
&lt;div class=&quot;info&quot;&gt;
    
        Tags: &lt;a href=&quot;https://doisinkidney.com/tags/Haskell.html&quot; rel=&quot;tag&quot; title=&quot;All pages tagged 'Haskell'.&quot;&gt;Haskell&lt;/a&gt;
    
&lt;/div&gt;

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

Implementation of an Evaluator for Polynomials in Arbitrary Variables

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

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

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

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

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

Tweet Trie

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

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

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

</channel>
</rss>
