<?xml version="1.0" encoding="UTF-8"?><rss dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><title>in Code — Entries</title><link>https://blog.jle.im/</link><description>Weblog of Justin Le, covering various adventures in programming and explorations in the worlds of computation physics, and knowledge.
</description><item><title>"Five-Point Haskell": Unconditional Election (via Parametricity)</title><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="https://blog.jle.im/entries/series/+five-point-haskell.html"&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="https://blog.jle.im/entry/five-point-haskell-part-1-total-depravity.html"&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="choice-is-a-prison"&gt;Choice is a Prison&lt;/h2&gt;
&lt;h3 id="conditional-election"&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="sourceCode" id="cb1"&gt;&lt;pre class="sourceCode java"&gt;&lt;code class="sourceCode java"&gt;&lt;span id="cb1-1"&gt;&lt;a href="#cb1-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;static&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&lt;/span&gt;T&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; T &lt;span class="fu"&gt;foo&lt;/span&gt;&lt;span class="op"&gt;(&lt;/span&gt;T x&lt;span class="op"&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="sourceCode" id="cb2"&gt;&lt;pre class="sourceCode java"&gt;&lt;code class="sourceCode java"&gt;&lt;span id="cb2-1"&gt;&lt;a href="#cb2-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;static&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&lt;/span&gt;T&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; T &lt;span class="fu"&gt;foo&lt;/span&gt;&lt;span class="op"&gt;(&lt;/span&gt;T x&lt;span class="op"&gt;)&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-2"&gt;&lt;a href="#cb2-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="cf"&gt;if&lt;/span&gt; &lt;span class="op"&gt;(&lt;/span&gt;x &lt;span class="kw"&gt;instanceof&lt;/span&gt; &lt;span class="bu"&gt;Integer&lt;/span&gt; i&lt;span class="op"&gt;)&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-3"&gt;&lt;a href="#cb2-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="cf"&gt;return&lt;/span&gt; &lt;span class="op"&gt;(&lt;/span&gt;T&lt;span class="op"&gt;)&lt;/span&gt; &lt;span class="bu"&gt;Integer&lt;/span&gt;&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="fu"&gt;valueOf&lt;/span&gt;&lt;span class="op"&gt;(-&lt;/span&gt;i&lt;span class="op"&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-4"&gt;&lt;a href="#cb2-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-5"&gt;&lt;a href="#cb2-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="cf"&gt;return&lt;/span&gt; x&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-6"&gt;&lt;a href="#cb2-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&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="sourceCode" id="cb3"&gt;&lt;pre class="sourceCode typescript"&gt;&lt;code class="sourceCode typescript"&gt;&lt;span id="cb3-1"&gt;&lt;a href="#cb3-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;function&lt;/span&gt; &lt;span class="fu"&gt;foo&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;T&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;(x&lt;span class="op"&gt;:&lt;/span&gt; T)&lt;span class="op"&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="sourceCode" id="cb4"&gt;&lt;pre class="sourceCode typescript"&gt;&lt;code class="sourceCode typescript"&gt;&lt;span id="cb4-1"&gt;&lt;a href="#cb4-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;function&lt;/span&gt; &lt;span class="fu"&gt;foo&lt;/span&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;T&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;(x&lt;span class="op"&gt;:&lt;/span&gt; T)&lt;span class="op"&gt;:&lt;/span&gt; T {&lt;/span&gt;
&lt;span id="cb4-2"&gt;&lt;a href="#cb4-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="cf"&gt;if&lt;/span&gt; (&lt;span class="kw"&gt;typeof&lt;/span&gt; x &lt;span class="op"&gt;===&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;number&amp;quot;&lt;/span&gt;) {&lt;/span&gt;
&lt;span id="cb4-3"&gt;&lt;a href="#cb4-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="cf"&gt;return&lt;/span&gt; (&lt;span class="op"&gt;-&lt;/span&gt;x) &lt;span class="im"&gt;as&lt;/span&gt; &lt;span class="dt"&gt;any&lt;/span&gt; &lt;span class="im"&gt;as&lt;/span&gt; T&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-4"&gt;&lt;a href="#cb4-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  }&lt;/span&gt;
&lt;span id="cb4-5"&gt;&lt;a href="#cb4-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="cf"&gt;return&lt;/span&gt; x&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-6"&gt;&lt;a href="#cb4-6" aria-hidden="true" tabindex="-1"&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="sourceCode" id="cb5"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb5-1"&gt;&lt;a href="#cb5-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;foo ::&lt;/span&gt; a &lt;span class="ot"&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="https://www.cse.chalmers.se/~nad/publications/danielsson-popl2006-tr.pdf"&gt;non-termination&lt;/a&gt;&lt;a
href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;
and other escape hatches&lt;a href="#fn2" class="footnote-ref" id="fnref2"
role="doc-noteref"&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="sourceCode" id="cb6"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb6-1"&gt;&lt;a href="#cb6-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;foo ::&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; a&lt;/span&gt;
&lt;span id="cb6-2"&gt;&lt;a href="#cb6-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;foo x &lt;span class="ot"&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="sourceCode" id="cb7"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb7-1"&gt;&lt;a href="#cb7-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;foo ::&lt;/span&gt; &lt;span class="kw"&gt;forall&lt;/span&gt; a&lt;span class="op"&gt;.&lt;/span&gt; a &lt;span class="ot"&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="sourceCode" id="cb8"&gt;&lt;pre class="sourceCode java"&gt;&lt;code class="sourceCode java"&gt;&lt;span id="cb8-1"&gt;&lt;a href="#cb8-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;static&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&lt;/span&gt;T&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="bu"&gt;String&lt;/span&gt; &lt;span class="fu"&gt;foo&lt;/span&gt;&lt;span class="op"&gt;(&lt;/span&gt;T x&lt;span class="op"&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="sourceCode" id="cb9"&gt;&lt;pre class="sourceCode java"&gt;&lt;code class="sourceCode java"&gt;&lt;span id="cb9-1"&gt;&lt;a href="#cb9-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;static&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&lt;/span&gt;T&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="bu"&gt;String&lt;/span&gt; &lt;span class="fu"&gt;foo&lt;/span&gt;&lt;span class="op"&gt;(&lt;/span&gt;T x&lt;span class="op"&gt;)&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt; &lt;span class="cf"&gt;return&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;hello&amp;quot;&lt;/span&gt;&lt;span class="op"&gt;;&lt;/span&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb9-2"&gt;&lt;a href="#cb9-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;static&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&lt;/span&gt;T&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="bu"&gt;String&lt;/span&gt; &lt;span class="fu"&gt;foo&lt;/span&gt;&lt;span class="op"&gt;(&lt;/span&gt;T x&lt;span class="op"&gt;)&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt; &lt;span class="cf"&gt;return&lt;/span&gt; x&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="fu"&gt;toString&lt;/span&gt;&lt;span class="op"&gt;();&lt;/span&gt; &lt;span class="op"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb9-3"&gt;&lt;a href="#cb9-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;static&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&lt;/span&gt;T&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="bu"&gt;String&lt;/span&gt; &lt;span class="fu"&gt;foo&lt;/span&gt;&lt;span class="op"&gt;(&lt;/span&gt;T x&lt;span class="op"&gt;)&lt;/span&gt; &lt;span class="op"&gt;{&lt;/span&gt; &lt;span class="cf"&gt;return&lt;/span&gt; x&lt;span class="op"&gt;.&lt;/span&gt;&lt;span class="fu"&gt;getClass&lt;/span&gt;&lt;span class="op"&gt;().&lt;/span&gt;&lt;span class="fu"&gt;getSimpleName&lt;/span&gt;&lt;span class="op"&gt;();&lt;/span&gt; &lt;span class="op"&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="sourceCode" id="cb10"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb10-1"&gt;&lt;a href="#cb10-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;foo ::&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb10-2"&gt;&lt;a href="#cb10-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;foo _ &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;hello&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb10-3"&gt;&lt;a href="#cb10-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- or&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb10-4"&gt;&lt;a href="#cb10-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;foo _ &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;goodbye&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb10-5"&gt;&lt;a href="#cb10-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- or&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb10-6"&gt;&lt;a href="#cb10-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;foo _ &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;i always ignore my input&amp;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="sourceCode" id="cb11"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb11-1"&gt;&lt;a href="#cb11-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;foo ::&lt;/span&gt; &lt;span class="dt"&gt;Show&lt;/span&gt; a &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb11-2"&gt;&lt;a href="#cb11-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;foo _ &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;hello&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb11-3"&gt;&lt;a href="#cb11-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- or&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb11-4"&gt;&lt;a href="#cb11-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;foo x &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;show&lt;/span&gt; x&lt;/span&gt;
&lt;span id="cb11-5"&gt;&lt;a href="#cb11-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- or&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb11-6"&gt;&lt;a href="#cb11-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;foo x &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;reversed: &amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;reverse&lt;/span&gt; (&lt;span class="fu"&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="sourceCode" id="cb12"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb12-1"&gt;&lt;a href="#cb12-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;foo ::&lt;/span&gt; (a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt;) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb12-2"&gt;&lt;a href="#cb12-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;foo showVal x &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="co"&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="the-guessing-game"&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="sourceCode" id="cb13"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb13-1"&gt;&lt;a href="#cb13-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;mystery ::&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; b &lt;span class="ot"&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="sourceCode" id="cb14"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb14-1"&gt;&lt;a href="#cb14-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;turmeric ::&lt;/span&gt; ((a, b) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; c) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; b &lt;span class="ot"&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="sourceCode" id="cb15"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb15-1"&gt;&lt;a href="#cb15-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;turmeric ::&lt;/span&gt; ((a, b) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; c) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; b &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; c&lt;/span&gt;
&lt;span id="cb15-2"&gt;&lt;a href="#cb15-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;turmeric f x y &lt;span class="ot"&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="https://blog.jle.im/entry/the-baby-paradox-in-haskell.html#haskell-as-a-theorem-prover"&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="sourceCode" id="cb16"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb16-1"&gt;&lt;a href="#cb16-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;theThing ::&lt;/span&gt; [a] &lt;span class="ot"&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="https://people.mpi-sws.org/~dreyer/tor/papers/wadler.pdf"&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="sourceCode" id="cb17"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb17-1"&gt;&lt;a href="#cb17-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;theThing &lt;span class="op"&gt;.&lt;/span&gt; &lt;span class="fu"&gt;map&lt;/span&gt; f&lt;/span&gt;
&lt;span id="cb17-2"&gt;&lt;a href="#cb17-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;==&lt;/span&gt; &lt;span class="fu"&gt;map&lt;/span&gt; f &lt;span class="op"&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="sourceCode" id="cb18"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb18-1"&gt;&lt;a href="#cb18-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;sort&lt;/span&gt; &lt;span class="op"&gt;.&lt;/span&gt; &lt;span class="fu"&gt;map&lt;/span&gt; &lt;span class="fu"&gt;abs&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; [&lt;span class="dv"&gt;5&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;1&lt;/span&gt;,&lt;span class="dv"&gt;3&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;7&lt;/span&gt;]&lt;/span&gt;
&lt;span id="cb18-2"&gt;&lt;a href="#cb18-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;[&lt;span class="dv"&gt;1&lt;/span&gt;,&lt;span class="dv"&gt;3&lt;/span&gt;,&lt;span class="dv"&gt;5&lt;/span&gt;,&lt;span class="dv"&gt;7&lt;/span&gt;]&lt;/span&gt;
&lt;span id="cb18-3"&gt;&lt;a href="#cb18-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;map&lt;/span&gt; &lt;span class="fu"&gt;abs&lt;/span&gt; &lt;span class="op"&gt;.&lt;/span&gt; &lt;span class="fu"&gt;sort&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; [&lt;span class="dv"&gt;5&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;1&lt;/span&gt;,&lt;span class="dv"&gt;3&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;7&lt;/span&gt;]&lt;/span&gt;
&lt;span id="cb18-4"&gt;&lt;a href="#cb18-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;[&lt;span class="dv"&gt;7&lt;/span&gt;,&lt;span class="dv"&gt;1&lt;/span&gt;,&lt;span class="dv"&gt;3&lt;/span&gt;,&lt;span class="dv"&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="sourceCode" id="cb19"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb19-1"&gt;&lt;a href="#cb19-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;take&lt;/span&gt; &lt;span class="dv"&gt;3&lt;/span&gt; &lt;span class="op"&gt;.&lt;/span&gt; &lt;span class="fu"&gt;map&lt;/span&gt; &lt;span class="fu"&gt;abs&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; [&lt;span class="dv"&gt;5&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;1&lt;/span&gt;,&lt;span class="dv"&gt;3&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;7&lt;/span&gt;]&lt;/span&gt;
&lt;span id="cb19-2"&gt;&lt;a href="#cb19-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;[&lt;span class="dv"&gt;5&lt;/span&gt;,&lt;span class="dv"&gt;1&lt;/span&gt;,&lt;span class="dv"&gt;3&lt;/span&gt;]&lt;/span&gt;
&lt;span id="cb19-3"&gt;&lt;a href="#cb19-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;map&lt;/span&gt; &lt;span class="fu"&gt;abs&lt;/span&gt; &lt;span class="op"&gt;.&lt;/span&gt; &lt;span class="fu"&gt;take&lt;/span&gt; &lt;span class="dv"&gt;3&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; [&lt;span class="dv"&gt;5&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;1&lt;/span&gt;,&lt;span class="dv"&gt;3&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;7&lt;/span&gt;]&lt;/span&gt;
&lt;span id="cb19-4"&gt;&lt;a href="#cb19-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;[&lt;span class="dv"&gt;5&lt;/span&gt;,&lt;span class="dv"&gt;1&lt;/span&gt;,&lt;span class="dv"&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="sourceCode" id="cb20"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb20-1"&gt;&lt;a href="#cb20-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;doIt ::&lt;/span&gt; [a] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&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="1"&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="sourceCode" id="cb21"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb21-1"&gt;&lt;a href="#cb21-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- no free theorem: `minimumMay :: [Int] -&amp;gt; Maybe Int`&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb21-2"&gt;&lt;a href="#cb21-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; minimumMay &lt;span class="op"&gt;.&lt;/span&gt; &lt;span class="fu"&gt;map&lt;/span&gt; &lt;span class="fu"&gt;abs&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; [&lt;span class="dv"&gt;5&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;1&lt;/span&gt;,&lt;span class="dv"&gt;3&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;7&lt;/span&gt;]&lt;/span&gt;
&lt;span id="cb21-3"&gt;&lt;a href="#cb21-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;Just&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb21-4"&gt;&lt;a href="#cb21-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;fmap&lt;/span&gt; &lt;span class="fu"&gt;abs&lt;/span&gt; &lt;span class="op"&gt;.&lt;/span&gt; minimumMay &lt;span class="op"&gt;$&lt;/span&gt; [&lt;span class="dv"&gt;5&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;1&lt;/span&gt;,&lt;span class="dv"&gt;3&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;7&lt;/span&gt;]&lt;/span&gt;
&lt;span id="cb21-5"&gt;&lt;a href="#cb21-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;Just&lt;/span&gt; &lt;span class="dv"&gt;7&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb21-6"&gt;&lt;a href="#cb21-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb21-7"&gt;&lt;a href="#cb21-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- free theorem: `listToMaybe :: [a] -&amp;gt; Maybe a`&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb21-8"&gt;&lt;a href="#cb21-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; listToMaybe &lt;span class="op"&gt;.&lt;/span&gt; &lt;span class="fu"&gt;map&lt;/span&gt; &lt;span class="fu"&gt;abs&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; [&lt;span class="dv"&gt;5&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;1&lt;/span&gt;,&lt;span class="dv"&gt;3&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;7&lt;/span&gt;]&lt;/span&gt;
&lt;span id="cb21-9"&gt;&lt;a href="#cb21-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;Just&lt;/span&gt; &lt;span class="dv"&gt;5&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb21-10"&gt;&lt;a href="#cb21-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;fmap&lt;/span&gt; &lt;span class="fu"&gt;abs&lt;/span&gt; &lt;span class="op"&gt;.&lt;/span&gt; listToMaybe &lt;span class="op"&gt;$&lt;/span&gt; [&lt;span class="dv"&gt;5&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;1&lt;/span&gt;,&lt;span class="dv"&gt;3&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;7&lt;/span&gt;]&lt;/span&gt;
&lt;span id="cb21-11"&gt;&lt;a href="#cb21-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;Just&lt;/span&gt; &lt;span class="dv"&gt;5&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb21-12"&gt;&lt;a href="#cb21-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb21-13"&gt;&lt;a href="#cb21-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- free theorem: `lastMay :: [a] -&amp;gt; Maybe a`&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb21-14"&gt;&lt;a href="#cb21-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; lastMay &lt;span class="op"&gt;.&lt;/span&gt; &lt;span class="fu"&gt;map&lt;/span&gt; &lt;span class="fu"&gt;abs&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; [&lt;span class="dv"&gt;5&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;1&lt;/span&gt;,&lt;span class="dv"&gt;3&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;7&lt;/span&gt;]&lt;/span&gt;
&lt;span id="cb21-15"&gt;&lt;a href="#cb21-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;Just&lt;/span&gt; &lt;span class="dv"&gt;7&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb21-16"&gt;&lt;a href="#cb21-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;fmap&lt;/span&gt; &lt;span class="fu"&gt;abs&lt;/span&gt; &lt;span class="op"&gt;.&lt;/span&gt; lastMay &lt;span class="op"&gt;$&lt;/span&gt; [&lt;span class="dv"&gt;5&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;1&lt;/span&gt;,&lt;span class="dv"&gt;3&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;7&lt;/span&gt;]&lt;/span&gt;
&lt;span id="cb21-17"&gt;&lt;a href="#cb21-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;Just&lt;/span&gt; &lt;span class="dv"&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="sourceCode" id="cb22"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb22-1"&gt;&lt;a href="#cb22-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;collapse ::&lt;/span&gt; [a] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&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="sourceCode" id="cb23"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb23-1"&gt;&lt;a href="#cb23-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- no free theorem: `sum :: [Int] -&amp;gt; Int`&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb23-2"&gt;&lt;a href="#cb23-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;sum&lt;/span&gt; &lt;span class="op"&gt;.&lt;/span&gt; &lt;span class="fu"&gt;map&lt;/span&gt; &lt;span class="fu"&gt;abs&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; [&lt;span class="dv"&gt;5&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;1&lt;/span&gt;,&lt;span class="dv"&gt;3&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;7&lt;/span&gt;]&lt;/span&gt;
&lt;span id="cb23-3"&gt;&lt;a href="#cb23-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dv"&gt;16&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb23-4"&gt;&lt;a href="#cb23-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;sum&lt;/span&gt; [&lt;span class="dv"&gt;5&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;1&lt;/span&gt;,&lt;span class="dv"&gt;3&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;7&lt;/span&gt;]&lt;/span&gt;
&lt;span id="cb23-5"&gt;&lt;a href="#cb23-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dv"&gt;0&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb23-6"&gt;&lt;a href="#cb23-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb23-7"&gt;&lt;a href="#cb23-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- free theorem: `length :: [a] -&amp;gt; Int`&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb23-8"&gt;&lt;a href="#cb23-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;length&lt;/span&gt; &lt;span class="op"&gt;.&lt;/span&gt; &lt;span class="fu"&gt;map&lt;/span&gt; &lt;span class="fu"&gt;abs&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; [&lt;span class="dv"&gt;5&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;1&lt;/span&gt;,&lt;span class="dv"&gt;3&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;7&lt;/span&gt;]&lt;/span&gt;
&lt;span id="cb23-9"&gt;&lt;a href="#cb23-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dv"&gt;4&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb23-10"&gt;&lt;a href="#cb23-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;length&lt;/span&gt; [&lt;span class="dv"&gt;5&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;1&lt;/span&gt;,&lt;span class="dv"&gt;3&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;7&lt;/span&gt;]&lt;/span&gt;
&lt;span id="cb23-11"&gt;&lt;a href="#cb23-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dv"&gt;4&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb23-12"&gt;&lt;a href="#cb23-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb23-13"&gt;&lt;a href="#cb23-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- free theorem: `const 10 :: [a] -&amp;gt; Int`&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb23-14"&gt;&lt;a href="#cb23-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;const&lt;/span&gt; &lt;span class="dv"&gt;10&lt;/span&gt; &lt;span class="op"&gt;.&lt;/span&gt; &lt;span class="fu"&gt;map&lt;/span&gt; &lt;span class="fu"&gt;abs&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; [&lt;span class="dv"&gt;5&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;1&lt;/span&gt;,&lt;span class="dv"&gt;3&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;7&lt;/span&gt;]&lt;/span&gt;
&lt;span id="cb23-15"&gt;&lt;a href="#cb23-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dv"&gt;10&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb23-16"&gt;&lt;a href="#cb23-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;const&lt;/span&gt; &lt;span class="dv"&gt;10&lt;/span&gt; [&lt;span class="dv"&gt;5&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;1&lt;/span&gt;,&lt;span class="dv"&gt;3&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;7&lt;/span&gt;]&lt;/span&gt;
&lt;span id="cb23-17"&gt;&lt;a href="#cb23-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dv"&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="sourceCode" id="cb24"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb24-1"&gt;&lt;a href="#cb24-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;duper ::&lt;/span&gt; a &lt;span class="ot"&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
href="#fn3" class="footnote-ref" id="fnref3"
role="doc-noteref"&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="sourceCode" id="cb25"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb25-1"&gt;&lt;a href="#cb25-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- no free theorem: `take 3 . iterate (+1) :: Int -&amp;gt; [Int]`&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb25-2"&gt;&lt;a href="#cb25-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;take&lt;/span&gt; &lt;span class="dv"&gt;3&lt;/span&gt; &lt;span class="op"&gt;.&lt;/span&gt; &lt;span class="fu"&gt;iterate&lt;/span&gt; (&lt;span class="op"&gt;+&lt;/span&gt;&lt;span class="dv"&gt;1&lt;/span&gt;) &lt;span class="op"&gt;.&lt;/span&gt; &lt;span class="fu"&gt;negate&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="dv"&gt;4&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb25-3"&gt;&lt;a href="#cb25-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;[&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;4&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;3&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;2&lt;/span&gt;]&lt;/span&gt;
&lt;span id="cb25-4"&gt;&lt;a href="#cb25-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;map&lt;/span&gt; &lt;span class="fu"&gt;negate&lt;/span&gt; &lt;span class="op"&gt;.&lt;/span&gt; &lt;span class="fu"&gt;take&lt;/span&gt; &lt;span class="dv"&gt;3&lt;/span&gt; &lt;span class="op"&gt;.&lt;/span&gt; &lt;span class="fu"&gt;iterate&lt;/span&gt; (&lt;span class="op"&gt;+&lt;/span&gt;&lt;span class="dv"&gt;1&lt;/span&gt;) &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="dv"&gt;4&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb25-5"&gt;&lt;a href="#cb25-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;[&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;4&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;5&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;6&lt;/span&gt;]&lt;/span&gt;
&lt;span id="cb25-6"&gt;&lt;a href="#cb25-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb25-7"&gt;&lt;a href="#cb25-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- free theorem: `replicate 3 :: Int -&amp;gt; [Int]`&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb25-8"&gt;&lt;a href="#cb25-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;replicate&lt;/span&gt; &lt;span class="dv"&gt;3&lt;/span&gt; &lt;span class="op"&gt;.&lt;/span&gt; &lt;span class="fu"&gt;negate&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="dv"&gt;4&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb25-9"&gt;&lt;a href="#cb25-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;[&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;4&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;4&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;4&lt;/span&gt;]&lt;/span&gt;
&lt;span id="cb25-10"&gt;&lt;a href="#cb25-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;map&lt;/span&gt; &lt;span class="fu"&gt;negate&lt;/span&gt; &lt;span class="op"&gt;.&lt;/span&gt; &lt;span class="fu"&gt;replicate&lt;/span&gt; &lt;span class="dv"&gt;3&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="dv"&gt;4&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb25-11"&gt;&lt;a href="#cb25-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;[&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;4&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;4&lt;/span&gt;,&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&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="sourceCode" id="cb26"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb26-1"&gt;&lt;a href="#cb26-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;consumeInt ::&lt;/span&gt; &lt;span class="kw"&gt;forall&lt;/span&gt; r&lt;span class="op"&gt;.&lt;/span&gt; (&lt;span class="dt"&gt;Int&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; r) &lt;span class="ot"&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 href="#fn4"
class="footnote-ref" id="fnref4" role="doc-noteref"&gt;&lt;sup&gt;4&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="sourceCode" id="cb27"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb27-1"&gt;&lt;a href="#cb27-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;consumeInt ::&lt;/span&gt; &lt;span class="kw"&gt;forall&lt;/span&gt; r&lt;span class="op"&gt;.&lt;/span&gt; (&lt;span class="dt"&gt;Int&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; r) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; r&lt;/span&gt;
&lt;span id="cb27-2"&gt;&lt;a href="#cb27-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;consumeInt f &lt;span class="ot"&gt;=&lt;/span&gt; f &lt;span class="dv"&gt;42&lt;/span&gt;     &lt;span class="co"&gt;-- must be a fixed `Int`, cannot dynamically change&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb27-3"&gt;&lt;a href="#cb27-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb27-4"&gt;&lt;a href="#cb27-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;consumeString ::&lt;/span&gt; &lt;span class="kw"&gt;forall&lt;/span&gt; r&lt;span class="op"&gt;.&lt;/span&gt; (&lt;span class="dt"&gt;String&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; r) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; r&lt;/span&gt;
&lt;span id="cb27-5"&gt;&lt;a href="#cb27-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;consumeString f &lt;span class="ot"&gt;=&lt;/span&gt; f &lt;span class="st"&gt;&amp;quot;hello&amp;quot;&lt;/span&gt;     &lt;span class="co"&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="sourceCode" id="cb28"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb28-1"&gt;&lt;a href="#cb28-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;mapMaybe ::&lt;/span&gt; (a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; b) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; [a] &lt;span class="ot"&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="sourceCode" id="cb29"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb29-1"&gt;&lt;a href="#cb29-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;traverseIO ::&lt;/span&gt; (a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; b) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; [a] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; [b]&lt;/span&gt;
&lt;span id="cb29-2"&gt;&lt;a href="#cb29-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb29-3"&gt;&lt;a href="#cb29-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- vs&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb29-4"&gt;&lt;a href="#cb29-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb29-5"&gt;&lt;a href="#cb29-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;traverse&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Applicative&lt;/span&gt; f &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt; (a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; f b) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; [a] &lt;span class="ot"&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 "hello"&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="the-more-you-surrender"&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="its-only-natural"&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="https://en.wikipedia.org/wiki/Natural_transformation"&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="sourceCode" id="cb30"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb30-1"&gt;&lt;a href="#cb30-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;h &lt;span class="op"&gt;.&lt;/span&gt; &lt;span class="fu"&gt;fmap&lt;/span&gt; f&lt;/span&gt;
&lt;span id="cb30-2"&gt;&lt;a href="#cb30-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;==&lt;/span&gt; &lt;span class="fu"&gt;fmap&lt;/span&gt; f &lt;span class="op"&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
href="#fn5" class="footnote-ref" id="fnref5"
role="doc-noteref"&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="add-a-type-variable"&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="sourceCode" id="cb31"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb31-1"&gt;&lt;a href="#cb31-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;User&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;User&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb31-2"&gt;&lt;a href="#cb31-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; userId ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb31-3"&gt;&lt;a href="#cb31-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; userName ::&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb31-4"&gt;&lt;a href="#cb31-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; userAge ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb31-5"&gt;&lt;a href="#cb31-5" aria-hidden="true" tabindex="-1"&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="sourceCode" id="cb32"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb32-1"&gt;&lt;a href="#cb32-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;processUser ::&lt;/span&gt; &lt;span class="dt"&gt;User&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&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="sourceCode" id="cb33"&gt;&lt;pre class="sourceCode c"&gt;&lt;code class="sourceCode c"&gt;&lt;span id="cb33-1"&gt;&lt;a href="#cb33-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;struct&lt;/span&gt; User &lt;span class="op"&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb33-2"&gt;&lt;a href="#cb33-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;const&lt;/span&gt; &lt;span class="dt"&gt;int&lt;/span&gt; userId&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb33-3"&gt;&lt;a href="#cb33-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;char&lt;/span&gt; userName&lt;span class="op"&gt;[&lt;/span&gt;&lt;span class="dv"&gt;20&lt;/span&gt;&lt;span class="op"&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb33-4"&gt;&lt;a href="#cb33-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;int&lt;/span&gt; userAge&lt;span class="op"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb33-5"&gt;&lt;a href="#cb33-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&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="sourceCode" id="cb34"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb34-1"&gt;&lt;a href="#cb34-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;User&lt;/span&gt; uid &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;User&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb34-2"&gt;&lt;a href="#cb34-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; userId ::&lt;/span&gt; uid&lt;/span&gt;
&lt;span id="cb34-3"&gt;&lt;a href="#cb34-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; userName ::&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb34-4"&gt;&lt;a href="#cb34-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; userAge ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb34-5"&gt;&lt;a href="#cb34-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="cb34-6"&gt;&lt;a href="#cb34-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb34-7"&gt;&lt;a href="#cb34-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Guaranteed not to change the ID&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb34-8"&gt;&lt;a href="#cb34-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;processUser ::&lt;/span&gt; &lt;span class="dt"&gt;User&lt;/span&gt; uid &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&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="sourceCode" id="cb35"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb35-1"&gt;&lt;a href="#cb35-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Checklist&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Checklist&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb35-2"&gt;&lt;a href="#cb35-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  {&lt;span class="ot"&gt; updated ::&lt;/span&gt; &lt;span class="dt"&gt;UTCTime&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb35-3"&gt;&lt;a href="#cb35-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  ,&lt;span class="ot"&gt; items ::&lt;/span&gt; [(&lt;span class="dt"&gt;Status&lt;/span&gt;, &lt;span class="dt"&gt;String&lt;/span&gt;)]&lt;/span&gt;
&lt;span id="cb35-4"&gt;&lt;a href="#cb35-4" aria-hidden="true" tabindex="-1"&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="sourceCode" id="cb36"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb36-1"&gt;&lt;a href="#cb36-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Invariant: Preserves the ordering of items, and their number.&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb36-2"&gt;&lt;a href="#cb36-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;updateItems ::&lt;/span&gt; &lt;span class="dt"&gt;Checklist&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&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="sourceCode" id="cb37"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb37-1"&gt;&lt;a href="#cb37-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Checklist&lt;/span&gt; t &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Checklist&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb37-2"&gt;&lt;a href="#cb37-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  {&lt;span class="ot"&gt; updated ::&lt;/span&gt; &lt;span class="dt"&gt;UTCTime&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb37-3"&gt;&lt;a href="#cb37-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  ,&lt;span class="ot"&gt; items ::&lt;/span&gt; t (&lt;span class="dt"&gt;Status&lt;/span&gt;, &lt;span class="dt"&gt;String&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb37-4"&gt;&lt;a href="#cb37-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  }&lt;/span&gt;
&lt;span id="cb37-5"&gt;&lt;a href="#cb37-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb37-6"&gt;&lt;a href="#cb37-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Guaranteed to preseve the same number of `items` (or, number of item&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb37-7"&gt;&lt;a href="#cb37-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- &amp;quot;slots&amp;quot;), but can still perform IO to get the new Status and String&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb37-8"&gt;&lt;a href="#cb37-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;updateItems ::&lt;/span&gt; &lt;span class="dt"&gt;Traversable&lt;/span&gt; t &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Checklist&lt;/span&gt; t &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&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="sourceCode" id="cb38"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb38-1"&gt;&lt;a href="#cb38-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;updateSingleItem ::&lt;/span&gt; (&lt;span class="dt"&gt;Status&lt;/span&gt;, &lt;span class="dt"&gt;String&lt;/span&gt;) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Status&lt;/span&gt;, &lt;span class="dt"&gt;String&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb38-2"&gt;&lt;a href="#cb38-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb38-3"&gt;&lt;a href="#cb38-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;updateItems ::&lt;/span&gt; &lt;span class="dt"&gt;Traversable&lt;/span&gt; t &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Checklist&lt;/span&gt; t &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Checklist&lt;/span&gt; t)&lt;/span&gt;
&lt;span id="cb38-4"&gt;&lt;a href="#cb38-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;updateItems c0 &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb38-5"&gt;&lt;a href="#cb38-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  newItems &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="fu"&gt;traverse&lt;/span&gt; updateSingleItem (items c0)&lt;/span&gt;
&lt;span id="cb38-6"&gt;&lt;a href="#cb38-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  newUpdated &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; getCurrentTime&lt;/span&gt;
&lt;span id="cb38-7"&gt;&lt;a href="#cb38-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;pure&lt;/span&gt; (&lt;span class="dt"&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="https://reasonablypolymorphic.com/blog/higher-kinded-data/"&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="sourceCode" id="cb39"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb39-1"&gt;&lt;a href="#cb39-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;UserF&lt;/span&gt; f &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;User&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb39-2"&gt;&lt;a href="#cb39-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; userName ::&lt;/span&gt; f &lt;span class="dt"&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb39-3"&gt;&lt;a href="#cb39-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; userAge ::&lt;/span&gt; f &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb39-4"&gt;&lt;a href="#cb39-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;
&lt;span id="cb39-5"&gt;&lt;a href="#cb39-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb39-6"&gt;&lt;a href="#cb39-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; &lt;span class="dt"&gt;User&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;UserF&lt;/span&gt; &lt;span class="dt"&gt;Identity&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb39-7"&gt;&lt;a href="#cb39-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; &lt;span class="dt"&gt;NullableUser&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;UserF&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb39-8"&gt;&lt;a href="#cb39-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; &lt;span class="dt"&gt;UserParser&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;UserF&lt;/span&gt; &lt;span class="dt"&gt;Parser&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb39-9"&gt;&lt;a href="#cb39-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; &lt;span class="dt"&gt;UserDocs&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;UserF&lt;/span&gt; (&lt;span class="dt"&gt;Const&lt;/span&gt; &lt;span class="dt"&gt;Doc&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb39-10"&gt;&lt;a href="#cb39-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; &lt;span class="dt"&gt;UserPrinter&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;UserF&lt;/span&gt; (&lt;span class="dt"&gt;Op&lt;/span&gt; &lt;span class="dt"&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="sourceCode" id="cb40"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb40-1"&gt;&lt;a href="#cb40-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;processUser ::&lt;/span&gt; &lt;span class="dt"&gt;Functor&lt;/span&gt; f &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;UserF&lt;/span&gt; f &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&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="sourceCode" id="cb41"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb41-1"&gt;&lt;a href="#cb41-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;processUser ::&lt;/span&gt; &lt;span class="dt"&gt;Functor&lt;/span&gt; f &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;UserF&lt;/span&gt; f &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;UserF&lt;/span&gt; f&lt;/span&gt;
&lt;span id="cb41-2"&gt;&lt;a href="#cb41-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;processUser user &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;User&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb41-3"&gt;&lt;a href="#cb41-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    { userName &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;fmap&lt;/span&gt; (&lt;span class="fu"&gt;map&lt;/span&gt; &lt;span class="fu"&gt;toUpper&lt;/span&gt;) (userName user)&lt;/span&gt;
&lt;span id="cb41-4"&gt;&lt;a href="#cb41-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , userAge &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;fmap&lt;/span&gt; (&lt;span class="op"&gt;+&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;) (userAge user)&lt;/span&gt;
&lt;span id="cb41-5"&gt;&lt;a href="#cb41-5" aria-hidden="true" tabindex="-1"&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="https://blog.jle.im/entry/introduction-to-singletons-1.html"&gt;this
singletons tutorial&lt;/a&gt;):&lt;/p&gt;
&lt;div class="sourceCode" id="cb42"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb42-1"&gt;&lt;a href="#cb42-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;DoorState&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Opened&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Closed&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Locked&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb42-2"&gt;&lt;a href="#cb42-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb42-3"&gt;&lt;a href="#cb42-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Door&lt;/span&gt; (&lt;span class="ot"&gt;s ::&lt;/span&gt; &lt;span class="dt"&gt;DoorState&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb42-4"&gt;&lt;a href="#cb42-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb42-5"&gt;&lt;a href="#cb42-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;processDoor ::&lt;/span&gt; &lt;span class="dt"&gt;Door&lt;/span&gt; s &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&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="https://blog.jle.im/entry/fixed-length-vector-types-in-haskell.html"&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="sourceCode" id="cb43"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb43-1"&gt;&lt;a href="#cb43-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;something ::&lt;/span&gt; &lt;span class="dt"&gt;Vector&lt;/span&gt; n a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&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="sourceCode" id="cb44"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb44-1"&gt;&lt;a href="#cb44-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;somethingElse ::&lt;/span&gt; &lt;span class="dt"&gt;Vector&lt;/span&gt; n a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Vector&lt;/span&gt; (n &lt;span class="op"&gt;-&lt;/span&gt; &lt;span class="dv"&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="ranking-up"&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="ensuring-structural-preservation"&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="sourceCode" id="cb45"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb45-1"&gt;&lt;a href="#cb45-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;traverseUser&lt;/span&gt;
&lt;span id="cb45-2"&gt;&lt;a href="#cb45-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;    ::&lt;/span&gt; &lt;span class="dt"&gt;Applicative&lt;/span&gt; h&lt;/span&gt;
&lt;span id="cb45-3"&gt;&lt;a href="#cb45-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt; (&lt;span class="kw"&gt;forall&lt;/span&gt; a&lt;span class="op"&gt;.&lt;/span&gt; f a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; h (g a))&lt;/span&gt;
&lt;span id="cb45-4"&gt;&lt;a href="#cb45-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;UserF&lt;/span&gt; f&lt;/span&gt;
&lt;span id="cb45-5"&gt;&lt;a href="#cb45-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; h (&lt;span class="dt"&gt;UserF&lt;/span&gt; g)&lt;/span&gt;
&lt;span id="cb45-6"&gt;&lt;a href="#cb45-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;traverseUser f u &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;User&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;$&amp;gt;&lt;/span&gt; f (userName u) &lt;span class="op"&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="ensuring-lexically-confined-resources"&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="sourceCode" id="cb46"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb46-1"&gt;&lt;a href="#cb46-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;Var&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Var&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb46-2"&gt;&lt;a href="#cb46-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;Memory&lt;/span&gt; v &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Memory&lt;/span&gt; {&lt;span class="ot"&gt; getMemory ::&lt;/span&gt; &lt;span class="dt"&gt;IntMap&lt;/span&gt; v }&lt;/span&gt;
&lt;span id="cb46-3"&gt;&lt;a href="#cb46-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb46-4"&gt;&lt;a href="#cb46-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;initVar ::&lt;/span&gt; v &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;State&lt;/span&gt; (&lt;span class="dt"&gt;Memory&lt;/span&gt; v) &lt;span class="dt"&gt;Var&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb46-5"&gt;&lt;a href="#cb46-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;initVar x &lt;span class="ot"&gt;=&lt;/span&gt; state &lt;span class="op"&gt;$&lt;/span&gt; \(&lt;span class="dt"&gt;Memory&lt;/span&gt; mp) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb46-6"&gt;&lt;a href="#cb46-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;case&lt;/span&gt; IM.lookupMax mp &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb46-7"&gt;&lt;a href="#cb46-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Nothing&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; (&lt;span class="dt"&gt;Var&lt;/span&gt; &lt;span class="dv"&gt;0&lt;/span&gt;, &lt;span class="dt"&gt;Memory&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; IM.insert &lt;span class="dv"&gt;0&lt;/span&gt; x mp)&lt;/span&gt;
&lt;span id="cb46-8"&gt;&lt;a href="#cb46-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Just&lt;/span&gt; (i, _) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; (&lt;span class="dt"&gt;Var&lt;/span&gt; (i &lt;span class="op"&gt;+&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;), &lt;span class="dt"&gt;Memory&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; IM.insert (i &lt;span class="op"&gt;+&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;) x mp)&lt;/span&gt;
&lt;span id="cb46-9"&gt;&lt;a href="#cb46-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb46-10"&gt;&lt;a href="#cb46-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;readVar ::&lt;/span&gt; &lt;span class="dt"&gt;Var&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;State&lt;/span&gt; (&lt;span class="dt"&gt;Memory&lt;/span&gt; v) v&lt;/span&gt;
&lt;span id="cb46-11"&gt;&lt;a href="#cb46-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;readVar (&lt;span class="dt"&gt;Var&lt;/span&gt; i) &lt;span class="ot"&gt;=&lt;/span&gt; gets ((&lt;span class="op"&gt;IM.!&lt;/span&gt; i) &lt;span class="op"&gt;.&lt;/span&gt; getMemory)&lt;/span&gt;
&lt;span id="cb46-12"&gt;&lt;a href="#cb46-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb46-13"&gt;&lt;a href="#cb46-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;writeVar ::&lt;/span&gt; &lt;span class="dt"&gt;Var&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; v &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;State&lt;/span&gt; (&lt;span class="dt"&gt;Memory&lt;/span&gt; v) ()&lt;/span&gt;
&lt;span id="cb46-14"&gt;&lt;a href="#cb46-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;writeVar (&lt;span class="dt"&gt;Var&lt;/span&gt; i) x &lt;span class="ot"&gt;=&lt;/span&gt; modify (&lt;span class="dt"&gt;Memory&lt;/span&gt; &lt;span class="op"&gt;.&lt;/span&gt; IM.insert i x &lt;span class="op"&gt;.&lt;/span&gt; getMemory)&lt;/span&gt;
&lt;span id="cb46-15"&gt;&lt;a href="#cb46-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb46-16"&gt;&lt;a href="#cb46-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;runWithMemory ::&lt;/span&gt; &lt;span class="dt"&gt;State&lt;/span&gt; (&lt;span class="dt"&gt;Memory&lt;/span&gt; v) a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; a&lt;/span&gt;
&lt;span id="cb46-17"&gt;&lt;a href="#cb46-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;runWithMemory &lt;span class="ot"&gt;=&lt;/span&gt; (&lt;span class="ot"&gt;`evalState`&lt;/span&gt; &lt;span class="dt"&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="sourceCode" id="cb47"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb47-1"&gt;&lt;a href="#cb47-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;getFib ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;State&lt;/span&gt; (&lt;span class="dt"&gt;Memory&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;) &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb47-2"&gt;&lt;a href="#cb47-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;getFib n &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb47-3"&gt;&lt;a href="#cb47-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    a &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; initVar &lt;span class="dv"&gt;0&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb47-4"&gt;&lt;a href="#cb47-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    b &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; initVar &lt;span class="dv"&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb47-5"&gt;&lt;a href="#cb47-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    replicateM_ n &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb47-6"&gt;&lt;a href="#cb47-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        newSum &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; (&lt;span class="op"&gt;+&lt;/span&gt;) &lt;span class="op"&gt;&amp;lt;$&amp;gt;&lt;/span&gt; readVar a &lt;span class="op"&gt;&amp;lt;*&amp;gt;&lt;/span&gt; readVar b&lt;/span&gt;
&lt;span id="cb47-7"&gt;&lt;a href="#cb47-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        writeVar a &lt;span class="op"&gt;=&amp;lt;&amp;lt;&lt;/span&gt; readVar b&lt;/span&gt;
&lt;span id="cb47-8"&gt;&lt;a href="#cb47-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        writeVar b newSum&lt;/span&gt;
&lt;span id="cb47-9"&gt;&lt;a href="#cb47-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    readVar b&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="sourceCode" id="cb48"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb48-1"&gt;&lt;a href="#cb48-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; runWithMemory (getFib &lt;span class="dv"&gt;10&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb48-2"&gt;&lt;a href="#cb48-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dv"&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="sourceCode" id="cb49"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb49-1"&gt;&lt;a href="#cb49-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;myAction ::&lt;/span&gt; &lt;span class="dt"&gt;State&lt;/span&gt; (&lt;span class="dt"&gt;Memory&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt;) a&lt;/span&gt;
&lt;span id="cb49-2"&gt;&lt;a href="#cb49-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;myAction &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;                 &lt;span class="co"&gt;-- new memory starts out empty&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb49-3"&gt;&lt;a href="#cb49-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  v &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; initVar &lt;span class="st"&gt;&amp;quot;hello&amp;quot;&lt;/span&gt;        &lt;span class="co"&gt;-- memory is now (0, &amp;quot;hello&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb49-4"&gt;&lt;a href="#cb49-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;let&lt;/span&gt; x &lt;span class="ot"&gt;=&lt;/span&gt; runWithMemory &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;  &lt;span class="co"&gt;-- new memory starts out empty&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb49-5"&gt;&lt;a href="#cb49-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        readVar v             &lt;span class="co"&gt;-- runtime error, looking up &amp;#39;0&amp;#39; in empty map!&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb49-6"&gt;&lt;a href="#cb49-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="co"&gt;-- ..&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb49-7"&gt;&lt;a href="#cb49-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="co"&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="sourceCode" id="cb50"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb50-1"&gt;&lt;a href="#cb50-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; runWithMemory (initVar &lt;span class="st"&gt;&amp;quot;hello&amp;quot;&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb50-2"&gt;&lt;a href="#cb50-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;Var&lt;/span&gt; &lt;span class="dv"&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="sourceCode" id="cb51"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb51-1"&gt;&lt;a href="#cb51-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;Var&lt;/span&gt; s &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Var&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb51-2"&gt;&lt;a href="#cb51-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;Memory&lt;/span&gt; s v &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Memory&lt;/span&gt; {&lt;span class="ot"&gt; getMemory ::&lt;/span&gt; &lt;span class="dt"&gt;IntMap&lt;/span&gt; v }&lt;/span&gt;
&lt;span id="cb51-3"&gt;&lt;a href="#cb51-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb51-4"&gt;&lt;a href="#cb51-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;initVar ::&lt;/span&gt; v &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;State&lt;/span&gt; (&lt;span class="dt"&gt;Memory&lt;/span&gt; s v) (&lt;span class="dt"&gt;Var&lt;/span&gt; s)&lt;/span&gt;
&lt;span id="cb51-5"&gt;&lt;a href="#cb51-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb51-6"&gt;&lt;a href="#cb51-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;readVar ::&lt;/span&gt; &lt;span class="dt"&gt;Var&lt;/span&gt; s &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;State&lt;/span&gt; (&lt;span class="dt"&gt;Memory&lt;/span&gt; s v) v&lt;/span&gt;
&lt;span id="cb51-7"&gt;&lt;a href="#cb51-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb51-8"&gt;&lt;a href="#cb51-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;writeVar ::&lt;/span&gt; &lt;span class="dt"&gt;Var&lt;/span&gt; s &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; v &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;State&lt;/span&gt; (&lt;span class="dt"&gt;Memory&lt;/span&gt; s v) ()&lt;/span&gt;
&lt;span id="cb51-9"&gt;&lt;a href="#cb51-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb51-10"&gt;&lt;a href="#cb51-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;runWithMemory ::&lt;/span&gt; (&lt;span class="kw"&gt;forall&lt;/span&gt; s&lt;span class="op"&gt;.&lt;/span&gt; &lt;span class="dt"&gt;State&lt;/span&gt; (&lt;span class="dt"&gt;Memory&lt;/span&gt; s v) a) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; a&lt;/span&gt;
&lt;span id="cb51-11"&gt;&lt;a href="#cb51-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;runWithMemory &lt;span class="ot"&gt;=&lt;/span&gt; (&lt;span class="ot"&gt;`evalState`&lt;/span&gt; &lt;span class="dt"&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="habits-to-build"&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="sourceCode" id="cb52"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb52-1"&gt;&lt;a href="#cb52-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;deployConfig ::&lt;/span&gt; &lt;span class="dt"&gt;Config&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&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="sourceCode" id="cb53"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb53-1"&gt;&lt;a href="#cb53-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | returns True if changed, otherwise False if already deployed&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb53-2"&gt;&lt;a href="#cb53-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;updateConfig ::&lt;/span&gt; &lt;span class="dt"&gt;IORef&lt;/span&gt; &lt;span class="dt"&gt;Config&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Config&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb53-3"&gt;&lt;a href="#cb53-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;updateConfig cache newConfig &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb53-4"&gt;&lt;a href="#cb53-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    oldConfig &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; readIORef cache&lt;/span&gt;
&lt;span id="cb53-5"&gt;&lt;a href="#cb53-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;if&lt;/span&gt; oldConfig &lt;span class="op"&gt;==&lt;/span&gt; newConfig&lt;/span&gt;
&lt;span id="cb53-6"&gt;&lt;a href="#cb53-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="kw"&gt;then&lt;/span&gt; &lt;span class="fu"&gt;pure&lt;/span&gt; &lt;span class="dt"&gt;False&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb53-7"&gt;&lt;a href="#cb53-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="kw"&gt;else&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb53-8"&gt;&lt;a href="#cb53-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            deployConfig newConfig&lt;/span&gt;
&lt;span id="cb53-9"&gt;&lt;a href="#cb53-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            writeIORef cache newConfig&lt;/span&gt;
&lt;span id="cb53-10"&gt;&lt;a href="#cb53-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="fu"&gt;pure&lt;/span&gt; &lt;span class="dt"&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="sourceCode" id="cb54"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb54-1"&gt;&lt;a href="#cb54-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;cachedUpdate ::&lt;/span&gt; &lt;span class="dt"&gt;Eq&lt;/span&gt; a &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt; (a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IORef&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb54-2"&gt;&lt;a href="#cb54-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;cachedUpdate action cache newVal &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb54-3"&gt;&lt;a href="#cb54-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    oldVal &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; readIORef cache&lt;/span&gt;
&lt;span id="cb54-4"&gt;&lt;a href="#cb54-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;if&lt;/span&gt; oldVal &lt;span class="op"&gt;==&lt;/span&gt; newVal&lt;/span&gt;
&lt;span id="cb54-5"&gt;&lt;a href="#cb54-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="kw"&gt;then&lt;/span&gt; &lt;span class="fu"&gt;pure&lt;/span&gt; &lt;span class="dt"&gt;False&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb54-6"&gt;&lt;a href="#cb54-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="kw"&gt;else&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb54-7"&gt;&lt;a href="#cb54-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            action newVal&lt;/span&gt;
&lt;span id="cb54-8"&gt;&lt;a href="#cb54-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            writeIORef cache newVal&lt;/span&gt;
&lt;span id="cb54-9"&gt;&lt;a href="#cb54-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="fu"&gt;pure&lt;/span&gt; &lt;span class="dt"&gt;True&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb54-10"&gt;&lt;a href="#cb54-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb54-11"&gt;&lt;a href="#cb54-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;updateConfig ::&lt;/span&gt; &lt;span class="dt"&gt;IORef&lt;/span&gt; &lt;span class="dt"&gt;Config&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Config&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb54-12"&gt;&lt;a href="#cb54-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;updateConfig &lt;span class="ot"&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="https://en.wikipedia.org/wiki/SOLID"&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="sourceCode" id="cb55"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb55-1"&gt;&lt;a href="#cb55-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;notifyUsers ::&lt;/span&gt; [&lt;span class="dt"&gt;User&lt;/span&gt;] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Text&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&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="sourceCode" id="cb56"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb56-1"&gt;&lt;a href="#cb56-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;notifyAll ::&lt;/span&gt; &lt;span class="dt"&gt;Foldable&lt;/span&gt; t &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt; t recipient &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; (recipient &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&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="embracing-unconditional-election"&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="the-next-step"&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="https://xkcd.com/1312/"&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="https://blog.jle.im/entries/series/+five-point-haskell.html"&gt;Five-Point
Haskell&lt;/a&gt;, &lt;strong&gt;Limited Atonement&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id="special-thanks"&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="https://www.patreon.com/justinle/overview"&gt;patreon&lt;/a&gt;, Josh Vera! :)&lt;/p&gt;
&lt;section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn1"&gt;&lt;p&gt;This is the “Fast and Loose Reasoning” condition (Danielsson et
al.).&lt;a href="#fnref1" class="footnote-back" role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn2"&gt;&lt;p&gt;Excluding &lt;code&gt;unsafePerformIO&lt;/code&gt;,
&lt;code&gt;unsafeCoerce&lt;/code&gt;, etc.&lt;a href="#fnref2" class="footnote-back"
role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn3"&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 href="#fnref3" class="footnote-back"
role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn4"&gt;&lt;p&gt;This is actually the essence of Yoneda lemma I think, whatever
that is.&lt;a href="#fnref4" class="footnote-back"
role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn5"&gt;&lt;p&gt;It’s &lt;code&gt;forall a. [a] -&amp;gt; Const Int a&lt;/code&gt;!&lt;a
href="#fnref5" class="footnote-back" role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description><author>Justin Le</author><category>Haskell</category><guid isPermaLink="true">https://blog.jle.im/entry/five-point-haskell-part-2-unconditional-election.html</guid><pubDate>Tue,  4 Aug 2026 18:15:09 UTC</pubDate><creator>Justin Le</creator><subject>Haskell</subject><date>2026-08-04</date></item><item><title>LLMs Will Cheese Your Types: Fighting Back in Haskell</title><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="the-ideal-case-haskell-and-llms"&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="https://bun.com/blog/bun-in-rust"&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="https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/"&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="decisions-that-require-scrutiny"&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="llm"&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="llm"&gt;“This test doesn’t pass, so let’s disable it”&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="llm"&gt;“Let’s feed this test junk data so it will
pass.”&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="llm"&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="disabling-warnings-for-escape-hatches"&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="llm"&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="llm"&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="llm"&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="llm"&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="ignoring-types-in-planned-code"&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="llm"&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="llm"&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="llm"&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="llm"&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="llm"&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="llm"&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="structural-type-abuse"&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="string-stuffing"&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="sourceCode" id="cb1"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb1-1"&gt;&lt;a href="#cb1-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ErrorEvent&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;UnknownUser&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-2"&gt;&lt;a href="#cb1-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;DatabaseErrorCode&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-3"&gt;&lt;a href="#cb1-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;InvalidJSON&lt;/span&gt; &lt;span class="dt"&gt;A.Value&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-4"&gt;&lt;a href="#cb1-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;NetworkError&lt;/span&gt; &lt;span class="dt"&gt;SomeException&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-5"&gt;&lt;a href="#cb1-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Canceled&lt;/span&gt; (&lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;CancelationReason&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb1-6"&gt;&lt;a href="#cb1-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="op"&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="sourceCode" id="cb2"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb2-1"&gt;&lt;a href="#cb2-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;handleRequest ::&lt;/span&gt; &lt;span class="dt"&gt;Request&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Either&lt;/span&gt; &lt;span class="dt"&gt;ErrorEvent&lt;/span&gt; &lt;span class="dt"&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="sourceCode" id="cb3"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb3-1"&gt;&lt;a href="#cb3-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;handleAddGroup ::&lt;/span&gt; &lt;span class="dt"&gt;AddGroupRequest&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Either&lt;/span&gt; &lt;span class="dt"&gt;ErrorEvent&lt;/span&gt; &lt;span class="dt"&gt;Response&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb3-2"&gt;&lt;a href="#cb3-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;handleAddGroup req&lt;/span&gt;
&lt;span id="cb3-3"&gt;&lt;a href="#cb3-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; validGroup &lt;span class="fu"&gt;group&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="co"&gt;-- ..&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-4"&gt;&lt;a href="#cb3-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="fu"&gt;otherwise&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;pure&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="dt"&gt;Left&lt;/span&gt; (&lt;span class="dt"&gt;UnknownUser&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Invalid group: &amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;group&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb3-5"&gt;&lt;a href="#cb3-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-6"&gt;&lt;a href="#cb3-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;group&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; getGroup req&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;span class="llm"&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="sourceCode" id="cb4"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb4-1"&gt;&lt;a href="#cb4-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;handleAddGroup ::&lt;/span&gt; &lt;span class="dt"&gt;AddGroupRequest&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Either&lt;/span&gt; &lt;span class="dt"&gt;ErrorEvent&lt;/span&gt; &lt;span class="dt"&gt;Response&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb4-2"&gt;&lt;a href="#cb4-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;handleAddGroup req&lt;/span&gt;
&lt;span id="cb4-3"&gt;&lt;a href="#cb4-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ...&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-4"&gt;&lt;a href="#cb4-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="fu"&gt;otherwise&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;pure&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="dt"&gt;Left&lt;/span&gt; (&lt;span class="dt"&gt;DatabaseErrorCode&lt;/span&gt; (&lt;span class="op"&gt;-&lt;/span&gt;&lt;span class="dv"&gt;1&lt;/span&gt;))&lt;/span&gt;
&lt;span id="cb4-5"&gt;&lt;a href="#cb4-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb4-6"&gt;&lt;a href="#cb4-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;handleAddGroup ::&lt;/span&gt; &lt;span class="dt"&gt;AddGroupRequest&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Either&lt;/span&gt; &lt;span class="dt"&gt;ErrorEvent&lt;/span&gt; &lt;span class="dt"&gt;Response&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb4-7"&gt;&lt;a href="#cb4-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;handleAddGroup req&lt;/span&gt;
&lt;span id="cb4-8"&gt;&lt;a href="#cb4-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ...&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-9"&gt;&lt;a href="#cb4-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="fu"&gt;otherwise&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;pure&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="dt"&gt;Left&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="dt"&gt;InvalidJSON&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-10"&gt;&lt;a href="#cb4-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        A.object [&lt;span class="st"&gt;&amp;quot;errorType&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;.=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Invalid group&amp;quot;&lt;/span&gt;, &lt;span class="st"&gt;&amp;quot;group&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;.=&lt;/span&gt; &lt;span class="fu"&gt;group&lt;/span&gt;]&lt;/span&gt;
&lt;span id="cb4-11"&gt;&lt;a href="#cb4-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-12"&gt;&lt;a href="#cb4-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;group&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; getGroup req&lt;/span&gt;
&lt;span id="cb4-13"&gt;&lt;a href="#cb4-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb4-14"&gt;&lt;a href="#cb4-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;handleAddGroup ::&lt;/span&gt; &lt;span class="dt"&gt;AddGroupRequest&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Either&lt;/span&gt; &lt;span class="dt"&gt;ErrorEvent&lt;/span&gt; &lt;span class="dt"&gt;Response&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb4-15"&gt;&lt;a href="#cb4-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;handleAddGroup req&lt;/span&gt;
&lt;span id="cb4-16"&gt;&lt;a href="#cb4-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ...&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-17"&gt;&lt;a href="#cb4-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="fu"&gt;otherwise&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;pure&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="dt"&gt;Left&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="dt"&gt;NetworkError&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-18"&gt;&lt;a href="#cb4-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        toException (&lt;span class="fu"&gt;userError&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Invalid group: &amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;show&lt;/span&gt; &lt;span class="fu"&gt;group&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb4-19"&gt;&lt;a href="#cb4-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-20"&gt;&lt;a href="#cb4-20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;group&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; getGroup req&lt;/span&gt;
&lt;span id="cb4-21"&gt;&lt;a href="#cb4-21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb4-22"&gt;&lt;a href="#cb4-22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;handleAddGroup ::&lt;/span&gt; &lt;span class="dt"&gt;AddGroupRequest&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Either&lt;/span&gt; &lt;span class="dt"&gt;ErrorEvent&lt;/span&gt; &lt;span class="dt"&gt;Response&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb4-23"&gt;&lt;a href="#cb4-23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;handleAddGroup req&lt;/span&gt;
&lt;span id="cb4-24"&gt;&lt;a href="#cb4-24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- ...&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-25"&gt;&lt;a href="#cb4-25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="fu"&gt;otherwise&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;pure&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="dt"&gt;Left&lt;/span&gt; (&lt;span class="dt"&gt;Canceled&lt;/span&gt; &lt;span class="dt"&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="llm"&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="sourceCode" id="cb5"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb5-1"&gt;&lt;a href="#cb5-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ErrorEvent&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;UnknownUser&lt;/span&gt; &lt;span class="dt"&gt;UserName&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-2"&gt;&lt;a href="#cb5-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;DatabaseErrorCode&lt;/span&gt; &lt;span class="dt"&gt;ErrorCode&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-3"&gt;&lt;a href="#cb5-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;InvalidJSON&lt;/span&gt; &lt;span class="dt"&gt;ParseError&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-4"&gt;&lt;a href="#cb5-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;NetworkError&lt;/span&gt; &lt;span class="dt"&gt;NetworkException&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-5"&gt;&lt;a href="#cb5-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Canceled&lt;/span&gt; &lt;span class="dt"&gt;CancelationReason&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-6"&gt;&lt;a href="#cb5-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id="field-abuse"&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="sourceCode" id="cb6"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb6-1"&gt;&lt;a href="#cb6-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Report&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Report&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-2"&gt;&lt;a href="#cb6-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; reportName ::&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-3"&gt;&lt;a href="#cb6-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; reportAuthors ::&lt;/span&gt; [&lt;span class="dt"&gt;String&lt;/span&gt;]&lt;/span&gt;
&lt;span id="cb6-4"&gt;&lt;a href="#cb6-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; reportDate ::&lt;/span&gt; &lt;span class="dt"&gt;Day&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-5"&gt;&lt;a href="#cb6-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , &lt;span class="op"&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-6"&gt;&lt;a href="#cb6-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;span class="llm"&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="sourceCode" id="cb7"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb7-1"&gt;&lt;a href="#cb7-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Targets&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Targets&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb7-2"&gt;&lt;a href="#cb7-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    {&lt;span class="ot"&gt; fooTarget ::&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb7-3"&gt;&lt;a href="#cb7-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ,&lt;span class="ot"&gt; barTarget ::&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb7-4"&gt;&lt;a href="#cb7-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , &lt;span class="co"&gt;-- ...&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb7-5"&gt;&lt;a href="#cb7-5" aria-hidden="true" tabindex="-1"&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="llm"&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="1"&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="llm"&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="resisting-new-types"&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="sourceCode" id="cb8"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb8-1"&gt;&lt;a href="#cb8-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;State&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Alaska&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Arkansas&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Arizona&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb8-2"&gt;&lt;a href="#cb8-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb8-3"&gt;&lt;a href="#cb8-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;processState ::&lt;/span&gt; &lt;span class="dt"&gt;State&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&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="sourceCode" id="cb9"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb9-1"&gt;&lt;a href="#cb9-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Region&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Canada&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Mexico&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Alaska&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Arkansas&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Arizona&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb9-2"&gt;&lt;a href="#cb9-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb9-3"&gt;&lt;a href="#cb9-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;processRegion ::&lt;/span&gt; &lt;span class="dt"&gt;Region&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="cb9-4"&gt;&lt;a href="#cb9-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;processRegion &lt;span class="ot"&gt;=&lt;/span&gt; \&lt;span class="kw"&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb9-5"&gt;&lt;a href="#cb9-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Canada&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb9-6"&gt;&lt;a href="#cb9-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Mexico&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb9-7"&gt;&lt;a href="#cb9-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    st &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; processState st&lt;/span&gt;
&lt;span id="cb9-8"&gt;&lt;a href="#cb9-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb9-9"&gt;&lt;a href="#cb9-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;processState ::&lt;/span&gt; &lt;span class="dt"&gt;Region&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="cb9-10"&gt;&lt;a href="#cb9-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;processState &lt;span class="ot"&gt;=&lt;/span&gt; \&lt;span class="kw"&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb9-11"&gt;&lt;a href="#cb9-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Canada&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;pure&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="cb9-12"&gt;&lt;a href="#cb9-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Mexico&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;pure&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="cb9-13"&gt;&lt;a href="#cb9-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Alaska&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt; &lt;span class="co"&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="sourceCode" id="cb10"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb10-1"&gt;&lt;a href="#cb10-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Region&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Canada&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Mexico&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;USState&lt;/span&gt; &lt;span class="dt"&gt;State&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb10-2"&gt;&lt;a href="#cb10-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;State&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Alaska&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Arkansas&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Arizona&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb10-3"&gt;&lt;a href="#cb10-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb10-4"&gt;&lt;a href="#cb10-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;processRegion ::&lt;/span&gt; &lt;span class="dt"&gt;Region&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="cb10-5"&gt;&lt;a href="#cb10-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;processRegion &lt;span class="ot"&gt;=&lt;/span&gt; \&lt;span class="kw"&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb10-6"&gt;&lt;a href="#cb10-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Canada&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb10-7"&gt;&lt;a href="#cb10-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Mexico&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb10-8"&gt;&lt;a href="#cb10-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;USState&lt;/span&gt; st &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; processState st&lt;/span&gt;
&lt;span id="cb10-9"&gt;&lt;a href="#cb10-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb10-10"&gt;&lt;a href="#cb10-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;processState ::&lt;/span&gt; &lt;span class="dt"&gt;State&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="cb10-11"&gt;&lt;a href="#cb10-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;processState &lt;span class="ot"&gt;=&lt;/span&gt; \&lt;span class="kw"&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb10-12"&gt;&lt;a href="#cb10-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Alaska&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;...&lt;/span&gt; &lt;span class="co"&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="meditations"&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="1"&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><author>Justin Le</author><category>Haskell</category><guid isPermaLink="true">https://blog.jle.im/entry/llms-and-haskell-1-constraint-evading-behavior.html</guid><pubDate>Wed, 22 Jul 2026 16:10:56 UTC</pubDate><creator>Justin Le</creator><subject>Haskell</subject><date>2026-07-22</date></item><item><title>Extreme Haskell: Typed Expression EDSLs (Part 1)</title><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="https://blog.jle.im/entry/levels-of-type-safety-haskell-lists.html"&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="1"&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="https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/flake.nix"&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="sourceCode" id="cb1"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb1-1"&gt;&lt;a href="#cb1-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; cd code-samples/typed-sm-lc&lt;/span&gt;
&lt;span id="cb1-2"&gt;&lt;a href="#cb1-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; nix develop&lt;/span&gt;
&lt;span id="cb1-3"&gt;&lt;a href="#cb1-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;$&lt;/span&gt; ghci&lt;/span&gt;
&lt;span id="cb1-4"&gt;&lt;a href="#cb1-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;ghci&lt;/span&gt;&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; :load ExprStage1.hs&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id="the-lambda-calculus"&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="a-first-pass"&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="sourceCode" id="cb2"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb2-1"&gt;&lt;a href="#cb2-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb2-2"&gt;&lt;a href="#cb2-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb2-3"&gt;&lt;a href="#cb2-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Prim&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;PBool&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;PString&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-4"&gt;&lt;a href="#cb2-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Eq&lt;/span&gt;, &lt;span class="dt"&gt;Show&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb2-5"&gt;&lt;a href="#cb2-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb2-6"&gt;&lt;a href="#cb2-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Op&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;OPlus&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;OTimes&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;OLte&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;OAnd&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-7"&gt;&lt;a href="#cb2-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Eq&lt;/span&gt;, &lt;span class="dt"&gt;Show&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb2-8"&gt;&lt;a href="#cb2-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb2-9"&gt;&lt;a href="#cb2-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-10"&gt;&lt;a href="#cb2-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;EPrim&lt;/span&gt; &lt;span class="dt"&gt;Prim&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-11"&gt;&lt;a href="#cb2-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;EVar&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-12"&gt;&lt;a href="#cb2-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ELambda&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-13"&gt;&lt;a href="#cb2-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;EApply&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-14"&gt;&lt;a href="#cb2-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;EOp&lt;/span&gt; &lt;span class="dt"&gt;Op&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-15"&gt;&lt;a href="#cb2-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ERecord&lt;/span&gt; (&lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb2-16"&gt;&lt;a href="#cb2-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;EAccess&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-17"&gt;&lt;a href="#cb2-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;EChoice&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-18"&gt;&lt;a href="#cb2-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;ECase&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; (&lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt; (&lt;span class="dt"&gt;String&lt;/span&gt;, &lt;span class="dt"&gt;Expr&lt;/span&gt;))&lt;/span&gt;
&lt;span id="cb2-19"&gt;&lt;a href="#cb2-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Eq&lt;/span&gt;, &lt;span class="dt"&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="sourceCode" id="cb3"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb3-1"&gt;&lt;a href="#cb3-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb3-2"&gt;&lt;a href="#cb3-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb3-3"&gt;&lt;a href="#cb3-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;fifteen ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-4"&gt;&lt;a href="#cb3-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;fifteen &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ELambda&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;x&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;EOp&lt;/span&gt; &lt;span class="dt"&gt;OTimes&lt;/span&gt; (&lt;span class="dt"&gt;EVar&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;x&amp;quot;&lt;/span&gt;) (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;3&lt;/span&gt;))) &lt;span class="ot"&gt;`EApply`&lt;/span&gt; &lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&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="sourceCode" id="cb4"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb4-1"&gt;&lt;a href="#cb4-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb4-2"&gt;&lt;a href="#cb4-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb4-3"&gt;&lt;a href="#cb4-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;badTypeExample ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-4"&gt;&lt;a href="#cb4-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;badTypeExample &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-5"&gt;&lt;a href="#cb4-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EOp&lt;/span&gt; &lt;span class="dt"&gt;OAnd&lt;/span&gt; (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;)) (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&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="sourceCode" id="cb5"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb5-1"&gt;&lt;a href="#cb5-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb5-2"&gt;&lt;a href="#cb5-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb5-3"&gt;&lt;a href="#cb5-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;recordExample ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-4"&gt;&lt;a href="#cb5-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;recordExample &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-5"&gt;&lt;a href="#cb5-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EOp&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-6"&gt;&lt;a href="#cb5-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;OPlus&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-7"&gt;&lt;a href="#cb5-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ( &lt;span class="dt"&gt;EAccess&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-8"&gt;&lt;a href="#cb5-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ( &lt;span class="dt"&gt;ERecord&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-9"&gt;&lt;a href="#cb5-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            M.fromList&lt;/span&gt;
&lt;span id="cb5-10"&gt;&lt;a href="#cb5-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;              [ (&lt;span class="st"&gt;&amp;quot;value&amp;quot;&lt;/span&gt;, &lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;7&lt;/span&gt;)),&lt;/span&gt;
&lt;span id="cb5-11"&gt;&lt;a href="#cb5-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                (&lt;span class="st"&gt;&amp;quot;label&amp;quot;&lt;/span&gt;, &lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PString&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;found&amp;quot;&lt;/span&gt;))&lt;/span&gt;
&lt;span id="cb5-12"&gt;&lt;a href="#cb5-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;              ]&lt;/span&gt;
&lt;span id="cb5-13"&gt;&lt;a href="#cb5-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        )&lt;/span&gt;
&lt;span id="cb5-14"&gt;&lt;a href="#cb5-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="st"&gt;&amp;quot;value&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-15"&gt;&lt;a href="#cb5-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    )&lt;/span&gt;
&lt;span id="cb5-16"&gt;&lt;a href="#cb5-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;))&lt;/span&gt;
&lt;span id="cb5-17"&gt;&lt;a href="#cb5-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb5-18"&gt;&lt;a href="#cb5-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;sumExample ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-19"&gt;&lt;a href="#cb5-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;sumExample &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-20"&gt;&lt;a href="#cb5-20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;ECase&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-21"&gt;&lt;a href="#cb5-21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    (&lt;span class="dt"&gt;EChoice&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Found&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;7&lt;/span&gt;)))&lt;/span&gt;
&lt;span id="cb5-22"&gt;&lt;a href="#cb5-22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ( M.fromList&lt;/span&gt;
&lt;span id="cb5-23"&gt;&lt;a href="#cb5-23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        [ (&lt;span class="st"&gt;&amp;quot;Found&amp;quot;&lt;/span&gt;, (&lt;span class="st"&gt;&amp;quot;value&amp;quot;&lt;/span&gt;, &lt;span class="dt"&gt;EOp&lt;/span&gt; &lt;span class="dt"&gt;OPlus&lt;/span&gt; (&lt;span class="dt"&gt;EVar&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;value&amp;quot;&lt;/span&gt;) (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;)))),&lt;/span&gt;
&lt;span id="cb5-24"&gt;&lt;a href="#cb5-24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          (&lt;span class="st"&gt;&amp;quot;Missing&amp;quot;&lt;/span&gt;, (&lt;span class="st"&gt;&amp;quot;message&amp;quot;&lt;/span&gt;, &lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;0&lt;/span&gt;)))&lt;/span&gt;
&lt;span id="cb5-25"&gt;&lt;a href="#cb5-25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ]&lt;/span&gt;
&lt;span id="cb5-26"&gt;&lt;a href="#cb5-26" aria-hidden="true" tabindex="-1"&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="https://hackage.haskell.org/package/prettyprinter"&gt;prettyprinter&lt;/a&gt;&lt;/em&gt;
library:&lt;/p&gt;
&lt;div class="sourceCode" id="cb6"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb6-1"&gt;&lt;a href="#cb6-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb6-2"&gt;&lt;a href="#cb6-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb6-3"&gt;&lt;a href="#cb6-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;ppPrim ::&lt;/span&gt; &lt;span class="dt"&gt;Prim&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id="cb6-4"&gt;&lt;a href="#cb6-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ppPrim &lt;span class="ot"&gt;=&lt;/span&gt; \&lt;span class="kw"&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-5"&gt;&lt;a href="#cb6-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;PInt&lt;/span&gt; n &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; PP.pretty n&lt;/span&gt;
&lt;span id="cb6-6"&gt;&lt;a href="#cb6-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;PBool&lt;/span&gt; &lt;span class="dt"&gt;True&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-7"&gt;&lt;a href="#cb6-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;PBool&lt;/span&gt; &lt;span class="dt"&gt;False&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-8"&gt;&lt;a href="#cb6-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;PString&lt;/span&gt; s &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; PP.pretty (&lt;span class="fu"&gt;show&lt;/span&gt; s)&lt;/span&gt;
&lt;span id="cb6-9"&gt;&lt;a href="#cb6-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb6-10"&gt;&lt;a href="#cb6-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;ppOp ::&lt;/span&gt; &lt;span class="dt"&gt;Op&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id="cb6-11"&gt;&lt;a href="#cb6-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ppOp &lt;span class="ot"&gt;=&lt;/span&gt; \&lt;span class="kw"&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-12"&gt;&lt;a href="#cb6-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;OPlus&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;+&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-13"&gt;&lt;a href="#cb6-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;OTimes&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;*&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-14"&gt;&lt;a href="#cb6-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;OLte&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;&amp;lt;=&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-15"&gt;&lt;a href="#cb6-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;OAnd&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;&amp;amp;&amp;amp;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-16"&gt;&lt;a href="#cb6-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb6-17"&gt;&lt;a href="#cb6-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;ppExpr ::&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id="cb6-18"&gt;&lt;a href="#cb6-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ppExpr paren &lt;span class="ot"&gt;=&lt;/span&gt; \&lt;span class="kw"&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-19"&gt;&lt;a href="#cb6-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EPrim&lt;/span&gt; p &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; ppPrim p&lt;/span&gt;
&lt;span id="cb6-20"&gt;&lt;a href="#cb6-20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EVar&lt;/span&gt; v &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; PP.pretty v&lt;/span&gt;
&lt;span id="cb6-21"&gt;&lt;a href="#cb6-21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;ELambda&lt;/span&gt; n body &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-22"&gt;&lt;a href="#cb6-22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    wrap &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;\\&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; PP.pretty n &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;-&amp;gt;&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class="dt"&gt;False&lt;/span&gt; body&lt;/span&gt;
&lt;span id="cb6-23"&gt;&lt;a href="#cb6-23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EApply&lt;/span&gt; f x &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-24"&gt;&lt;a href="#cb6-24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    wrap &lt;span class="op"&gt;$&lt;/span&gt; ppExpr &lt;span class="dt"&gt;True&lt;/span&gt; f &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class="dt"&gt;True&lt;/span&gt; x&lt;/span&gt;
&lt;span id="cb6-25"&gt;&lt;a href="#cb6-25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EOp&lt;/span&gt; o x y &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-26"&gt;&lt;a href="#cb6-26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    wrap &lt;span class="op"&gt;$&lt;/span&gt; ppExpr &lt;span class="dt"&gt;True&lt;/span&gt; x &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppOp o &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class="dt"&gt;True&lt;/span&gt; y&lt;/span&gt;
&lt;span id="cb6-27"&gt;&lt;a href="#cb6-27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;ERecord&lt;/span&gt; xs &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-28"&gt;&lt;a href="#cb6-28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    PP.encloseSep &lt;span class="st"&gt;&amp;quot;{ &amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot; }&amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;, &amp;quot;&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-29"&gt;&lt;a href="#cb6-29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      [PP.pretty k &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;=&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class="dt"&gt;False&lt;/span&gt; v &lt;span class="op"&gt;|&lt;/span&gt; (k, v) &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; M.toList xs]&lt;/span&gt;
&lt;span id="cb6-30"&gt;&lt;a href="#cb6-30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EAccess&lt;/span&gt; e k &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-31"&gt;&lt;a href="#cb6-31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ppExpr &lt;span class="dt"&gt;True&lt;/span&gt; e &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;.&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; PP.pretty k&lt;/span&gt;
&lt;span id="cb6-32"&gt;&lt;a href="#cb6-32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EChoice&lt;/span&gt; tag x &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-33"&gt;&lt;a href="#cb6-33" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    wrap &lt;span class="op"&gt;$&lt;/span&gt; PP.pretty tag &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class="dt"&gt;True&lt;/span&gt; x&lt;/span&gt;
&lt;span id="cb6-34"&gt;&lt;a href="#cb6-34" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;ECase&lt;/span&gt; x hs &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-35"&gt;&lt;a href="#cb6-35" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    wrap &lt;span class="op"&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-36"&gt;&lt;a href="#cb6-36" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      PP.sep&lt;/span&gt;
&lt;span id="cb6-37"&gt;&lt;a href="#cb6-37" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        [ &lt;span class="st"&gt;&amp;quot;case&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class="dt"&gt;False&lt;/span&gt; x &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;of&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-38"&gt;&lt;a href="#cb6-38" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , PP.encloseSep &lt;span class="st"&gt;&amp;quot;{ &amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot; }&amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;; &amp;quot;&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-39"&gt;&lt;a href="#cb6-39" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            [ PP.pretty tag &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; PP.pretty n &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;-&amp;gt;&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class="dt"&gt;False&lt;/span&gt; body&lt;/span&gt;
&lt;span id="cb6-40"&gt;&lt;a href="#cb6-40" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="op"&gt;|&lt;/span&gt; (tag, (n, body)) &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; M.toList hs&lt;/span&gt;
&lt;span id="cb6-41"&gt;&lt;a href="#cb6-41" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            ]&lt;/span&gt;
&lt;span id="cb6-42"&gt;&lt;a href="#cb6-42" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ]&lt;/span&gt;
&lt;span id="cb6-43"&gt;&lt;a href="#cb6-43" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-44"&gt;&lt;a href="#cb6-44" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    wrap&lt;/span&gt;
&lt;span id="cb6-45"&gt;&lt;a href="#cb6-45" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="op"&gt;|&lt;/span&gt; paren &lt;span class="ot"&gt;=&lt;/span&gt; PP.parens&lt;/span&gt;
&lt;span id="cb6-46"&gt;&lt;a href="#cb6-46" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="fu"&gt;otherwise&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;id&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-47"&gt;&lt;a href="#cb6-47" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb6-48"&gt;&lt;a href="#cb6-48" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;prettyExpr ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id="cb6-49"&gt;&lt;a href="#cb6-49" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;prettyExpr &lt;span class="ot"&gt;=&lt;/span&gt; ppExpr &lt;span class="dt"&gt;False&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="sourceCode" id="cb7"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb7-1"&gt;&lt;a href="#cb7-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; prettyExpr fifteen&lt;/span&gt;
&lt;span id="cb7-2"&gt;&lt;a href="#cb7-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;(\x &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; x &lt;span class="op"&gt;*&lt;/span&gt; &lt;span class="dv"&gt;3&lt;/span&gt;) &lt;span class="dv"&gt;5&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb7-3"&gt;&lt;a href="#cb7-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; prettyExpr badTypeExample&lt;/span&gt;
&lt;span id="cb7-4"&gt;&lt;a href="#cb7-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dv"&gt;1&lt;/span&gt; &lt;span class="op"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="dv"&gt;2&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb7-5"&gt;&lt;a href="#cb7-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; prettyExpr recordExample&lt;/span&gt;
&lt;span id="cb7-6"&gt;&lt;a href="#cb7-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;{ label &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;found&amp;quot;&lt;/span&gt;, value &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dv"&gt;7&lt;/span&gt; }&lt;span class="op"&gt;.&lt;/span&gt;value &lt;span class="op"&gt;+&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb7-7"&gt;&lt;a href="#cb7-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; prettyExpr sumExample&lt;/span&gt;
&lt;span id="cb7-8"&gt;&lt;a href="#cb7-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;case&lt;/span&gt; &lt;span class="dt"&gt;Found&lt;/span&gt; &lt;span class="dv"&gt;7&lt;/span&gt; &lt;span class="kw"&gt;of&lt;/span&gt; { &lt;span class="dt"&gt;Found&lt;/span&gt; value &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; value &lt;span class="op"&gt;+&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;; &lt;span class="dt"&gt;Missing&lt;/span&gt; message &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dv"&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="https://github.com/mstksg/inCode/tree/master/code-samples/typed-sm-lc/ExprStage1.hs#L77-L89"&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="sourceCode" id="cb8"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb8-1"&gt;&lt;a href="#cb8-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb8-2"&gt;&lt;a href="#cb8-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb8-3"&gt;&lt;a href="#cb8-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;EValue&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb8-4"&gt;&lt;a href="#cb8-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;EVInt&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb8-5"&gt;&lt;a href="#cb8-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;EVBool&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb8-6"&gt;&lt;a href="#cb8-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;EVString&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb8-7"&gt;&lt;a href="#cb8-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;EVFun&lt;/span&gt; (&lt;span class="dt"&gt;EValue&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;EValue&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb8-8"&gt;&lt;a href="#cb8-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;EVRecord&lt;/span&gt; (&lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt; &lt;span class="dt"&gt;EValue&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb8-9"&gt;&lt;a href="#cb8-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;EVChoice&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt; &lt;span class="dt"&gt;EValue&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb8-10"&gt;&lt;a href="#cb8-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb8-11"&gt;&lt;a href="#cb8-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;eval ::&lt;/span&gt; &lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt; &lt;span class="dt"&gt;EValue&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;EValue&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb8-12"&gt;&lt;a href="#cb8-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;eval env &lt;span class="ot"&gt;=&lt;/span&gt; \&lt;span class="kw"&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb8-13"&gt;&lt;a href="#cb8-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EPrim&lt;/span&gt; p &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; evalPrim p&lt;/span&gt;
&lt;span id="cb8-14"&gt;&lt;a href="#cb8-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EVar&lt;/span&gt; v &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; M.lookup v env&lt;/span&gt;
&lt;span id="cb8-15"&gt;&lt;a href="#cb8-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;ELambda&lt;/span&gt; n body &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;pure&lt;/span&gt; (&lt;span class="dt"&gt;EVFun&lt;/span&gt; (\x &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; eval (M.insert n x env) body))&lt;/span&gt;
&lt;span id="cb8-16"&gt;&lt;a href="#cb8-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EApply&lt;/span&gt; f x &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; eval env f &lt;span class="op"&gt;&amp;gt;&amp;gt;=&lt;/span&gt; \&lt;span class="kw"&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb8-17"&gt;&lt;a href="#cb8-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;EVFun&lt;/span&gt; f&amp;#39; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; eval env x &lt;span class="op"&gt;&amp;gt;&amp;gt;=&lt;/span&gt; f&amp;#39;&lt;/span&gt;
&lt;span id="cb8-18"&gt;&lt;a href="#cb8-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    _ &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb8-19"&gt;&lt;a href="#cb8-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EOp&lt;/span&gt; o x y &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb8-20"&gt;&lt;a href="#cb8-20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    u &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id="cb8-21"&gt;&lt;a href="#cb8-21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    v &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; eval env y&lt;/span&gt;
&lt;span id="cb8-22"&gt;&lt;a href="#cb8-22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;case&lt;/span&gt; (u, v) &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb8-23"&gt;&lt;a href="#cb8-23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      (&lt;span class="dt"&gt;EVInt&lt;/span&gt; a, &lt;span class="dt"&gt;EVInt&lt;/span&gt; b) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;case&lt;/span&gt; o &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb8-24"&gt;&lt;a href="#cb8-24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;OPlus&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;pure&lt;/span&gt; (&lt;span class="dt"&gt;EVInt&lt;/span&gt; (a &lt;span class="op"&gt;+&lt;/span&gt; b))&lt;/span&gt;
&lt;span id="cb8-25"&gt;&lt;a href="#cb8-25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;OTimes&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;pure&lt;/span&gt; (&lt;span class="dt"&gt;EVInt&lt;/span&gt; (a &lt;span class="op"&gt;*&lt;/span&gt; b))&lt;/span&gt;
&lt;span id="cb8-26"&gt;&lt;a href="#cb8-26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;OLte&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;pure&lt;/span&gt; (&lt;span class="dt"&gt;EVBool&lt;/span&gt; (a &lt;span class="op"&gt;&amp;lt;=&lt;/span&gt; b))&lt;/span&gt;
&lt;span id="cb8-27"&gt;&lt;a href="#cb8-27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;OAnd&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb8-28"&gt;&lt;a href="#cb8-28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      (&lt;span class="dt"&gt;EVBool&lt;/span&gt; a, &lt;span class="dt"&gt;EVBool&lt;/span&gt; b) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;case&lt;/span&gt; o &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb8-29"&gt;&lt;a href="#cb8-29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;OAnd&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;pure&lt;/span&gt; (&lt;span class="dt"&gt;EVBool&lt;/span&gt; (a &lt;span class="op"&gt;&amp;amp;&amp;amp;&lt;/span&gt; b))&lt;/span&gt;
&lt;span id="cb8-30"&gt;&lt;a href="#cb8-30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        _ &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb8-31"&gt;&lt;a href="#cb8-31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      _ &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb8-32"&gt;&lt;a href="#cb8-32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;ERecord&lt;/span&gt; xs &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EVRecord&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;$&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;traverse&lt;/span&gt; (eval env) xs&lt;/span&gt;
&lt;span id="cb8-33"&gt;&lt;a href="#cb8-33" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EAccess&lt;/span&gt; e k &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb8-34"&gt;&lt;a href="#cb8-34" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;EVRecord&lt;/span&gt; xs &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; eval env e&lt;/span&gt;
&lt;span id="cb8-35"&gt;&lt;a href="#cb8-35" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    M.lookup k xs&lt;/span&gt;
&lt;span id="cb8-36"&gt;&lt;a href="#cb8-36" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EChoice&lt;/span&gt; tag x &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EVChoice&lt;/span&gt; tag &lt;span class="op"&gt;&amp;lt;$&amp;gt;&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id="cb8-37"&gt;&lt;a href="#cb8-37" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;ECase&lt;/span&gt; x hs &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb8-38"&gt;&lt;a href="#cb8-38" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;EVChoice&lt;/span&gt; tag payload &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id="cb8-39"&gt;&lt;a href="#cb8-39" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    (n, body) &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; M.lookup tag hs&lt;/span&gt;
&lt;span id="cb8-40"&gt;&lt;a href="#cb8-40" aria-hidden="true" tabindex="-1"&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="sourceCode" id="cb9"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb9-1"&gt;&lt;a href="#cb9-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; eval M.empty fifteen&lt;/span&gt;
&lt;span id="cb9-2"&gt;&lt;a href="#cb9-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;Just&lt;/span&gt; (&lt;span class="dt"&gt;EVInt&lt;/span&gt; &lt;span class="dv"&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="sourceCode" id="cb10"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb10-1"&gt;&lt;a href="#cb10-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb10-2"&gt;&lt;a href="#cb10-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb10-3"&gt;&lt;a href="#cb10-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;plusThree ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb10-4"&gt;&lt;a href="#cb10-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;plusThree &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ELambda&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;x&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;EOp&lt;/span&gt; &lt;span class="dt"&gt;OPlus&lt;/span&gt; (&lt;span class="dt"&gt;EVar&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;x&amp;quot;&lt;/span&gt;) (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;3&lt;/span&gt;)))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="sourceCode" id="cb11"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb11-1"&gt;&lt;a href="#cb11-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; for_ (eval M.empty plusThree) \&lt;span class="kw"&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb11-2"&gt;&lt;a href="#cb11-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;EVFun&lt;/span&gt; f &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;print&lt;/span&gt; (f (&lt;span class="dt"&gt;EVInt&lt;/span&gt; &lt;span class="dv"&gt;4&lt;/span&gt;))&lt;/span&gt;
&lt;span id="cb11-3"&gt;&lt;a href="#cb11-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    _ &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;putStrLn&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;not a function&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb11-4"&gt;&lt;a href="#cb11-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;Just&lt;/span&gt; (&lt;span class="dt"&gt;EVInt&lt;/span&gt; &lt;span class="dv"&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="type-indexed-expressions"&gt;Type-Indexed Expressions&lt;/h2&gt;
&lt;h3 id="just-add-the-index"&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="sourceCode" id="cb12"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb12-1"&gt;&lt;a href="#cb12-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb12-2"&gt;&lt;a href="#cb12-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb12-3"&gt;&lt;a href="#cb12-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; &lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Ty&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb12-4"&gt;&lt;a href="#cb12-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb12-5"&gt;&lt;a href="#cb12-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;TBool&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb12-6"&gt;&lt;a href="#cb12-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;TString&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb12-7"&gt;&lt;a href="#cb12-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Ty&lt;/span&gt; &lt;span class="op"&gt;:-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Ty&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb12-8"&gt;&lt;a href="#cb12-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb12-9"&gt;&lt;a href="#cb12-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Prim&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Ty&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Type&lt;/span&gt; &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb12-10"&gt;&lt;a href="#cb12-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;PInt&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Prim&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb12-11"&gt;&lt;a href="#cb12-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;PBool&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Prim&lt;/span&gt; &lt;span class="dt"&gt;TBool&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb12-12"&gt;&lt;a href="#cb12-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;PString&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Prim&lt;/span&gt; &lt;span class="dt"&gt;TString&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb12-13"&gt;&lt;a href="#cb12-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb12-14"&gt;&lt;a href="#cb12-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Op&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Ty&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Ty&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Ty&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Type&lt;/span&gt; &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb12-15"&gt;&lt;a href="#cb12-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;OPlus&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Op&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb12-16"&gt;&lt;a href="#cb12-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;OTimes&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Op&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb12-17"&gt;&lt;a href="#cb12-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;OLte&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Op&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt; &lt;span class="dt"&gt;TBool&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb12-18"&gt;&lt;a href="#cb12-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;OAnd&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Op&lt;/span&gt; &lt;span class="dt"&gt;TBool&lt;/span&gt; &lt;span class="dt"&gt;TBool&lt;/span&gt; &lt;span class="dt"&gt;TBool&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb12-19"&gt;&lt;a href="#cb12-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb12-20"&gt;&lt;a href="#cb12-20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Ty&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Type&lt;/span&gt; &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb12-21"&gt;&lt;a href="#cb12-21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EPrim&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Prim&lt;/span&gt; t &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; t&lt;/span&gt;
&lt;span id="cb12-22"&gt;&lt;a href="#cb12-22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EVar&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;STy&lt;/span&gt; t &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; t&lt;/span&gt;
&lt;span id="cb12-23"&gt;&lt;a href="#cb12-23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;ELambda&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;STy&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; b &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; (a &lt;span class="op"&gt;:-&amp;gt;&lt;/span&gt; b)&lt;/span&gt;
&lt;span id="cb12-24"&gt;&lt;a href="#cb12-24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EApply&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; (a &lt;span class="op"&gt;:-&amp;gt;&lt;/span&gt; b) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; b&lt;/span&gt;
&lt;span id="cb12-25"&gt;&lt;a href="#cb12-25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EOp&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Op&lt;/span&gt; a b c &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; b &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&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="sourceCode" id="cb13"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb13-1"&gt;&lt;a href="#cb13-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;EOp&lt;/span&gt; &lt;span class="dt"&gt;OLte&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; &lt;span class="dt"&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="sourceCode" id="cb14"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb14-1"&gt;&lt;a href="#cb14-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;:&lt;/span&gt;t &lt;span class="dt"&gt;EOp&lt;/span&gt; &lt;span class="dt"&gt;OLte&lt;/span&gt; (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;3&lt;/span&gt;)) (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;4&lt;/span&gt;))&lt;/span&gt;
&lt;span id="cb14-2"&gt;&lt;a href="#cb14-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;Expr&lt;/span&gt; &lt;span class="dt"&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="sourceCode" id="cb15"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb15-1"&gt;&lt;a href="#cb15-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;:&lt;/span&gt;t &lt;span class="dt"&gt;EOp&lt;/span&gt; &lt;span class="dt"&gt;OAnd&lt;/span&gt; (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;)) (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;2&lt;/span&gt;))&lt;/span&gt;
&lt;span id="cb15-2"&gt;&lt;a href="#cb15-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;interactive&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;error&lt;/span&gt;&lt;span class="op"&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb15-3"&gt;&lt;a href="#cb15-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    • &lt;span class="dt"&gt;Couldn&amp;#39;t&lt;/span&gt; match &lt;span class="kw"&gt;type&lt;/span&gt; ‘&lt;span class="dt"&gt;TInt&lt;/span&gt;’ with ‘&lt;span class="dt"&gt;TBool&lt;/span&gt;’&lt;/span&gt;
&lt;span id="cb15-4"&gt;&lt;a href="#cb15-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;Expected&lt;/span&gt;&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;Prim&lt;/span&gt; &lt;span class="dt"&gt;TBool&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb15-5"&gt;&lt;a href="#cb15-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;Actual&lt;/span&gt;&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;Prim&lt;/span&gt; &lt;span class="dt"&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="sourceCode" id="cb16"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb16-1"&gt;&lt;a href="#cb16-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb16-2"&gt;&lt;a href="#cb16-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb16-3"&gt;&lt;a href="#cb16-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;fifteen ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb16-4"&gt;&lt;a href="#cb16-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;fifteen &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb16-5"&gt;&lt;a href="#cb16-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EApply&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb16-6"&gt;&lt;a href="#cb16-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    (&lt;span class="dt"&gt;ELambda&lt;/span&gt; &lt;span class="dt"&gt;STInt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;x&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;EOp&lt;/span&gt; &lt;span class="dt"&gt;OTimes&lt;/span&gt; (&lt;span class="dt"&gt;EVar&lt;/span&gt; &lt;span class="dt"&gt;STInt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;x&amp;quot;&lt;/span&gt;) (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;3&lt;/span&gt;))))&lt;/span&gt;
&lt;span id="cb16-7"&gt;&lt;a href="#cb16-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&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="sourceCode" id="cb17"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb17-1"&gt;&lt;a href="#cb17-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb17-2"&gt;&lt;a href="#cb17-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb17-3"&gt;&lt;a href="#cb17-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;EValue&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Ty&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Type&lt;/span&gt; &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb17-4"&gt;&lt;a href="#cb17-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EVInt&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EValue&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb17-5"&gt;&lt;a href="#cb17-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EVBool&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EValue&lt;/span&gt; &lt;span class="dt"&gt;TBool&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb17-6"&gt;&lt;a href="#cb17-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EVString&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EValue&lt;/span&gt; &lt;span class="dt"&gt;TString&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb17-7"&gt;&lt;a href="#cb17-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EVFun&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; (&lt;span class="dt"&gt;EValue&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; (&lt;span class="dt"&gt;EValue&lt;/span&gt; b)) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EValue&lt;/span&gt; (a &lt;span class="op"&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="sourceCode" id="cb18"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb18-1"&gt;&lt;a href="#cb18-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;eValueToInt ::&lt;/span&gt; &lt;span class="dt"&gt;EValue&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb18-2"&gt;&lt;a href="#cb18-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;eValueToInt &lt;span class="ot"&gt;=&lt;/span&gt; \&lt;span class="kw"&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb18-3"&gt;&lt;a href="#cb18-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;EVInt&lt;/span&gt; x &lt;span class="ot"&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="singletons-and-existentials"&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="https://blog.jle.im/entries/series/+introduction-to-singletons.html"&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="sourceCode" id="cb19"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb19-1"&gt;&lt;a href="#cb19-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb19-2"&gt;&lt;a href="#cb19-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb19-3"&gt;&lt;a href="#cb19-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;STy&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Ty&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Type&lt;/span&gt; &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb19-4"&gt;&lt;a href="#cb19-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;STInt&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;STy&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb19-5"&gt;&lt;a href="#cb19-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;STBool&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;STy&lt;/span&gt; &lt;span class="dt"&gt;TBool&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb19-6"&gt;&lt;a href="#cb19-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;STString&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;STy&lt;/span&gt; &lt;span class="dt"&gt;TString&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb19-7"&gt;&lt;a href="#cb19-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;STFun&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;STy&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;STy&lt;/span&gt; b &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;STy&lt;/span&gt; (a &lt;span class="op"&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 "myVar" :: 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="runtime-type-equality"&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="sourceCode" id="cb20"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb20-1"&gt;&lt;a href="#cb20-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt;&lt;span class="ot"&gt; (:~:) ::&lt;/span&gt; k &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; k &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Type&lt;/span&gt; &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb20-2"&gt;&lt;a href="#cb20-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Refl&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; a &lt;span class="op"&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="sourceCode" id="cb21"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb21-1"&gt;&lt;a href="#cb21-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb21-2"&gt;&lt;a href="#cb21-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb21-3"&gt;&lt;a href="#cb21-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;sameTy ::&lt;/span&gt; &lt;span class="dt"&gt;STy&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;STy&lt;/span&gt; b &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; (a &lt;span class="op"&gt;:~:&lt;/span&gt; b)&lt;/span&gt;
&lt;span id="cb21-4"&gt;&lt;a href="#cb21-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;sameTy &lt;span class="ot"&gt;=&lt;/span&gt; \&lt;span class="kw"&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb21-5"&gt;&lt;a href="#cb21-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;STInt&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; \&lt;span class="kw"&gt;case&lt;/span&gt; &lt;span class="dt"&gt;STInt&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Just&lt;/span&gt; &lt;span class="dt"&gt;Refl&lt;/span&gt;; _ &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb21-6"&gt;&lt;a href="#cb21-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;STBool&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; \&lt;span class="kw"&gt;case&lt;/span&gt; &lt;span class="dt"&gt;STBool&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Just&lt;/span&gt; &lt;span class="dt"&gt;Refl&lt;/span&gt;; _ &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb21-7"&gt;&lt;a href="#cb21-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;STString&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; \&lt;span class="kw"&gt;case&lt;/span&gt; &lt;span class="dt"&gt;STString&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Just&lt;/span&gt; &lt;span class="dt"&gt;Refl&lt;/span&gt;; _ &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb21-8"&gt;&lt;a href="#cb21-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;STFun&lt;/span&gt; a b &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; \&lt;span class="kw"&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb21-9"&gt;&lt;a href="#cb21-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;STFun&lt;/span&gt; c d &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb21-10"&gt;&lt;a href="#cb21-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;Refl&lt;/span&gt; &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; sameTy a c&lt;/span&gt;
&lt;span id="cb21-11"&gt;&lt;a href="#cb21-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;Refl&lt;/span&gt; &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; sameTy b d&lt;/span&gt;
&lt;span id="cb21-12"&gt;&lt;a href="#cb21-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;Just&lt;/span&gt; &lt;span class="dt"&gt;Refl&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb21-13"&gt;&lt;a href="#cb21-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    _ &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&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="sourceCode" id="cb22"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb22-1"&gt;&lt;a href="#cb22-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;class&lt;/span&gt; &lt;span class="dt"&gt;TestEquality&lt;/span&gt; f &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb22-2"&gt;&lt;a href="#cb22-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;    testEquality ::&lt;/span&gt; f a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; f b &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; (a &lt;span class="op"&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="sourceCode" id="cb23"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb23-1"&gt;&lt;a href="#cb23-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb23-2"&gt;&lt;a href="#cb23-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb23-3"&gt;&lt;a href="#cb23-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;instance&lt;/span&gt; &lt;span class="dt"&gt;TestEquality&lt;/span&gt; &lt;span class="dt"&gt;STy&lt;/span&gt; &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb23-4"&gt;&lt;a href="#cb23-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  testEquality &lt;span class="ot"&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 "x"&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="sourceCode" id="cb24"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb24-1"&gt;&lt;a href="#cb24-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb24-2"&gt;&lt;a href="#cb24-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb24-3"&gt;&lt;a href="#cb24-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;eval ::&lt;/span&gt; &lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt; &lt;span class="dt"&gt;SomeValue&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; t &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; (&lt;span class="dt"&gt;EValue&lt;/span&gt; t)&lt;/span&gt;
&lt;span id="cb24-4"&gt;&lt;a href="#cb24-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;eval env &lt;span class="ot"&gt;=&lt;/span&gt; \&lt;span class="kw"&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb24-5"&gt;&lt;a href="#cb24-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; n) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;pure&lt;/span&gt; (&lt;span class="dt"&gt;EVInt&lt;/span&gt; n)&lt;/span&gt;
&lt;span id="cb24-6"&gt;&lt;a href="#cb24-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PBool&lt;/span&gt; b) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;pure&lt;/span&gt; (&lt;span class="dt"&gt;EVBool&lt;/span&gt; b)&lt;/span&gt;
&lt;span id="cb24-7"&gt;&lt;a href="#cb24-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PString&lt;/span&gt; s) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;pure&lt;/span&gt; (&lt;span class="dt"&gt;EVString&lt;/span&gt; s)&lt;/span&gt;
&lt;span id="cb24-8"&gt;&lt;a href="#cb24-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EVar&lt;/span&gt; t v &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb24-9"&gt;&lt;a href="#cb24-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;SomeValue&lt;/span&gt; t&amp;#39; v&amp;#39; &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; M.lookup v env&lt;/span&gt;
&lt;span id="cb24-10"&gt;&lt;a href="#cb24-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Refl&lt;/span&gt; &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; sameTy t t&amp;#39;&lt;/span&gt;
&lt;span id="cb24-11"&gt;&lt;a href="#cb24-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;pure&lt;/span&gt; v&amp;#39;&lt;/span&gt;
&lt;span id="cb24-12"&gt;&lt;a href="#cb24-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;ELambda&lt;/span&gt; ta n body &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb24-13"&gt;&lt;a href="#cb24-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;pure&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="dt"&gt;EVFun&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; \x &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; eval (M.insert n (&lt;span class="dt"&gt;SomeValue&lt;/span&gt; ta x) env) body&lt;/span&gt;
&lt;span id="cb24-14"&gt;&lt;a href="#cb24-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EApply&lt;/span&gt; f x &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb24-15"&gt;&lt;a href="#cb24-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;EVFun&lt;/span&gt; g &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; eval env f&lt;/span&gt;
&lt;span id="cb24-16"&gt;&lt;a href="#cb24-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    x&amp;#39; &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id="cb24-17"&gt;&lt;a href="#cb24-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    g x&amp;#39;&lt;/span&gt;
&lt;span id="cb24-18"&gt;&lt;a href="#cb24-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EOp&lt;/span&gt; o x y &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;case&lt;/span&gt; o &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb24-19"&gt;&lt;a href="#cb24-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;OPlus&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb24-20"&gt;&lt;a href="#cb24-20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;EVInt&lt;/span&gt; a &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id="cb24-21"&gt;&lt;a href="#cb24-21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;EVInt&lt;/span&gt; b &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; eval env y&lt;/span&gt;
&lt;span id="cb24-22"&gt;&lt;a href="#cb24-22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;pure&lt;/span&gt; (&lt;span class="dt"&gt;EVInt&lt;/span&gt; (a &lt;span class="op"&gt;+&lt;/span&gt; b))&lt;/span&gt;
&lt;span id="cb24-23"&gt;&lt;a href="#cb24-23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;OTimes&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb24-24"&gt;&lt;a href="#cb24-24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;EVInt&lt;/span&gt; a &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id="cb24-25"&gt;&lt;a href="#cb24-25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;EVInt&lt;/span&gt; b &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; eval env y&lt;/span&gt;
&lt;span id="cb24-26"&gt;&lt;a href="#cb24-26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;pure&lt;/span&gt; (&lt;span class="dt"&gt;EVInt&lt;/span&gt; (a &lt;span class="op"&gt;*&lt;/span&gt; b))&lt;/span&gt;
&lt;span id="cb24-27"&gt;&lt;a href="#cb24-27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;OLte&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb24-28"&gt;&lt;a href="#cb24-28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;EVInt&lt;/span&gt; a &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id="cb24-29"&gt;&lt;a href="#cb24-29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;EVInt&lt;/span&gt; b &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; eval env y&lt;/span&gt;
&lt;span id="cb24-30"&gt;&lt;a href="#cb24-30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;pure&lt;/span&gt; (&lt;span class="dt"&gt;EVBool&lt;/span&gt; (a &lt;span class="op"&gt;&amp;lt;=&lt;/span&gt; b))&lt;/span&gt;
&lt;span id="cb24-31"&gt;&lt;a href="#cb24-31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;OAnd&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb24-32"&gt;&lt;a href="#cb24-32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;EVBool&lt;/span&gt; a &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id="cb24-33"&gt;&lt;a href="#cb24-33" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;EVBool&lt;/span&gt; b &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; eval env y&lt;/span&gt;
&lt;span id="cb24-34"&gt;&lt;a href="#cb24-34" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;pure&lt;/span&gt; (&lt;span class="dt"&gt;EVBool&lt;/span&gt; (a &lt;span class="op"&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="sourceCode" id="cb25"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb25-1"&gt;&lt;a href="#cb25-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; for_ (eval M.empty fifteen) \&lt;span class="kw"&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb25-2"&gt;&lt;a href="#cb25-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;EVInt&lt;/span&gt; x &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;print&lt;/span&gt; x&lt;/span&gt;
&lt;span id="cb25-3"&gt;&lt;a href="#cb25-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dv"&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="sourceCode" id="cb26"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb26-1"&gt;&lt;a href="#cb26-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb26-2"&gt;&lt;a href="#cb26-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb26-3"&gt;&lt;a href="#cb26-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;plusThree ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; (&lt;span class="dt"&gt;TInt&lt;/span&gt; &lt;span class="op"&gt;:-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb26-4"&gt;&lt;a href="#cb26-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;plusThree &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ELambda&lt;/span&gt; &lt;span class="dt"&gt;STInt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;x&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;EOp&lt;/span&gt; &lt;span class="dt"&gt;OPlus&lt;/span&gt; (&lt;span class="dt"&gt;EVar&lt;/span&gt; &lt;span class="dt"&gt;STInt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;x&amp;quot;&lt;/span&gt;) (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;3&lt;/span&gt;)))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="sourceCode" id="cb27"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb27-1"&gt;&lt;a href="#cb27-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; for_ (eval M.empty plusThree) \&lt;span class="kw"&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb27-2"&gt;&lt;a href="#cb27-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;EVFun&lt;/span&gt; f &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; for_ (f (&lt;span class="dt"&gt;EVInt&lt;/span&gt; &lt;span class="dv"&gt;4&lt;/span&gt;)) \&lt;span class="kw"&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb27-3"&gt;&lt;a href="#cb27-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;EVInt&lt;/span&gt; x &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;print&lt;/span&gt; x    &lt;span class="co"&gt;-- compiler-verified to always be EVInt&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb27-4"&gt;&lt;a href="#cb27-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dv"&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="pretty-printing"&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="sourceCode" id="cb28"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb28-1"&gt;&lt;a href="#cb28-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb28-2"&gt;&lt;a href="#cb28-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb28-3"&gt;&lt;a href="#cb28-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;ppPrim ::&lt;/span&gt; &lt;span class="dt"&gt;Prim&lt;/span&gt; t &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id="cb28-4"&gt;&lt;a href="#cb28-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ppPrim &lt;span class="ot"&gt;=&lt;/span&gt; \&lt;span class="kw"&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb28-5"&gt;&lt;a href="#cb28-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;PInt&lt;/span&gt; n &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; PP.pretty n&lt;/span&gt;
&lt;span id="cb28-6"&gt;&lt;a href="#cb28-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;PBool&lt;/span&gt; b &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;if&lt;/span&gt; b &lt;span class="kw"&gt;then&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;true&amp;quot;&lt;/span&gt; &lt;span class="kw"&gt;else&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb28-7"&gt;&lt;a href="#cb28-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;PString&lt;/span&gt; s &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; PP.pretty (&lt;span class="fu"&gt;show&lt;/span&gt; s)&lt;/span&gt;
&lt;span id="cb28-8"&gt;&lt;a href="#cb28-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb28-9"&gt;&lt;a href="#cb28-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;ppOp ::&lt;/span&gt; &lt;span class="dt"&gt;Op&lt;/span&gt; a b c &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id="cb28-10"&gt;&lt;a href="#cb28-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ppOp &lt;span class="ot"&gt;=&lt;/span&gt; \&lt;span class="kw"&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb28-11"&gt;&lt;a href="#cb28-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;OPlus&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;+&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb28-12"&gt;&lt;a href="#cb28-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;OTimes&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;*&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb28-13"&gt;&lt;a href="#cb28-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;OLte&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;&amp;lt;=&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb28-14"&gt;&lt;a href="#cb28-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;OAnd&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;&amp;amp;&amp;amp;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb28-15"&gt;&lt;a href="#cb28-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb28-16"&gt;&lt;a href="#cb28-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;ppExpr ::&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; t &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id="cb28-17"&gt;&lt;a href="#cb28-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ppExpr paren &lt;span class="ot"&gt;=&lt;/span&gt; \&lt;span class="kw"&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb28-18"&gt;&lt;a href="#cb28-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EPrim&lt;/span&gt; p &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; ppPrim p&lt;/span&gt;
&lt;span id="cb28-19"&gt;&lt;a href="#cb28-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EVar&lt;/span&gt; _ v &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; PP.pretty v&lt;/span&gt;
&lt;span id="cb28-20"&gt;&lt;a href="#cb28-20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;ELambda&lt;/span&gt; _ n body &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; wrap &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;\\&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; PP.pretty n &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;-&amp;gt;&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class="dt"&gt;False&lt;/span&gt; body&lt;/span&gt;
&lt;span id="cb28-21"&gt;&lt;a href="#cb28-21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EApply&lt;/span&gt; f x &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; wrap &lt;span class="op"&gt;$&lt;/span&gt; ppExpr &lt;span class="dt"&gt;True&lt;/span&gt; f &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class="dt"&gt;True&lt;/span&gt; x&lt;/span&gt;
&lt;span id="cb28-22"&gt;&lt;a href="#cb28-22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EOp&lt;/span&gt; o x y &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; wrap &lt;span class="op"&gt;$&lt;/span&gt; ppExpr &lt;span class="dt"&gt;True&lt;/span&gt; x &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppOp o &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class="dt"&gt;True&lt;/span&gt; y&lt;/span&gt;
&lt;span id="cb28-23"&gt;&lt;a href="#cb28-23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb28-24"&gt;&lt;a href="#cb28-24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    wrap&lt;/span&gt;
&lt;span id="cb28-25"&gt;&lt;a href="#cb28-25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="op"&gt;|&lt;/span&gt; paren &lt;span class="ot"&gt;=&lt;/span&gt; PP.parens&lt;/span&gt;
&lt;span id="cb28-26"&gt;&lt;a href="#cb28-26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="fu"&gt;otherwise&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;id&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb28-27"&gt;&lt;a href="#cb28-27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb28-28"&gt;&lt;a href="#cb28-28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;prettyExpr ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; t &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id="cb28-29"&gt;&lt;a href="#cb28-29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;prettyExpr &lt;span class="ot"&gt;=&lt;/span&gt; ppExpr &lt;span class="dt"&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="sourceCode" id="cb29"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb29-1"&gt;&lt;a href="#cb29-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; prettyExpr fifteen&lt;/span&gt;
&lt;span id="cb29-2"&gt;&lt;a href="#cb29-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;(\x &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; x &lt;span class="op"&gt;*&lt;/span&gt; &lt;span class="dv"&gt;3&lt;/span&gt;) &lt;span class="dv"&gt;5&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb29-3"&gt;&lt;a href="#cb29-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; prettyExpr plusThree&lt;/span&gt;
&lt;span id="cb29-4"&gt;&lt;a href="#cb29-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;\x &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; x &lt;span class="op"&gt;+&lt;/span&gt; &lt;span class="dv"&gt;3&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb29-5"&gt;&lt;a href="#cb29-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; prettyExpr badVariable&lt;/span&gt;
&lt;span id="cb29-6"&gt;&lt;a href="#cb29-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;(\x &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; x &lt;span class="op"&gt;+&lt;/span&gt; &lt;span class="dv"&gt;3&lt;/span&gt;) true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id="still-not-fully-verified"&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="sourceCode" id="cb30"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb30-1"&gt;&lt;a href="#cb30-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb30-2"&gt;&lt;a href="#cb30-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb30-3"&gt;&lt;a href="#cb30-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;unboundVariable ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb30-4"&gt;&lt;a href="#cb30-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;unboundVariable &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;EVar&lt;/span&gt; &lt;span class="dt"&gt;STInt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;missing&amp;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="sourceCode" id="cb31"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb31-1"&gt;&lt;a href="#cb31-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb31-2"&gt;&lt;a href="#cb31-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb31-3"&gt;&lt;a href="#cb31-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;badVariable ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb31-4"&gt;&lt;a href="#cb31-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;badVariable &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb31-5"&gt;&lt;a href="#cb31-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EApply&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb31-6"&gt;&lt;a href="#cb31-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    (&lt;span class="dt"&gt;ELambda&lt;/span&gt; &lt;span class="dt"&gt;STBool&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;x&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;EOp&lt;/span&gt; &lt;span class="dt"&gt;OPlus&lt;/span&gt; (&lt;span class="dt"&gt;EVar&lt;/span&gt; &lt;span class="dt"&gt;STInt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;x&amp;quot;&lt;/span&gt;) (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;3&lt;/span&gt;))))&lt;/span&gt;
&lt;span id="cb31-7"&gt;&lt;a href="#cb31-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PBool&lt;/span&gt; &lt;span class="dt"&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="typed-records-and-sums"&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="sourceCode" id="cb32"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb32-1"&gt;&lt;a href="#cb32-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb32-2"&gt;&lt;a href="#cb32-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb32-3"&gt;&lt;a href="#cb32-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; &lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Ty&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb32-4"&gt;&lt;a href="#cb32-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb32-5"&gt;&lt;a href="#cb32-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;TBool&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb32-6"&gt;&lt;a href="#cb32-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;TString&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb32-7"&gt;&lt;a href="#cb32-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;TRecord&lt;/span&gt; [(&lt;span class="dt"&gt;Symbol&lt;/span&gt;, &lt;span class="dt"&gt;Ty&lt;/span&gt;)]&lt;/span&gt;
&lt;span id="cb32-8"&gt;&lt;a href="#cb32-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;TSum&lt;/span&gt; [(&lt;span class="dt"&gt;Symbol&lt;/span&gt;, &lt;span class="dt"&gt;Ty&lt;/span&gt;)]&lt;/span&gt;
&lt;span id="cb32-9"&gt;&lt;a href="#cb32-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Ty&lt;/span&gt; &lt;span class="op"&gt;:-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Ty&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb32-10"&gt;&lt;a href="#cb32-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb32-11"&gt;&lt;a href="#cb32-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;STy&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Ty&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Type&lt;/span&gt; &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb32-12"&gt;&lt;a href="#cb32-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;STInt&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;STy&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb32-13"&gt;&lt;a href="#cb32-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;STBool&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;STy&lt;/span&gt; &lt;span class="dt"&gt;TBool&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb32-14"&gt;&lt;a href="#cb32-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;STString&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;STy&lt;/span&gt; &lt;span class="dt"&gt;TString&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb32-15"&gt;&lt;a href="#cb32-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;STRecord&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Rec&lt;/span&gt; &lt;span class="dt"&gt;STyField&lt;/span&gt; as &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;STy&lt;/span&gt; (&lt;span class="dt"&gt;TRecord&lt;/span&gt; as)&lt;/span&gt;
&lt;span id="cb32-16"&gt;&lt;a href="#cb32-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;STSum&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Rec&lt;/span&gt; &lt;span class="dt"&gt;STyField&lt;/span&gt; as &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;STy&lt;/span&gt; (&lt;span class="dt"&gt;TSum&lt;/span&gt; as)&lt;/span&gt;
&lt;span id="cb32-17"&gt;&lt;a href="#cb32-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;STFun&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;STy&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;STy&lt;/span&gt; b &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;STy&lt;/span&gt; (a &lt;span class="op"&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 ["value" ::: TInt, "label" ::: 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 ["Found" ::: TInt, "Missing" ::: 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="https://hackage.haskell.org/package/vinyl"&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="record-access"&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 ["value" ::: TInt, "label" ::: 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="sourceCode" id="cb33"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb33-1"&gt;&lt;a href="#cb33-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb33-2"&gt;&lt;a href="#cb33-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb33-3"&gt;&lt;a href="#cb33-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Index&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; [k] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; k &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Type&lt;/span&gt; &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb33-4"&gt;&lt;a href="#cb33-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;IZ&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Index&lt;/span&gt; (x &lt;span class="op"&gt;:&lt;/span&gt; xs) x&lt;/span&gt;
&lt;span id="cb33-5"&gt;&lt;a href="#cb33-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;IS&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Index&lt;/span&gt; xs x &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Index&lt;/span&gt; (y &lt;span class="op"&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;["value" ::: TInt, "label" ::: TString]&lt;/code&gt;, then we have
values:&lt;/p&gt;
&lt;div class="sourceCode" id="cb34"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb34-1"&gt;&lt;a href="#cb34-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;IZ&lt;/span&gt;&lt;span class="ot"&gt;    ::&lt;/span&gt; &lt;span class="dt"&gt;Index&lt;/span&gt; [&lt;span class="st"&gt;&amp;quot;value&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;, &lt;span class="st"&gt;&amp;quot;label&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TString&lt;/span&gt;] (&lt;span class="st"&gt;&amp;quot;value&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb34-2"&gt;&lt;a href="#cb34-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;IS&lt;/span&gt; &lt;span class="dt"&gt;IZ&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Index&lt;/span&gt; [&lt;span class="st"&gt;&amp;quot;value&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;, &lt;span class="st"&gt;&amp;quot;label&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TString&lt;/span&gt;] (&lt;span class="st"&gt;&amp;quot;label&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&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 ["value" ::: TInt, "label" ::: 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="sourceCode" id="cb35"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb35-1"&gt;&lt;a href="#cb35-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb35-2"&gt;&lt;a href="#cb35-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb35-3"&gt;&lt;a href="#cb35-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EAccess&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;KnownSymbol&lt;/span&gt; l &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; (&lt;span class="dt"&gt;TRecord&lt;/span&gt; as) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Index&lt;/span&gt; as (l &lt;span class="op"&gt;:::&lt;/span&gt; a) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&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="sourceCode" id="cb36"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb36-1"&gt;&lt;a href="#cb36-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;(&lt;span class="ot"&gt;`EAccess`&lt;/span&gt; &lt;span class="dt"&gt;IZ&lt;/span&gt;)&lt;span class="ot"&gt;    ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; (&lt;span class="dt"&gt;TRecord&lt;/span&gt; [&lt;span class="st"&gt;&amp;quot;value&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;, &lt;span class="st"&gt;&amp;quot;label&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TString&lt;/span&gt;]) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb36-2"&gt;&lt;a href="#cb36-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;(&lt;span class="ot"&gt;`EAccess`&lt;/span&gt; &lt;span class="dt"&gt;IS&lt;/span&gt; &lt;span class="dt"&gt;IZ&lt;/span&gt;)&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; (&lt;span class="dt"&gt;TRecord&lt;/span&gt; [&lt;span class="st"&gt;&amp;quot;value&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;, &lt;span class="st"&gt;&amp;quot;label&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TString&lt;/span&gt;]) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; &lt;span class="dt"&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="https://hackage.haskell.org/package/vinyl"&gt;vinyl&lt;/a&gt;&lt;/em&gt; or
&lt;code&gt;NP&lt;/code&gt; from &lt;em&gt;&lt;a
href="https://hackage.haskell.org/package/sop-core"&gt;sop-core&lt;/a&gt;&lt;/em&gt;: a
heterogeneous list indexed by a type-level list.&lt;/p&gt;
&lt;div class="sourceCode" id="cb37"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb37-1"&gt;&lt;a href="#cb37-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb37-2"&gt;&lt;a href="#cb37-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb37-3"&gt;&lt;a href="#cb37-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Rec&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; (k &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Type&lt;/span&gt;) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; [k] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Type&lt;/span&gt; &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb37-4"&gt;&lt;a href="#cb37-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;RNil&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Rec&lt;/span&gt; f &amp;#39;[]&lt;/span&gt;
&lt;span id="cb37-5"&gt;&lt;a href="#cb37-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;  (:&amp;amp;) ::&lt;/span&gt; f x &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Rec&lt;/span&gt; f xs &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Rec&lt;/span&gt; f (x &lt;span class="op"&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="sourceCode" id="cb38"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb38-1"&gt;&lt;a href="#cb38-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;:&lt;/span&gt;t &lt;span class="dt"&gt;Identity&lt;/span&gt; &lt;span class="dv"&gt;3&lt;/span&gt; &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; &lt;span class="dt"&gt;Identity&lt;/span&gt; &lt;span class="dt"&gt;True&lt;/span&gt; &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; &lt;span class="dt"&gt;Identity&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;hello&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; &lt;span class="dt"&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb38-2"&gt;&lt;a href="#cb38-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;Rec&lt;/span&gt; &lt;span class="dt"&gt;Identity&lt;/span&gt; [&lt;span class="dt"&gt;Int&lt;/span&gt;, &lt;span class="dt"&gt;Bool&lt;/span&gt;, &lt;span class="dt"&gt;String&lt;/span&gt;]&lt;/span&gt;
&lt;span id="cb38-3"&gt;&lt;a href="#cb38-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;:&lt;/span&gt;t &lt;span class="dt"&gt;Const&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;x&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; &lt;span class="dt"&gt;Const&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;y&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; &lt;span class="dt"&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb38-4"&gt;&lt;a href="#cb38-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;Rec&lt;/span&gt; (&lt;span class="dt"&gt;Const&lt;/span&gt; &lt;span class="dt"&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="sourceCode" id="cb39"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb39-1"&gt;&lt;a href="#cb39-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb39-2"&gt;&lt;a href="#cb39-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb39-3"&gt;&lt;a href="#cb39-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ExprField&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; (&lt;span class="dt"&gt;Symbol&lt;/span&gt;, &lt;span class="dt"&gt;Ty&lt;/span&gt;) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Type&lt;/span&gt; &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb39-4"&gt;&lt;a href="#cb39-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EField&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;KnownSymbol&lt;/span&gt; l &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ExprField&lt;/span&gt; (l &lt;span class="op"&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="sourceCode" id="cb40"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb40-1"&gt;&lt;a href="#cb40-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;:&lt;/span&gt;t &lt;span class="dt"&gt;EField&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;value&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;7&lt;/span&gt;))&lt;/span&gt;
&lt;span id="cb40-2"&gt;&lt;a href="#cb40-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; &lt;span class="dt"&gt;EField&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;label&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PString&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;found&amp;quot;&lt;/span&gt;))&lt;/span&gt;
&lt;span id="cb40-3"&gt;&lt;a href="#cb40-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; &lt;span class="dt"&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb40-4"&gt;&lt;a href="#cb40-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;Rec&lt;/span&gt; &lt;span class="dt"&gt;ExprField&lt;/span&gt; [&lt;span class="st"&gt;&amp;quot;value&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;, &lt;span class="st"&gt;&amp;quot;label&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&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 ["value" ::: TInt, "label" ::: TString])&lt;/code&gt; by taking a
&lt;code&gt;Rec&lt;/code&gt;:&lt;/p&gt;
&lt;div class="sourceCode" id="cb41"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb41-1"&gt;&lt;a href="#cb41-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb41-2"&gt;&lt;a href="#cb41-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb41-3"&gt;&lt;a href="#cb41-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;ERecord&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Rec&lt;/span&gt; &lt;span class="dt"&gt;ExprField&lt;/span&gt; as &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; (&lt;span class="dt"&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="sourceCode" id="cb42"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb42-1"&gt;&lt;a href="#cb42-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb42-2"&gt;&lt;a href="#cb42-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb42-3"&gt;&lt;a href="#cb42-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;eField ::&lt;/span&gt; &lt;span class="kw"&gt;forall&lt;/span&gt; l &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;KnownSymbol&lt;/span&gt; l &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ExprField&lt;/span&gt; (l &lt;span class="op"&gt;:::&lt;/span&gt; a)&lt;/span&gt;
&lt;span id="cb42-4"&gt;&lt;a href="#cb42-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;eField l &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;EField&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;l&lt;/span&gt;
&lt;span id="cb42-5"&gt;&lt;a href="#cb42-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb42-6"&gt;&lt;a href="#cb42-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;makeRecordExample ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; (&lt;span class="dt"&gt;TRecord&lt;/span&gt; [&lt;span class="st"&gt;&amp;quot;value&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;, &lt;span class="st"&gt;&amp;quot;label&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TString&lt;/span&gt;])&lt;/span&gt;
&lt;span id="cb42-7"&gt;&lt;a href="#cb42-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;makeRecordExample &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb42-8"&gt;&lt;a href="#cb42-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;ERecord&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb42-9"&gt;&lt;a href="#cb42-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ( eField &lt;span class="st"&gt;&amp;quot;value&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;7&lt;/span&gt;))&lt;/span&gt;
&lt;span id="cb42-10"&gt;&lt;a href="#cb42-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; eField &lt;span class="st"&gt;&amp;quot;label&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PString&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;found&amp;quot;&lt;/span&gt;))&lt;/span&gt;
&lt;span id="cb42-11"&gt;&lt;a href="#cb42-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; &lt;span class="dt"&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb42-12"&gt;&lt;a href="#cb42-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    )&lt;/span&gt;
&lt;span id="cb42-13"&gt;&lt;a href="#cb42-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb42-14"&gt;&lt;a href="#cb42-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;recordExample ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb42-15"&gt;&lt;a href="#cb42-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;recordExample &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;EOp&lt;/span&gt; &lt;span class="dt"&gt;OPlus&lt;/span&gt; (&lt;span class="dt"&gt;EAccess&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;value&amp;quot;&lt;/span&gt; makeRecordExample &lt;span class="dt"&gt;IZ&lt;/span&gt;) (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id="sum-injection-and-case-analysis"&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 ["Found" ::: TInt, "Missing" ::: 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="sourceCode" id="cb43"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb43-1"&gt;&lt;a href="#cb43-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb43-2"&gt;&lt;a href="#cb43-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb43-3"&gt;&lt;a href="#cb43-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EChoice&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;KnownSymbol&lt;/span&gt; l &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Index&lt;/span&gt; as (l &lt;span class="op"&gt;:::&lt;/span&gt; a) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; (&lt;span class="dt"&gt;TSum&lt;/span&gt; as)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="sourceCode" id="cb44"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb44-1"&gt;&lt;a href="#cb44-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;EChoice&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;Found&amp;quot;&lt;/span&gt; &lt;span class="dt"&gt;IZ&lt;/span&gt;&lt;span class="ot"&gt;        ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; (&lt;span class="dt"&gt;TSum&lt;/span&gt; [&lt;span class="st"&gt;&amp;quot;Found&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;, &lt;span class="st"&gt;&amp;quot;Missing&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TString&lt;/span&gt;])&lt;/span&gt;
&lt;span id="cb44-2"&gt;&lt;a href="#cb44-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;EChoice&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;Missing&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;IS&lt;/span&gt; &lt;span class="dt"&gt;IZ&lt;/span&gt;)&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; &lt;span class="dt"&gt;TString&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; (&lt;span class="dt"&gt;TSum&lt;/span&gt; [&lt;span class="st"&gt;&amp;quot;Found&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;, &lt;span class="st"&gt;&amp;quot;Missing&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TString&lt;/span&gt;])&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="sourceCode" id="cb45"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb45-1"&gt;&lt;a href="#cb45-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb45-2"&gt;&lt;a href="#cb45-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb45-3"&gt;&lt;a href="#cb45-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;makeSumExample ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; (&lt;span class="dt"&gt;TSum&lt;/span&gt; [&lt;span class="st"&gt;&amp;quot;Found&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;, &lt;span class="st"&gt;&amp;quot;Missing&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TString&lt;/span&gt;])&lt;/span&gt;
&lt;span id="cb45-4"&gt;&lt;a href="#cb45-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;makeSumExample &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;EChoice&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;Found&amp;quot;&lt;/span&gt; &lt;span class="dt"&gt;IZ&lt;/span&gt; (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&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;["Found" ::: TInt, "Missing" ::: TString]&lt;/code&gt; sum:&lt;/p&gt;
&lt;div class="sourceCode" id="cb46"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb46-1"&gt;&lt;a href="#cb46-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb46-2"&gt;&lt;a href="#cb46-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb46-3"&gt;&lt;a href="#cb46-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ExprHandler&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Ty&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; (&lt;span class="dt"&gt;Symbol&lt;/span&gt;, &lt;span class="dt"&gt;Ty&lt;/span&gt;) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Type&lt;/span&gt; &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb46-4"&gt;&lt;a href="#cb46-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EHandler&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;KnownSymbol&lt;/span&gt; l &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;STy&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; b &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ExprHandler&lt;/span&gt; b (l &lt;span class="op"&gt;:::&lt;/span&gt; a)&lt;/span&gt;
&lt;span id="cb46-5"&gt;&lt;a href="#cb46-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb46-6"&gt;&lt;a href="#cb46-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;eHandler ::&lt;/span&gt; &lt;span class="kw"&gt;forall&lt;/span&gt; l &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;KnownSymbol&lt;/span&gt; l &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;STy&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; b &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ExprHandler&lt;/span&gt; b (l &lt;span class="op"&gt;:::&lt;/span&gt; a)&lt;/span&gt;
&lt;span id="cb46-7"&gt;&lt;a href="#cb46-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;eHandler l &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;EHandler&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;l&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="sourceCode" id="cb47"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb47-1"&gt;&lt;a href="#cb47-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;:&lt;/span&gt;t eHandler &lt;span class="st"&gt;&amp;quot;Found&amp;quot;&lt;/span&gt; &lt;span class="dt"&gt;STInt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;value&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;EOp&lt;/span&gt; &lt;span class="dt"&gt;OPlus&lt;/span&gt; (&lt;span class="dt"&gt;EVar&lt;/span&gt; &lt;span class="dt"&gt;STInt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;value&amp;quot;&lt;/span&gt;) (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;)))&lt;/span&gt;
&lt;span id="cb47-2"&gt;&lt;a href="#cb47-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;ExprHandler&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt; (&lt;span class="st"&gt;&amp;quot;Found&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb47-3"&gt;&lt;a href="#cb47-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;         &lt;span class="co"&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="sourceCode" id="cb48"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb48-1"&gt;&lt;a href="#cb48-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;:&lt;/span&gt;t eHandler &lt;span class="st"&gt;&amp;quot;Found&amp;quot;&lt;/span&gt; &lt;span class="dt"&gt;STInt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;value&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;EOp&lt;/span&gt; &lt;span class="dt"&gt;OPlus&lt;/span&gt; (&lt;span class="dt"&gt;EVar&lt;/span&gt; &lt;span class="dt"&gt;STInt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;value&amp;quot;&lt;/span&gt;) (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;)))&lt;/span&gt;
&lt;span id="cb48-2"&gt;&lt;a href="#cb48-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;           &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; eHandler &lt;span class="st"&gt;&amp;quot;Missing&amp;quot;&lt;/span&gt; &lt;span class="dt"&gt;STString&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;message&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;0&lt;/span&gt;))&lt;/span&gt;
&lt;span id="cb48-3"&gt;&lt;a href="#cb48-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;           &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; &lt;span class="dt"&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb48-4"&gt;&lt;a href="#cb48-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;Rec&lt;/span&gt; (&lt;span class="dt"&gt;ExprHandler&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;) [&lt;span class="st"&gt;&amp;quot;Found&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;, &lt;span class="st"&gt;&amp;quot;Missing&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&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="sourceCode" id="cb49"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb49-1"&gt;&lt;a href="#cb49-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb49-2"&gt;&lt;a href="#cb49-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb49-3"&gt;&lt;a href="#cb49-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;ECase&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; (&lt;span class="dt"&gt;TSum&lt;/span&gt; as) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Rec&lt;/span&gt; (&lt;span class="dt"&gt;ExprHandler&lt;/span&gt; b) as &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; b&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="sourceCode" id="cb50"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb50-1"&gt;&lt;a href="#cb50-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb50-2"&gt;&lt;a href="#cb50-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb50-3"&gt;&lt;a href="#cb50-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;sumExample ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb50-4"&gt;&lt;a href="#cb50-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;sumExample &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb50-5"&gt;&lt;a href="#cb50-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;ECase&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb50-6"&gt;&lt;a href="#cb50-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    makeSumExample&lt;/span&gt;
&lt;span id="cb50-7"&gt;&lt;a href="#cb50-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ( eHandler &lt;span class="st"&gt;&amp;quot;Found&amp;quot;&lt;/span&gt; &lt;span class="dt"&gt;STInt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;value&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;EOp&lt;/span&gt; &lt;span class="dt"&gt;OPlus&lt;/span&gt; (&lt;span class="dt"&gt;EVar&lt;/span&gt; &lt;span class="dt"&gt;STInt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;value&amp;quot;&lt;/span&gt;) (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;)))&lt;/span&gt;
&lt;span id="cb50-8"&gt;&lt;a href="#cb50-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; eHandler &lt;span class="st"&gt;&amp;quot;Missing&amp;quot;&lt;/span&gt; &lt;span class="dt"&gt;STString&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;message&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;0&lt;/span&gt;))&lt;/span&gt;
&lt;span id="cb50-9"&gt;&lt;a href="#cb50-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; &lt;span class="dt"&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb50-10"&gt;&lt;a href="#cb50-10" aria-hidden="true" tabindex="-1"&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;"value"&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 "value"&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 "value"&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="sourceCode" id="cb51"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb51-1"&gt;&lt;a href="#cb51-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb51-2"&gt;&lt;a href="#cb51-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb51-3"&gt;&lt;a href="#cb51-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;badCaseBranchExample ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb51-4"&gt;&lt;a href="#cb51-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;badCaseBranchExample &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb51-5"&gt;&lt;a href="#cb51-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;ECase&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb51-6"&gt;&lt;a href="#cb51-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    (&lt;span class="dt"&gt;EChoice&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;Found&amp;quot;&lt;/span&gt; &lt;span class="dt"&gt;IZ&lt;/span&gt; (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;7&lt;/span&gt;)))&lt;/span&gt;
&lt;span id="cb51-7"&gt;&lt;a href="#cb51-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ( eHandler &lt;span class="st"&gt;&amp;quot;Found&amp;quot;&lt;/span&gt; &lt;span class="dt"&gt;STInt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;value&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;EOp&lt;/span&gt; &lt;span class="dt"&gt;OPlus&lt;/span&gt; (&lt;span class="dt"&gt;EVar&lt;/span&gt; &lt;span class="dt"&gt;STInt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;missing&amp;quot;&lt;/span&gt;) (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;)))&lt;/span&gt;
&lt;span id="cb51-8"&gt;&lt;a href="#cb51-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; eHandler &lt;span class="st"&gt;&amp;quot;Missing&amp;quot;&lt;/span&gt; &lt;span class="dt"&gt;STString&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;message&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;EOp&lt;/span&gt; &lt;span class="dt"&gt;OPlus&lt;/span&gt; (&lt;span class="dt"&gt;EVar&lt;/span&gt; &lt;span class="dt"&gt;STInt&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;message&amp;quot;&lt;/span&gt;) (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;)))&lt;/span&gt;
&lt;span id="cb51-9"&gt;&lt;a href="#cb51-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; &lt;span class="dt"&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb51-10"&gt;&lt;a href="#cb51-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    )&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id="runtime-equality-for-records-and-sums"&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="sourceCode" id="cb52"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb52-1"&gt;&lt;a href="#cb52-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb52-2"&gt;&lt;a href="#cb52-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb52-3"&gt;&lt;a href="#cb52-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;instance&lt;/span&gt; &lt;span class="dt"&gt;TestEquality&lt;/span&gt; &lt;span class="dt"&gt;STy&lt;/span&gt; &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb52-4"&gt;&lt;a href="#cb52-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    testEquality &lt;span class="ot"&gt;=&lt;/span&gt; sameTy&lt;/span&gt;
&lt;span id="cb52-5"&gt;&lt;a href="#cb52-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb52-6"&gt;&lt;a href="#cb52-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;instance&lt;/span&gt; &lt;span class="dt"&gt;TestEquality&lt;/span&gt; &lt;span class="dt"&gt;STyField&lt;/span&gt; &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb52-7"&gt;&lt;a href="#cb52-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    testEquality &lt;span class="ot"&gt;=&lt;/span&gt; sameField&lt;/span&gt;
&lt;span id="cb52-8"&gt;&lt;a href="#cb52-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb52-9"&gt;&lt;a href="#cb52-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;sameTy ::&lt;/span&gt; &lt;span class="dt"&gt;STy&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;STy&lt;/span&gt; b &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; (a &lt;span class="op"&gt;:~:&lt;/span&gt; b)&lt;/span&gt;
&lt;span id="cb52-10"&gt;&lt;a href="#cb52-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;sameTy &lt;span class="ot"&gt;=&lt;/span&gt; \&lt;span class="kw"&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb52-11"&gt;&lt;a href="#cb52-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;STInt&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; \&lt;span class="kw"&gt;case&lt;/span&gt; &lt;span class="dt"&gt;STInt&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Just&lt;/span&gt; &lt;span class="dt"&gt;Refl&lt;/span&gt;; _ &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb52-12"&gt;&lt;a href="#cb52-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;STBool&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; \&lt;span class="kw"&gt;case&lt;/span&gt; &lt;span class="dt"&gt;STBool&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Just&lt;/span&gt; &lt;span class="dt"&gt;Refl&lt;/span&gt;; _ &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb52-13"&gt;&lt;a href="#cb52-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;STString&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; \&lt;span class="kw"&gt;case&lt;/span&gt; &lt;span class="dt"&gt;STString&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Just&lt;/span&gt; &lt;span class="dt"&gt;Refl&lt;/span&gt;; _ &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb52-14"&gt;&lt;a href="#cb52-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;STRecord&lt;/span&gt; as &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; \&lt;span class="kw"&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb52-15"&gt;&lt;a href="#cb52-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;STRecord&lt;/span&gt; bs &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb52-16"&gt;&lt;a href="#cb52-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;Refl&lt;/span&gt; &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; sameFields as bs&lt;/span&gt;
&lt;span id="cb52-17"&gt;&lt;a href="#cb52-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;Just&lt;/span&gt; &lt;span class="dt"&gt;Refl&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb52-18"&gt;&lt;a href="#cb52-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    _ &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb52-19"&gt;&lt;a href="#cb52-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;STSum&lt;/span&gt; as &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; \&lt;span class="kw"&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb52-20"&gt;&lt;a href="#cb52-20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;STSum&lt;/span&gt; bs &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb52-21"&gt;&lt;a href="#cb52-21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;Refl&lt;/span&gt; &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; sameFields as bs&lt;/span&gt;
&lt;span id="cb52-22"&gt;&lt;a href="#cb52-22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;Just&lt;/span&gt; &lt;span class="dt"&gt;Refl&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb52-23"&gt;&lt;a href="#cb52-23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    _ &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb52-24"&gt;&lt;a href="#cb52-24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;STFun&lt;/span&gt; a b &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; \&lt;span class="kw"&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb52-25"&gt;&lt;a href="#cb52-25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;STFun&lt;/span&gt; c d &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb52-26"&gt;&lt;a href="#cb52-26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;Refl&lt;/span&gt; &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; sameTy a c&lt;/span&gt;
&lt;span id="cb52-27"&gt;&lt;a href="#cb52-27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;Refl&lt;/span&gt; &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; sameTy b d&lt;/span&gt;
&lt;span id="cb52-28"&gt;&lt;a href="#cb52-28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;Just&lt;/span&gt; &lt;span class="dt"&gt;Refl&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb52-29"&gt;&lt;a href="#cb52-29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    _ &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb52-30"&gt;&lt;a href="#cb52-30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb52-31"&gt;&lt;a href="#cb52-31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;sameFields ::&lt;/span&gt; &lt;span class="dt"&gt;Rec&lt;/span&gt; &lt;span class="dt"&gt;STyField&lt;/span&gt; xs &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Rec&lt;/span&gt; &lt;span class="dt"&gt;STyField&lt;/span&gt; ys &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; (xs &lt;span class="op"&gt;:~:&lt;/span&gt; ys)&lt;/span&gt;
&lt;span id="cb52-32"&gt;&lt;a href="#cb52-32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;sameFields &lt;span class="dt"&gt;RNil&lt;/span&gt; &lt;span class="dt"&gt;RNil&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Just&lt;/span&gt; &lt;span class="dt"&gt;Refl&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb52-33"&gt;&lt;a href="#cb52-33" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;sameFields (x &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; xs) (y &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; ys) &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb52-34"&gt;&lt;a href="#cb52-34" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;Refl&lt;/span&gt; &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; sameField x y&lt;/span&gt;
&lt;span id="cb52-35"&gt;&lt;a href="#cb52-35" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;Refl&lt;/span&gt; &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; sameFields xs ys&lt;/span&gt;
&lt;span id="cb52-36"&gt;&lt;a href="#cb52-36" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;Just&lt;/span&gt; &lt;span class="dt"&gt;Refl&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb52-37"&gt;&lt;a href="#cb52-37" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;sameFields _ _ &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb52-38"&gt;&lt;a href="#cb52-38" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb52-39"&gt;&lt;a href="#cb52-39" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;sameField ::&lt;/span&gt; &lt;span class="dt"&gt;STyField&lt;/span&gt; x &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;STyField&lt;/span&gt; y &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; (x &lt;span class="op"&gt;:~:&lt;/span&gt; y)&lt;/span&gt;
&lt;span id="cb52-40"&gt;&lt;a href="#cb52-40" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;sameField (&lt;span class="dt"&gt;STyField&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;l tx) (&lt;span class="dt"&gt;STyField&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;m ty) &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb52-41"&gt;&lt;a href="#cb52-41" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Refl&lt;/span&gt; &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; sameSymbol (&lt;span class="dt"&gt;Proxy&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;l) (&lt;span class="dt"&gt;Proxy&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;m)&lt;/span&gt;
&lt;span id="cb52-42"&gt;&lt;a href="#cb52-42" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Refl&lt;/span&gt; &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; sameTy tx ty&lt;/span&gt;
&lt;span id="cb52-43"&gt;&lt;a href="#cb52-43" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Just&lt;/span&gt; &lt;span class="dt"&gt;Refl&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id="the-full-eval"&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="sourceCode" id="cb53"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb53-1"&gt;&lt;a href="#cb53-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb53-2"&gt;&lt;a href="#cb53-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb53-3"&gt;&lt;a href="#cb53-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;indexRec ::&lt;/span&gt; &lt;span class="dt"&gt;Index&lt;/span&gt; xs x &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Rec&lt;/span&gt; f xs &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; f x&lt;/span&gt;
&lt;span id="cb53-4"&gt;&lt;a href="#cb53-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;indexRec &lt;span class="ot"&gt;=&lt;/span&gt; \&lt;span class="kw"&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb53-5"&gt;&lt;a href="#cb53-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;IZ&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; \(x &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; _) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; x&lt;/span&gt;
&lt;span id="cb53-6"&gt;&lt;a href="#cb53-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;IS&lt;/span&gt; i &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; \(_ &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; xs) &lt;span class="ot"&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="sourceCode" id="cb54"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb54-1"&gt;&lt;a href="#cb54-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb54-2"&gt;&lt;a href="#cb54-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb54-3"&gt;&lt;a href="#cb54-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;traverseRec ::&lt;/span&gt; &lt;span class="dt"&gt;Applicative&lt;/span&gt; m &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt; (&lt;span class="kw"&gt;forall&lt;/span&gt; x&lt;span class="op"&gt;.&lt;/span&gt; f x &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; m (g x)) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Rec&lt;/span&gt; f xs &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; m (&lt;span class="dt"&gt;Rec&lt;/span&gt; g xs)&lt;/span&gt;
&lt;span id="cb54-4"&gt;&lt;a href="#cb54-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;traverseRec _ &lt;span class="dt"&gt;RNil&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;pure&lt;/span&gt; &lt;span class="dt"&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb54-5"&gt;&lt;a href="#cb54-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;traverseRec f (x &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; xs) &lt;span class="ot"&gt;=&lt;/span&gt; (&lt;span class="op"&gt;:&amp;amp;&lt;/span&gt;) &lt;span class="op"&gt;&amp;lt;$&amp;gt;&lt;/span&gt; f x &lt;span class="op"&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="sourceCode" id="cb55"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb55-1"&gt;&lt;a href="#cb55-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb55-2"&gt;&lt;a href="#cb55-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb55-3"&gt;&lt;a href="#cb55-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;eval ::&lt;/span&gt; &lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt; &lt;span class="dt"&gt;SomeValue&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; t &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; (&lt;span class="dt"&gt;EValue&lt;/span&gt; t)&lt;/span&gt;
&lt;span id="cb55-4"&gt;&lt;a href="#cb55-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;eval env &lt;span class="ot"&gt;=&lt;/span&gt; \&lt;span class="kw"&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb55-5"&gt;&lt;a href="#cb55-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; n) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;pure&lt;/span&gt; (&lt;span class="dt"&gt;EVInt&lt;/span&gt; n)&lt;/span&gt;
&lt;span id="cb55-6"&gt;&lt;a href="#cb55-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PBool&lt;/span&gt; b) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;pure&lt;/span&gt; (&lt;span class="dt"&gt;EVBool&lt;/span&gt; b)&lt;/span&gt;
&lt;span id="cb55-7"&gt;&lt;a href="#cb55-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PString&lt;/span&gt; s) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;pure&lt;/span&gt; (&lt;span class="dt"&gt;EVString&lt;/span&gt; s)&lt;/span&gt;
&lt;span id="cb55-8"&gt;&lt;a href="#cb55-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EVar&lt;/span&gt; t v &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb55-9"&gt;&lt;a href="#cb55-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;SomeValue&lt;/span&gt; t&amp;#39; v&amp;#39; &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; M.lookup v env&lt;/span&gt;
&lt;span id="cb55-10"&gt;&lt;a href="#cb55-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Refl&lt;/span&gt; &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; sameTy t t&amp;#39;&lt;/span&gt;
&lt;span id="cb55-11"&gt;&lt;a href="#cb55-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;pure&lt;/span&gt; v&amp;#39;&lt;/span&gt;
&lt;span id="cb55-12"&gt;&lt;a href="#cb55-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;ELambda&lt;/span&gt; ta n body &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb55-13"&gt;&lt;a href="#cb55-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;pure&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="dt"&gt;EVFun&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; \x &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; eval (M.insert n (&lt;span class="dt"&gt;SomeValue&lt;/span&gt; ta x) env) body&lt;/span&gt;
&lt;span id="cb55-14"&gt;&lt;a href="#cb55-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EApply&lt;/span&gt; f x &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb55-15"&gt;&lt;a href="#cb55-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;EVFun&lt;/span&gt; g &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; eval env f&lt;/span&gt;
&lt;span id="cb55-16"&gt;&lt;a href="#cb55-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    x&amp;#39; &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id="cb55-17"&gt;&lt;a href="#cb55-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    g x&amp;#39;&lt;/span&gt;
&lt;span id="cb55-18"&gt;&lt;a href="#cb55-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EOp&lt;/span&gt; o x y &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;case&lt;/span&gt; o &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb55-19"&gt;&lt;a href="#cb55-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;OPlus&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb55-20"&gt;&lt;a href="#cb55-20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;EVInt&lt;/span&gt; a &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id="cb55-21"&gt;&lt;a href="#cb55-21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;EVInt&lt;/span&gt; b &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; eval env y&lt;/span&gt;
&lt;span id="cb55-22"&gt;&lt;a href="#cb55-22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;pure&lt;/span&gt; (&lt;span class="dt"&gt;EVInt&lt;/span&gt; (a &lt;span class="op"&gt;+&lt;/span&gt; b))&lt;/span&gt;
&lt;span id="cb55-23"&gt;&lt;a href="#cb55-23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;OTimes&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb55-24"&gt;&lt;a href="#cb55-24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;EVInt&lt;/span&gt; a &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id="cb55-25"&gt;&lt;a href="#cb55-25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;EVInt&lt;/span&gt; b &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; eval env y&lt;/span&gt;
&lt;span id="cb55-26"&gt;&lt;a href="#cb55-26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;pure&lt;/span&gt; (&lt;span class="dt"&gt;EVInt&lt;/span&gt; (a &lt;span class="op"&gt;*&lt;/span&gt; b))&lt;/span&gt;
&lt;span id="cb55-27"&gt;&lt;a href="#cb55-27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;OLte&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb55-28"&gt;&lt;a href="#cb55-28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;EVInt&lt;/span&gt; a &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id="cb55-29"&gt;&lt;a href="#cb55-29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;EVInt&lt;/span&gt; b &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; eval env y&lt;/span&gt;
&lt;span id="cb55-30"&gt;&lt;a href="#cb55-30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;pure&lt;/span&gt; (&lt;span class="dt"&gt;EVBool&lt;/span&gt; (a &lt;span class="op"&gt;&amp;lt;=&lt;/span&gt; b))&lt;/span&gt;
&lt;span id="cb55-31"&gt;&lt;a href="#cb55-31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;OAnd&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb55-32"&gt;&lt;a href="#cb55-32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;EVBool&lt;/span&gt; a &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id="cb55-33"&gt;&lt;a href="#cb55-33" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;EVBool&lt;/span&gt; b &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; eval env y&lt;/span&gt;
&lt;span id="cb55-34"&gt;&lt;a href="#cb55-34" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;pure&lt;/span&gt; (&lt;span class="dt"&gt;EVBool&lt;/span&gt; (a &lt;span class="op"&gt;&amp;amp;&amp;amp;&lt;/span&gt; b))&lt;/span&gt;
&lt;span id="cb55-35"&gt;&lt;a href="#cb55-35" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;ERecord&lt;/span&gt; xs &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb55-36"&gt;&lt;a href="#cb55-36" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;EVRecord&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;$&amp;gt;&lt;/span&gt; traverseRec (evalField env) xs&lt;/span&gt;
&lt;span id="cb55-37"&gt;&lt;a href="#cb55-37" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EAccess&lt;/span&gt; e i &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb55-38"&gt;&lt;a href="#cb55-38" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;EVRecord&lt;/span&gt; xs &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; eval env e&lt;/span&gt;
&lt;span id="cb55-39"&gt;&lt;a href="#cb55-39" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;case&lt;/span&gt; indexRec i xs &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb55-40"&gt;&lt;a href="#cb55-40" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;EVField&lt;/span&gt; v &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;pure&lt;/span&gt; v&lt;/span&gt;
&lt;span id="cb55-41"&gt;&lt;a href="#cb55-41" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EChoice&lt;/span&gt; i x &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb55-42"&gt;&lt;a href="#cb55-42" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;EVSum&lt;/span&gt; i &lt;span class="op"&gt;&amp;lt;$&amp;gt;&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id="cb55-43"&gt;&lt;a href="#cb55-43" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;ECase&lt;/span&gt; x hs &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb55-44"&gt;&lt;a href="#cb55-44" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;EVSum&lt;/span&gt; i v &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; eval env x&lt;/span&gt;
&lt;span id="cb55-45"&gt;&lt;a href="#cb55-45" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;case&lt;/span&gt; indexRec i hs &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb55-46"&gt;&lt;a href="#cb55-46" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;EHandler&lt;/span&gt; t n body &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; eval (M.insert n (&lt;span class="dt"&gt;SomeValue&lt;/span&gt; t v) env) body&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id="ergonomics-of-records-and-sums"&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="sourceCode" id="cb56"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb56-1"&gt;&lt;a href="#cb56-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb56-2"&gt;&lt;a href="#cb56-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb56-3"&gt;&lt;a href="#cb56-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;class&lt;/span&gt; &lt;span class="dt"&gt;ListIx&lt;/span&gt; (&lt;span class="ot"&gt;l ::&lt;/span&gt; &lt;span class="dt"&gt;Symbol&lt;/span&gt;) (&lt;span class="ot"&gt;xs ::&lt;/span&gt; [(&lt;span class="dt"&gt;Symbol&lt;/span&gt;, &lt;span class="dt"&gt;Ty&lt;/span&gt;)]) (&lt;span class="ot"&gt;a ::&lt;/span&gt; &lt;span class="dt"&gt;Ty&lt;/span&gt;) &lt;span class="op"&gt;|&lt;/span&gt; l xs &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; a &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb56-4"&gt;&lt;a href="#cb56-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;  listIx ::&lt;/span&gt; &lt;span class="dt"&gt;Index&lt;/span&gt; xs (l &lt;span class="op"&gt;:::&lt;/span&gt; a)&lt;/span&gt;
&lt;span id="cb56-5"&gt;&lt;a href="#cb56-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb56-6"&gt;&lt;a href="#cb56-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;instance&lt;/span&gt; &lt;span class="dt"&gt;ListIx&lt;/span&gt; l (l &lt;span class="op"&gt;:::&lt;/span&gt; a &lt;span class="op"&gt;:&lt;/span&gt; xs) a &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb56-7"&gt;&lt;a href="#cb56-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  listIx &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;IZ&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb56-8"&gt;&lt;a href="#cb56-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb56-9"&gt;&lt;a href="#cb56-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;instance&lt;/span&gt; &lt;span class="ot"&gt;{-# OVERLAPPABLE #-}&lt;/span&gt; &lt;span class="dt"&gt;ListIx&lt;/span&gt; l xs a &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ListIx&lt;/span&gt; l (m &lt;span class="op"&gt;:::&lt;/span&gt; b &lt;span class="op"&gt;:&lt;/span&gt; xs) a &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb56-10"&gt;&lt;a href="#cb56-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  listIx &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;IS&lt;/span&gt; (listIx &lt;span class="op"&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 "value" ["value" ::: TInt, "label" ::: TString] TInt&lt;/code&gt;, where
the label &lt;code&gt;"value"&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 "value"&lt;/code&gt; using GHC 9.10’s
&lt;code&gt;RequiredTypeArguments&lt;/code&gt;:&lt;/p&gt;
&lt;div class="sourceCode" id="cb57"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb57-1"&gt;&lt;a href="#cb57-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb57-2"&gt;&lt;a href="#cb57-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb57-3"&gt;&lt;a href="#cb57-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;eAccess ::&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb57-4"&gt;&lt;a href="#cb57-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;forall&lt;/span&gt; (&lt;span class="ot"&gt;l ::&lt;/span&gt; &lt;span class="dt"&gt;Symbol&lt;/span&gt;) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb57-5"&gt;&lt;a href="#cb57-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  (&lt;span class="dt"&gt;KnownSymbol&lt;/span&gt; l, &lt;span class="dt"&gt;ListIx&lt;/span&gt; l as a) &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb57-6"&gt;&lt;a href="#cb57-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;Expr&lt;/span&gt; (&lt;span class="dt"&gt;TRecord&lt;/span&gt; as) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb57-7"&gt;&lt;a href="#cb57-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;Expr&lt;/span&gt; a&lt;/span&gt;
&lt;span id="cb57-8"&gt;&lt;a href="#cb57-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;eAccess l e &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;EAccess&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;l e (listIx &lt;span class="op"&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="sourceCode" id="cb58"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb58-1"&gt;&lt;a href="#cb58-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb58-2"&gt;&lt;a href="#cb58-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb58-3"&gt;&lt;a href="#cb58-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;namedAccessExample ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; &lt;span class="dt"&gt;TString&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb58-4"&gt;&lt;a href="#cb58-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;namedAccessExample &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb58-5"&gt;&lt;a href="#cb58-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  eAccess&lt;/span&gt;
&lt;span id="cb58-6"&gt;&lt;a href="#cb58-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="st"&gt;&amp;quot;label&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb58-7"&gt;&lt;a href="#cb58-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ( &lt;span class="dt"&gt;ERecord&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb58-8"&gt;&lt;a href="#cb58-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ( eField &lt;span class="st"&gt;&amp;quot;value&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;7&lt;/span&gt;))&lt;/span&gt;
&lt;span id="cb58-9"&gt;&lt;a href="#cb58-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; eField &lt;span class="st"&gt;&amp;quot;label&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PString&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;found&amp;quot;&lt;/span&gt;))&lt;/span&gt;
&lt;span id="cb58-10"&gt;&lt;a href="#cb58-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; &lt;span class="dt"&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb58-11"&gt;&lt;a href="#cb58-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        )&lt;/span&gt;
&lt;span id="cb58-12"&gt;&lt;a href="#cb58-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    )&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here,
&lt;code&gt;eAccess "value" :: Expr (TRecord ["value" ::: TInt, "label" ::: 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="sourceCode" id="cb59"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb59-1"&gt;&lt;a href="#cb59-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb59-2"&gt;&lt;a href="#cb59-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb59-3"&gt;&lt;a href="#cb59-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;eChoice ::&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb59-4"&gt;&lt;a href="#cb59-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;forall&lt;/span&gt; (&lt;span class="ot"&gt;l ::&lt;/span&gt; &lt;span class="dt"&gt;Symbol&lt;/span&gt;) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb59-5"&gt;&lt;a href="#cb59-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  (&lt;span class="dt"&gt;KnownSymbol&lt;/span&gt; l, &lt;span class="dt"&gt;ListIx&lt;/span&gt; l as a) &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb59-6"&gt;&lt;a href="#cb59-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;Expr&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb59-7"&gt;&lt;a href="#cb59-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;Expr&lt;/span&gt; (&lt;span class="dt"&gt;TSum&lt;/span&gt; as)&lt;/span&gt;
&lt;span id="cb59-8"&gt;&lt;a href="#cb59-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;eChoice l e &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;EChoice&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;l (listIx &lt;span class="op"&gt;@&lt;/span&gt;l) e&lt;/span&gt;
&lt;span id="cb59-9"&gt;&lt;a href="#cb59-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb59-10"&gt;&lt;a href="#cb59-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;namedChoiceExample ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; (&lt;span class="dt"&gt;TSum&lt;/span&gt; [&lt;span class="st"&gt;&amp;quot;Found&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;, &lt;span class="st"&gt;&amp;quot;Missing&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TString&lt;/span&gt;])&lt;/span&gt;
&lt;span id="cb59-11"&gt;&lt;a href="#cb59-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;namedChoiceExample &lt;span class="ot"&gt;=&lt;/span&gt; eChoice &lt;span class="st"&gt;&amp;quot;Missing&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PString&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;not here&amp;quot;&lt;/span&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here,
&lt;code&gt;eChoice "Missing" :: Expr TString -&amp;gt; Expr (TSum ["Found" ::: TInt, "Missing" ::: TString])&lt;/code&gt;,
because the constructor name &lt;code&gt;"Missing"&lt;/code&gt; uniquely determines the
payload type inside that sum.&lt;/p&gt;
&lt;h3 id="pretty-printing-records-and-sums"&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="sourceCode" id="cb60"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb60-1"&gt;&lt;a href="#cb60-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb60-2"&gt;&lt;a href="#cb60-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb60-3"&gt;&lt;a href="#cb60-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;ppPrim ::&lt;/span&gt; &lt;span class="dt"&gt;Prim&lt;/span&gt; t &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id="cb60-4"&gt;&lt;a href="#cb60-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ppPrim &lt;span class="ot"&gt;=&lt;/span&gt; \&lt;span class="kw"&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb60-5"&gt;&lt;a href="#cb60-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;PInt&lt;/span&gt; n &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; PP.pretty n&lt;/span&gt;
&lt;span id="cb60-6"&gt;&lt;a href="#cb60-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;PBool&lt;/span&gt; b &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;if&lt;/span&gt; b &lt;span class="kw"&gt;then&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;true&amp;quot;&lt;/span&gt; &lt;span class="kw"&gt;else&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb60-7"&gt;&lt;a href="#cb60-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;PString&lt;/span&gt; s &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; PP.pretty (&lt;span class="fu"&gt;show&lt;/span&gt; s)&lt;/span&gt;
&lt;span id="cb60-8"&gt;&lt;a href="#cb60-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb60-9"&gt;&lt;a href="#cb60-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;ppOp ::&lt;/span&gt; &lt;span class="dt"&gt;Op&lt;/span&gt; a b c &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id="cb60-10"&gt;&lt;a href="#cb60-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ppOp &lt;span class="ot"&gt;=&lt;/span&gt; \&lt;span class="kw"&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb60-11"&gt;&lt;a href="#cb60-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;OPlus&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;+&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb60-12"&gt;&lt;a href="#cb60-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;OTimes&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;*&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb60-13"&gt;&lt;a href="#cb60-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;OLte&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;&amp;lt;=&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb60-14"&gt;&lt;a href="#cb60-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;OAnd&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;&amp;amp;&amp;amp;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb60-15"&gt;&lt;a href="#cb60-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb60-16"&gt;&lt;a href="#cb60-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;ppFields ::&lt;/span&gt; &lt;span class="dt"&gt;Rec&lt;/span&gt; &lt;span class="dt"&gt;ExprField&lt;/span&gt; xs &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; [&lt;span class="dt"&gt;PP.Doc&lt;/span&gt; ann]&lt;/span&gt;
&lt;span id="cb60-17"&gt;&lt;a href="#cb60-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ppFields &lt;span class="dt"&gt;RNil&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; []&lt;/span&gt;
&lt;span id="cb60-18"&gt;&lt;a href="#cb60-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ppFields (&lt;span class="dt"&gt;EField&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;l x &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; xs) &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb60-19"&gt;&lt;a href="#cb60-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  (PP.pretty (symbolVal (&lt;span class="dt"&gt;Proxy&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;l)) &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;=&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class="dt"&gt;False&lt;/span&gt; x) &lt;span class="op"&gt;:&lt;/span&gt; ppFields xs&lt;/span&gt;
&lt;span id="cb60-20"&gt;&lt;a href="#cb60-20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb60-21"&gt;&lt;a href="#cb60-21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;ppHandlers ::&lt;/span&gt; &lt;span class="dt"&gt;Rec&lt;/span&gt; (&lt;span class="dt"&gt;ExprHandler&lt;/span&gt; b) xs &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; [&lt;span class="dt"&gt;PP.Doc&lt;/span&gt; ann]&lt;/span&gt;
&lt;span id="cb60-22"&gt;&lt;a href="#cb60-22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ppHandlers &lt;span class="dt"&gt;RNil&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; []&lt;/span&gt;
&lt;span id="cb60-23"&gt;&lt;a href="#cb60-23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ppHandlers (&lt;span class="dt"&gt;EHandler&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;l _ n body &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; xs) &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb60-24"&gt;&lt;a href="#cb60-24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  (PP.pretty (symbolVal (&lt;span class="dt"&gt;Proxy&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;l)) &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; PP.pretty n &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;-&amp;gt;&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class="dt"&gt;False&lt;/span&gt; body) &lt;span class="op"&gt;:&lt;/span&gt; ppHandlers xs&lt;/span&gt;
&lt;span id="cb60-25"&gt;&lt;a href="#cb60-25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb60-26"&gt;&lt;a href="#cb60-26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;ppExpr ::&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; t &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id="cb60-27"&gt;&lt;a href="#cb60-27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ppExpr paren &lt;span class="ot"&gt;=&lt;/span&gt; \&lt;span class="kw"&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb60-28"&gt;&lt;a href="#cb60-28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EPrim&lt;/span&gt; p &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; ppPrim p&lt;/span&gt;
&lt;span id="cb60-29"&gt;&lt;a href="#cb60-29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EVar&lt;/span&gt; _ v &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; PP.pretty v&lt;/span&gt;
&lt;span id="cb60-30"&gt;&lt;a href="#cb60-30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;ELambda&lt;/span&gt; _ n body &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; wrap &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;\\&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; PP.pretty n &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;-&amp;gt;&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class="dt"&gt;False&lt;/span&gt; body&lt;/span&gt;
&lt;span id="cb60-31"&gt;&lt;a href="#cb60-31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EApply&lt;/span&gt; f x &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; wrap &lt;span class="op"&gt;$&lt;/span&gt; ppExpr &lt;span class="dt"&gt;True&lt;/span&gt; f &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class="dt"&gt;True&lt;/span&gt; x&lt;/span&gt;
&lt;span id="cb60-32"&gt;&lt;a href="#cb60-32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EOp&lt;/span&gt; o x y &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; wrap &lt;span class="op"&gt;$&lt;/span&gt; ppExpr &lt;span class="dt"&gt;True&lt;/span&gt; x &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppOp o &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class="dt"&gt;True&lt;/span&gt; y&lt;/span&gt;
&lt;span id="cb60-33"&gt;&lt;a href="#cb60-33" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;ERecord&lt;/span&gt; xs &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; PP.encloseSep &lt;span class="st"&gt;&amp;quot;{ &amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot; }&amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;, &amp;quot;&lt;/span&gt; (ppFields xs)&lt;/span&gt;
&lt;span id="cb60-34"&gt;&lt;a href="#cb60-34" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EAccess&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;l e _ &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; ppExpr &lt;span class="dt"&gt;True&lt;/span&gt; e &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;.&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; PP.pretty (symbolVal (&lt;span class="dt"&gt;Proxy&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;l))&lt;/span&gt;
&lt;span id="cb60-35"&gt;&lt;a href="#cb60-35" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EChoice&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;l _ x &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; wrap &lt;span class="op"&gt;$&lt;/span&gt; PP.pretty (symbolVal (&lt;span class="dt"&gt;Proxy&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;l)) &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class="dt"&gt;True&lt;/span&gt; x&lt;/span&gt;
&lt;span id="cb60-36"&gt;&lt;a href="#cb60-36" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;ECase&lt;/span&gt; x hs &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb60-37"&gt;&lt;a href="#cb60-37" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    wrap &lt;span class="op"&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb60-38"&gt;&lt;a href="#cb60-38" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      PP.sep&lt;/span&gt;
&lt;span id="cb60-39"&gt;&lt;a href="#cb60-39" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        [ &lt;span class="st"&gt;&amp;quot;case&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr &lt;span class="dt"&gt;False&lt;/span&gt; x &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;of&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb60-40"&gt;&lt;a href="#cb60-40" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , PP.encloseSep &lt;span class="st"&gt;&amp;quot;{ &amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot; }&amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;; &amp;quot;&lt;/span&gt; (ppHandlers hs)&lt;/span&gt;
&lt;span id="cb60-41"&gt;&lt;a href="#cb60-41" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ]&lt;/span&gt;
&lt;span id="cb60-42"&gt;&lt;a href="#cb60-42" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb60-43"&gt;&lt;a href="#cb60-43" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    wrap&lt;/span&gt;
&lt;span id="cb60-44"&gt;&lt;a href="#cb60-44" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="op"&gt;|&lt;/span&gt; paren &lt;span class="ot"&gt;=&lt;/span&gt; PP.parens&lt;/span&gt;
&lt;span id="cb60-45"&gt;&lt;a href="#cb60-45" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="fu"&gt;otherwise&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;id&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb60-46"&gt;&lt;a href="#cb60-46" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb60-47"&gt;&lt;a href="#cb60-47" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;prettyExpr ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; t &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id="cb60-48"&gt;&lt;a href="#cb60-48" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;prettyExpr &lt;span class="ot"&gt;=&lt;/span&gt; ppExpr &lt;span class="dt"&gt;False&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id="capturing-variables"&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="sourceCode" id="cb61"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb61-1"&gt;&lt;a href="#cb61-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb61-2"&gt;&lt;a href="#cb61-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb61-3"&gt;&lt;a href="#cb61-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; [(&lt;span class="dt"&gt;Symbol&lt;/span&gt;, &lt;span class="dt"&gt;Ty&lt;/span&gt;)] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Ty&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Type&lt;/span&gt; &lt;span class="kw"&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 ["x" ::: TInt, "y" ::: 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="sourceCode" id="cb62"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb62-1"&gt;&lt;a href="#cb62-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb62-2"&gt;&lt;a href="#cb62-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb62-3"&gt;&lt;a href="#cb62-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;ELambda&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;KnownSymbol&lt;/span&gt; n &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; (n &lt;span class="op"&gt;:::&lt;/span&gt; a &amp;#39;&lt;span class="op"&gt;:&lt;/span&gt; vs) b &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; vs (a &lt;span class="op"&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="sourceCode" id="cb63"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb63-1"&gt;&lt;a href="#cb63-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb63-2"&gt;&lt;a href="#cb63-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb63-3"&gt;&lt;a href="#cb63-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EVar&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Index&lt;/span&gt; vs (n &lt;span class="op"&gt;:::&lt;/span&gt; t) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&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 ["x" ::: TInt, "y" ::: 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="sourceCode" id="cb64"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb64-1"&gt;&lt;a href="#cb64-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb64-2"&gt;&lt;a href="#cb64-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb64-3"&gt;&lt;a href="#cb64-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; [(&lt;span class="dt"&gt;Symbol&lt;/span&gt;, &lt;span class="dt"&gt;Ty&lt;/span&gt;)] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Ty&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Type&lt;/span&gt; &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb64-4"&gt;&lt;a href="#cb64-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EPrim&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Prim&lt;/span&gt; t &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; vs t&lt;/span&gt;
&lt;span id="cb64-5"&gt;&lt;a href="#cb64-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EVar&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Index&lt;/span&gt; vs (n &lt;span class="op"&gt;:::&lt;/span&gt; t) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; vs t&lt;/span&gt;
&lt;span id="cb64-6"&gt;&lt;a href="#cb64-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;ELambda&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;KnownSymbol&lt;/span&gt; n &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; (n &lt;span class="op"&gt;:::&lt;/span&gt; a &amp;#39;&lt;span class="op"&gt;:&lt;/span&gt; vs) b &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; vs (a &lt;span class="op"&gt;:-&amp;gt;&lt;/span&gt; b)&lt;/span&gt;
&lt;span id="cb64-7"&gt;&lt;a href="#cb64-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EApply&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; vs (a &lt;span class="op"&gt;:-&amp;gt;&lt;/span&gt; b) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; vs a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; vs b&lt;/span&gt;
&lt;span id="cb64-8"&gt;&lt;a href="#cb64-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EOp&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Op&lt;/span&gt; a b c &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; vs a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; vs b &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; vs c&lt;/span&gt;
&lt;span id="cb64-9"&gt;&lt;a href="#cb64-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;ERecord&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Rec&lt;/span&gt; (&lt;span class="dt"&gt;ExprField&lt;/span&gt; vs) as &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; vs (&lt;span class="dt"&gt;TRecord&lt;/span&gt; as)&lt;/span&gt;
&lt;span id="cb64-10"&gt;&lt;a href="#cb64-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EAccess&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;KnownSymbol&lt;/span&gt; l &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; vs (&lt;span class="dt"&gt;TRecord&lt;/span&gt; as) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Index&lt;/span&gt; as (l &lt;span class="op"&gt;:::&lt;/span&gt; a) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; vs a&lt;/span&gt;
&lt;span id="cb64-11"&gt;&lt;a href="#cb64-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EChoice&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;KnownSymbol&lt;/span&gt; l &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Index&lt;/span&gt; as (l &lt;span class="op"&gt;:::&lt;/span&gt; a) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; vs a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; vs (&lt;span class="dt"&gt;TSum&lt;/span&gt; as)&lt;/span&gt;
&lt;span id="cb64-12"&gt;&lt;a href="#cb64-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;ECase&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; vs (&lt;span class="dt"&gt;TSum&lt;/span&gt; as) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Rec&lt;/span&gt; (&lt;span class="dt"&gt;ExprHandler&lt;/span&gt; vs b) as &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&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="sourceCode" id="cb65"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb65-1"&gt;&lt;a href="#cb65-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb65-2"&gt;&lt;a href="#cb65-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb65-3"&gt;&lt;a href="#cb65-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;class&lt;/span&gt; &lt;span class="dt"&gt;ListIx&lt;/span&gt; (&lt;span class="ot"&gt;l ::&lt;/span&gt; &lt;span class="dt"&gt;Symbol&lt;/span&gt;) (&lt;span class="ot"&gt;xs ::&lt;/span&gt; [(&lt;span class="dt"&gt;Symbol&lt;/span&gt;, &lt;span class="dt"&gt;Ty&lt;/span&gt;)]) (&lt;span class="ot"&gt;a ::&lt;/span&gt; &lt;span class="dt"&gt;Ty&lt;/span&gt;) &lt;span class="op"&gt;|&lt;/span&gt; l xs &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; a &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb65-4"&gt;&lt;a href="#cb65-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;  listIx ::&lt;/span&gt; &lt;span class="dt"&gt;Index&lt;/span&gt; xs (l &lt;span class="op"&gt;:::&lt;/span&gt; a)&lt;/span&gt;
&lt;span id="cb65-5"&gt;&lt;a href="#cb65-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb65-6"&gt;&lt;a href="#cb65-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;instance&lt;/span&gt; &lt;span class="dt"&gt;ListIx&lt;/span&gt; l (l &lt;span class="op"&gt;:::&lt;/span&gt; a &amp;#39;&lt;span class="op"&gt;:&lt;/span&gt; xs) a &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb65-7"&gt;&lt;a href="#cb65-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  listIx &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;IZ&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb65-8"&gt;&lt;a href="#cb65-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb65-9"&gt;&lt;a href="#cb65-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;instance&lt;/span&gt; &lt;span class="ot"&gt;{-# OVERLAPPABLE #-}&lt;/span&gt; &lt;span class="dt"&gt;ListIx&lt;/span&gt; l xs a &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ListIx&lt;/span&gt; l (m &lt;span class="op"&gt;:::&lt;/span&gt; b &amp;#39;&lt;span class="op"&gt;:&lt;/span&gt; xs) a &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb65-10"&gt;&lt;a href="#cb65-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  listIx &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;IS&lt;/span&gt; (listIx &lt;span class="op"&gt;@&lt;/span&gt;l)&lt;/span&gt;
&lt;span id="cb65-11"&gt;&lt;a href="#cb65-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb65-12"&gt;&lt;a href="#cb65-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;eVar ::&lt;/span&gt; &lt;span class="kw"&gt;forall&lt;/span&gt; n &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ListIx&lt;/span&gt; n vs a &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; vs a&lt;/span&gt;
&lt;span id="cb65-13"&gt;&lt;a href="#cb65-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;eVar n &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;EVar&lt;/span&gt; (listIx &lt;span class="op"&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="sourceCode" id="cb66"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb66-1"&gt;&lt;a href="#cb66-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb66-2"&gt;&lt;a href="#cb66-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb66-3"&gt;&lt;a href="#cb66-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;eLambda ::&lt;/span&gt; &lt;span class="kw"&gt;forall&lt;/span&gt; n &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;KnownSymbol&lt;/span&gt; n &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; (n &lt;span class="op"&gt;:::&lt;/span&gt; a &amp;#39;&lt;span class="op"&gt;:&lt;/span&gt; vs) b &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; vs (a &lt;span class="op"&gt;:-&amp;gt;&lt;/span&gt; b)&lt;/span&gt;
&lt;span id="cb66-4"&gt;&lt;a href="#cb66-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;eLambda n &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;ELambda&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;n&lt;/span&gt;
&lt;span id="cb66-5"&gt;&lt;a href="#cb66-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb66-6"&gt;&lt;a href="#cb66-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;eField ::&lt;/span&gt; &lt;span class="kw"&gt;forall&lt;/span&gt; l &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;KnownSymbol&lt;/span&gt; l &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; vs a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ExprField&lt;/span&gt; vs (l &lt;span class="op"&gt;:::&lt;/span&gt; a)&lt;/span&gt;
&lt;span id="cb66-7"&gt;&lt;a href="#cb66-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;eField l &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;EField&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;l&lt;/span&gt;
&lt;span id="cb66-8"&gt;&lt;a href="#cb66-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb66-9"&gt;&lt;a href="#cb66-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;eAccess ::&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb66-10"&gt;&lt;a href="#cb66-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;forall&lt;/span&gt; l &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb66-11"&gt;&lt;a href="#cb66-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  (&lt;span class="dt"&gt;KnownSymbol&lt;/span&gt; l, &lt;span class="dt"&gt;ListIx&lt;/span&gt; l as a) &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb66-12"&gt;&lt;a href="#cb66-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;Expr&lt;/span&gt; vs (&lt;span class="dt"&gt;TRecord&lt;/span&gt; as) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb66-13"&gt;&lt;a href="#cb66-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;Expr&lt;/span&gt; vs a&lt;/span&gt;
&lt;span id="cb66-14"&gt;&lt;a href="#cb66-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;eAccess l e &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;EAccess&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;l e (listIx &lt;span class="op"&gt;@&lt;/span&gt;l)&lt;/span&gt;
&lt;span id="cb66-15"&gt;&lt;a href="#cb66-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb66-16"&gt;&lt;a href="#cb66-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;eChoice ::&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb66-17"&gt;&lt;a href="#cb66-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;forall&lt;/span&gt; l &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb66-18"&gt;&lt;a href="#cb66-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  (&lt;span class="dt"&gt;KnownSymbol&lt;/span&gt; l, &lt;span class="dt"&gt;ListIx&lt;/span&gt; l as a) &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb66-19"&gt;&lt;a href="#cb66-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;Expr&lt;/span&gt; vs a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb66-20"&gt;&lt;a href="#cb66-20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;Expr&lt;/span&gt; vs (&lt;span class="dt"&gt;TSum&lt;/span&gt; as)&lt;/span&gt;
&lt;span id="cb66-21"&gt;&lt;a href="#cb66-21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;eChoice l e &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;EChoice&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;l (listIx &lt;span class="op"&gt;@&lt;/span&gt;l) e&lt;/span&gt;
&lt;span id="cb66-22"&gt;&lt;a href="#cb66-22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb66-23"&gt;&lt;a href="#cb66-23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;eHandler ::&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb66-24"&gt;&lt;a href="#cb66-24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;forall&lt;/span&gt; n &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb66-25"&gt;&lt;a href="#cb66-25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;forall&lt;/span&gt; l &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb66-26"&gt;&lt;a href="#cb66-26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  (&lt;span class="dt"&gt;KnownSymbol&lt;/span&gt; n, &lt;span class="dt"&gt;KnownSymbol&lt;/span&gt; l) &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb66-27"&gt;&lt;a href="#cb66-27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;Expr&lt;/span&gt; (n &lt;span class="op"&gt;:::&lt;/span&gt; a &amp;#39;&lt;span class="op"&gt;:&lt;/span&gt; vs) b &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb66-28"&gt;&lt;a href="#cb66-28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;ExprHandler&lt;/span&gt; vs b (l &lt;span class="op"&gt;:::&lt;/span&gt; a)&lt;/span&gt;
&lt;span id="cb66-29"&gt;&lt;a href="#cb66-29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;eHandler n l &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;EHandler&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;n &lt;span class="op"&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="sourceCode" id="cb67"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb67-1"&gt;&lt;a href="#cb67-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb67-2"&gt;&lt;a href="#cb67-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb67-3"&gt;&lt;a href="#cb67-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;fifteen ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; &amp;#39;[] &lt;span class="dt"&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb67-4"&gt;&lt;a href="#cb67-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;fifteen &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb67-5"&gt;&lt;a href="#cb67-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EApply&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb67-6"&gt;&lt;a href="#cb67-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    (eLambda &lt;span class="st"&gt;&amp;quot;x&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;EOp&lt;/span&gt; &lt;span class="dt"&gt;OTimes&lt;/span&gt; (eVar &lt;span class="st"&gt;&amp;quot;x&amp;quot;&lt;/span&gt;) (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;3&lt;/span&gt;))))&lt;/span&gt;
&lt;span id="cb67-7"&gt;&lt;a href="#cb67-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;5&lt;/span&gt;))&lt;/span&gt;
&lt;span id="cb67-8"&gt;&lt;a href="#cb67-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb67-9"&gt;&lt;a href="#cb67-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;recordExample ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; &amp;#39;[] &lt;span class="dt"&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb67-10"&gt;&lt;a href="#cb67-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;recordExample &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb67-11"&gt;&lt;a href="#cb67-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EOp&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb67-12"&gt;&lt;a href="#cb67-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;OPlus&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb67-13"&gt;&lt;a href="#cb67-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ( eAccess&lt;/span&gt;
&lt;span id="cb67-14"&gt;&lt;a href="#cb67-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="st"&gt;&amp;quot;value&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb67-15"&gt;&lt;a href="#cb67-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ( &lt;span class="dt"&gt;ERecord&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb67-16"&gt;&lt;a href="#cb67-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            ( eField &lt;span class="st"&gt;&amp;quot;value&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;7&lt;/span&gt;))&lt;/span&gt;
&lt;span id="cb67-17"&gt;&lt;a href="#cb67-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; eField &lt;span class="st"&gt;&amp;quot;label&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PString&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;found&amp;quot;&lt;/span&gt;))&lt;/span&gt;
&lt;span id="cb67-18"&gt;&lt;a href="#cb67-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; &lt;span class="dt"&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb67-19"&gt;&lt;a href="#cb67-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;            )&lt;/span&gt;
&lt;span id="cb67-20"&gt;&lt;a href="#cb67-20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        )&lt;/span&gt;
&lt;span id="cb67-21"&gt;&lt;a href="#cb67-21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    )&lt;/span&gt;
&lt;span id="cb67-22"&gt;&lt;a href="#cb67-22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;))&lt;/span&gt;
&lt;span id="cb67-23"&gt;&lt;a href="#cb67-23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb67-24"&gt;&lt;a href="#cb67-24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;sumExample ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; &amp;#39;[] &lt;span class="dt"&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb67-25"&gt;&lt;a href="#cb67-25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;sumExample &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb67-26"&gt;&lt;a href="#cb67-26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;ECase&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb67-27"&gt;&lt;a href="#cb67-27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    (eChoice &lt;span class="st"&gt;&amp;quot;Found&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;7&lt;/span&gt;)))&lt;/span&gt;
&lt;span id="cb67-28"&gt;&lt;a href="#cb67-28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ( eHandler &lt;span class="st"&gt;&amp;quot;value&amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Found&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;EOp&lt;/span&gt; &lt;span class="dt"&gt;OPlus&lt;/span&gt; (eVar &lt;span class="st"&gt;&amp;quot;value&amp;quot;&lt;/span&gt;) (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;)))&lt;/span&gt;
&lt;span id="cb67-29"&gt;&lt;a href="#cb67-29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; eHandler &lt;span class="st"&gt;&amp;quot;message&amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Missing&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;0&lt;/span&gt;))&lt;/span&gt;
&lt;span id="cb67-30"&gt;&lt;a href="#cb67-30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; &lt;span class="dt"&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb67-31"&gt;&lt;a href="#cb67-31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    )&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id="what-we-gained"&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="sourceCode" id="cb68"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb68-1"&gt;&lt;a href="#cb68-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;:&lt;/span&gt;t (&lt;span class="dt"&gt;EVar&lt;/span&gt; &lt;span class="dt"&gt;IZ&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; &amp;#39;[] &lt;span class="dt"&gt;TInt&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb68-2"&gt;&lt;a href="#cb68-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;interactive&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;error&lt;/span&gt;&lt;span class="op"&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb68-3"&gt;&lt;a href="#cb68-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    • &lt;span class="dt"&gt;Couldn&amp;#39;t&lt;/span&gt; match &lt;span class="kw"&gt;type&lt;/span&gt;&lt;span class="op"&gt;:&lt;/span&gt; (n0 &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;) &lt;span class="op"&gt;:&lt;/span&gt; xs0&lt;/span&gt;
&lt;span id="cb68-4"&gt;&lt;a href="#cb68-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                     with&lt;span class="op"&gt;:&lt;/span&gt; &amp;#39;[]&lt;/span&gt;
&lt;span id="cb68-5"&gt;&lt;a href="#cb68-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;Expected&lt;/span&gt;&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;Index&lt;/span&gt; &amp;#39;[] (n0 &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb68-6"&gt;&lt;a href="#cb68-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;Actual&lt;/span&gt;&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;Index&lt;/span&gt; ((n0 &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;) &lt;span class="op"&gt;:&lt;/span&gt; xs0) (n0 &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb68-7"&gt;&lt;a href="#cb68-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb68-8"&gt;&lt;a href="#cb68-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;:&lt;/span&gt;t (&lt;span class="dt"&gt;EVar&lt;/span&gt; &lt;span class="dt"&gt;IZ&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; &amp;#39;[&lt;span class="st"&gt;&amp;quot;x&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TString&lt;/span&gt;] &lt;span class="dt"&gt;TInt&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb68-9"&gt;&lt;a href="#cb68-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;interactive&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;error&lt;/span&gt;&lt;span class="op"&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb68-10"&gt;&lt;a href="#cb68-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    • &lt;span class="dt"&gt;Couldn&amp;#39;t&lt;/span&gt; match &lt;span class="kw"&gt;type&lt;/span&gt; ‘&lt;span class="dt"&gt;TString&lt;/span&gt;’ with ‘&lt;span class="dt"&gt;TInt&lt;/span&gt;’&lt;/span&gt;
&lt;span id="cb68-11"&gt;&lt;a href="#cb68-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;Expected&lt;/span&gt;&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;Index&lt;/span&gt; &amp;#39;[&lt;span class="st"&gt;&amp;quot;x&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TString&lt;/span&gt;] (&lt;span class="st"&gt;&amp;quot;x&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb68-12"&gt;&lt;a href="#cb68-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;Actual&lt;/span&gt;&lt;span class="op"&gt;:&lt;/span&gt; &lt;span class="dt"&gt;Index&lt;/span&gt; &amp;#39;[&lt;span class="st"&gt;&amp;quot;x&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TString&lt;/span&gt;] (&lt;span class="st"&gt;&amp;quot;x&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TString&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb68-13"&gt;&lt;a href="#cb68-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb68-14"&gt;&lt;a href="#cb68-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;:&lt;/span&gt;t &lt;span class="dt"&gt;ECase&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb68-15"&gt;&lt;a href="#cb68-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      (&lt;span class="dt"&gt;EChoice&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;Found&amp;quot;&lt;/span&gt; &lt;span class="dt"&gt;IZ&lt;/span&gt; (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;7&lt;/span&gt;))&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; &amp;#39;[] (&lt;span class="dt"&gt;TSum&lt;/span&gt; &amp;#39;[&lt;span class="st"&gt;&amp;quot;Found&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;, &lt;span class="st"&gt;&amp;quot;Missing&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TString&lt;/span&gt;]))&lt;/span&gt;
&lt;span id="cb68-16"&gt;&lt;a href="#cb68-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      ( &lt;span class="dt"&gt;EHandler&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;value&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;Found&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;EOp&lt;/span&gt; &lt;span class="dt"&gt;OPlus&lt;/span&gt; (&lt;span class="dt"&gt;EVar&lt;/span&gt; (&lt;span class="dt"&gt;IS&lt;/span&gt; &lt;span class="dt"&gt;IZ&lt;/span&gt;)) (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;)))&lt;/span&gt;
&lt;span id="cb68-17"&gt;&lt;a href="#cb68-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; &lt;span class="dt"&gt;EHandler&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;message&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;Missing&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;EOp&lt;/span&gt; &lt;span class="dt"&gt;OPlus&lt;/span&gt; (&lt;span class="dt"&gt;EVar&lt;/span&gt; &lt;span class="dt"&gt;IZ&lt;/span&gt;) (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;)))&lt;/span&gt;
&lt;span id="cb68-18"&gt;&lt;a href="#cb68-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; &lt;span class="dt"&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb68-19"&gt;&lt;a href="#cb68-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      )&lt;/span&gt;
&lt;span id="cb68-20"&gt;&lt;a href="#cb68-20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;interactive&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;error&lt;/span&gt;&lt;span class="op"&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb68-21"&gt;&lt;a href="#cb68-21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    • &lt;span class="dt"&gt;Couldn&amp;#39;t&lt;/span&gt; match &lt;span class="kw"&gt;type&lt;/span&gt;&lt;span class="op"&gt;:&lt;/span&gt; (n0 &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;) &lt;span class="op"&gt;:&lt;/span&gt; xs0&lt;/span&gt;
&lt;span id="cb68-22"&gt;&lt;a href="#cb68-22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;                     with&lt;span class="op"&gt;:&lt;/span&gt; &amp;#39;[]&lt;/span&gt;
&lt;span id="cb68-23"&gt;&lt;a href="#cb68-23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;interactive&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;error&lt;/span&gt;&lt;span class="op"&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb68-24"&gt;&lt;a href="#cb68-24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    • &lt;span class="dt"&gt;Couldn&amp;#39;t&lt;/span&gt; match &lt;span class="kw"&gt;type&lt;/span&gt; ‘&lt;span class="dt"&gt;TString&lt;/span&gt;’ with ‘&lt;span class="dt"&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="sourceCode" id="cb69"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb69-1"&gt;&lt;a href="#cb69-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;:&lt;/span&gt;t (eVar &lt;span class="st"&gt;&amp;quot;missing&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; &amp;#39;[] &lt;span class="dt"&gt;TInt&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb69-2"&gt;&lt;a href="#cb69-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;interactive&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;error&lt;/span&gt;&lt;span class="op"&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb69-3"&gt;&lt;a href="#cb69-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    • &lt;span class="dt"&gt;No&lt;/span&gt; &lt;span class="kw"&gt;instance&lt;/span&gt; for ‘&lt;span class="dt"&gt;ListIx&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;missing&amp;quot;&lt;/span&gt; &amp;#39;[] &lt;span class="dt"&gt;TInt&lt;/span&gt;’&lt;/span&gt;
&lt;span id="cb69-4"&gt;&lt;a href="#cb69-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb69-5"&gt;&lt;a href="#cb69-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;:&lt;/span&gt;t (eVar &lt;span class="st"&gt;&amp;quot;x&amp;quot;&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; &amp;#39;[&lt;span class="st"&gt;&amp;quot;x&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TString&lt;/span&gt;] &lt;span class="dt"&gt;TInt&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb69-6"&gt;&lt;a href="#cb69-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;interactive&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;error&lt;/span&gt;&lt;span class="op"&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb69-7"&gt;&lt;a href="#cb69-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    • &lt;span class="dt"&gt;No&lt;/span&gt; &lt;span class="kw"&gt;instance&lt;/span&gt; for ‘&lt;span class="dt"&gt;ListIx&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;x&amp;quot;&lt;/span&gt; &amp;#39;[] &lt;span class="dt"&gt;TInt&lt;/span&gt;’&lt;/span&gt;
&lt;span id="cb69-8"&gt;&lt;a href="#cb69-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb69-9"&gt;&lt;a href="#cb69-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;:&lt;/span&gt;t &lt;span class="dt"&gt;ECase&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb69-10"&gt;&lt;a href="#cb69-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      (eChoice &lt;span class="st"&gt;&amp;quot;Found&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;7&lt;/span&gt;))&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; &amp;#39;[] (&lt;span class="dt"&gt;TSum&lt;/span&gt; &amp;#39;[&lt;span class="st"&gt;&amp;quot;Found&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;, &lt;span class="st"&gt;&amp;quot;Missing&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TString&lt;/span&gt;]))&lt;/span&gt;
&lt;span id="cb69-11"&gt;&lt;a href="#cb69-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      ( eHandler &lt;span class="st"&gt;&amp;quot;value&amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Found&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;EOp&lt;/span&gt; &lt;span class="dt"&gt;OPlus&lt;/span&gt; (eVar &lt;span class="st"&gt;&amp;quot;missing&amp;quot;&lt;/span&gt;) (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;)))&lt;/span&gt;
&lt;span id="cb69-12"&gt;&lt;a href="#cb69-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; eHandler &lt;span class="st"&gt;&amp;quot;message&amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Missing&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;EOp&lt;/span&gt; &lt;span class="dt"&gt;OPlus&lt;/span&gt; (eVar &lt;span class="st"&gt;&amp;quot;message&amp;quot;&lt;/span&gt;) (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;1&lt;/span&gt;)))&lt;/span&gt;
&lt;span id="cb69-13"&gt;&lt;a href="#cb69-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;          &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; &lt;span class="dt"&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb69-14"&gt;&lt;a href="#cb69-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      )&lt;/span&gt;
&lt;span id="cb69-15"&gt;&lt;a href="#cb69-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;interactive&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;error&lt;/span&gt;&lt;span class="op"&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb69-16"&gt;&lt;a href="#cb69-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    • &lt;span class="dt"&gt;No&lt;/span&gt; &lt;span class="kw"&gt;instance&lt;/span&gt; for ‘&lt;span class="dt"&gt;ListIx&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;missing&amp;quot;&lt;/span&gt; &amp;#39;[] &lt;span class="dt"&gt;TInt&lt;/span&gt;’&lt;/span&gt;
&lt;span id="cb69-17"&gt;&lt;a href="#cb69-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;interactive&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;error&lt;/span&gt;&lt;span class="op"&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb69-18"&gt;&lt;a href="#cb69-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    • &lt;span class="dt"&gt;No&lt;/span&gt; &lt;span class="kw"&gt;instance&lt;/span&gt; for ‘&lt;span class="dt"&gt;ListIx&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;message&amp;quot;&lt;/span&gt; &amp;#39;[] &lt;span class="dt"&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 href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"&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="https://hackage.haskell.org/package/vinyl/docs/Data-Vinyl-Derived.html#t:FieldType"&gt;instance&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Note that this is sometimes done using straight &lt;a
href="https://en.wikipedia.org/wiki/De_Bruijn_index"&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="eval-with-a-typed-environment"&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 ["x" ::: TInt, "y" ::: 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="sourceCode" id="cb70"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb70-1"&gt;&lt;a href="#cb70-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb70-2"&gt;&lt;a href="#cb70-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb70-3"&gt;&lt;a href="#cb70-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;EValueField&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; (&lt;span class="dt"&gt;Symbol&lt;/span&gt;, &lt;span class="dt"&gt;Ty&lt;/span&gt;) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Type&lt;/span&gt; &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb70-4"&gt;&lt;a href="#cb70-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EVField&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;EValue&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EValueField&lt;/span&gt; &amp;#39;(l, a)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="sourceCode" id="cb71"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb71-1"&gt;&lt;a href="#cb71-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;:&lt;/span&gt;t (&lt;span class="dt"&gt;EVField&lt;/span&gt; (&lt;span class="dt"&gt;EVInt&lt;/span&gt; &lt;span class="dv"&gt;3&lt;/span&gt;) &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; &lt;span class="dt"&gt;EVField&lt;/span&gt; (&lt;span class="dt"&gt;EVBool&lt;/span&gt; &lt;span class="dt"&gt;True&lt;/span&gt;) &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; &lt;span class="dt"&gt;RNil&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Rec&lt;/span&gt; &lt;span class="dt"&gt;EValueField&lt;/span&gt; [&lt;span class="st"&gt;&amp;quot;x&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;, &lt;span class="st"&gt;&amp;quot;y&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TBool&lt;/span&gt;])&lt;/span&gt;
&lt;span id="cb71-2"&gt;&lt;a href="#cb71-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;Rec&lt;/span&gt; &lt;span class="dt"&gt;EValueField&lt;/span&gt; [&lt;span class="st"&gt;&amp;quot;x&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;, &lt;span class="st"&gt;&amp;quot;y&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; &lt;span class="dt"&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="sourceCode" id="cb72"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb72-1"&gt;&lt;a href="#cb72-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb72-2"&gt;&lt;a href="#cb72-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb72-3"&gt;&lt;a href="#cb72-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;EValue&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Ty&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Type&lt;/span&gt; &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb72-4"&gt;&lt;a href="#cb72-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EVInt&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EValue&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb72-5"&gt;&lt;a href="#cb72-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EVBool&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EValue&lt;/span&gt; &lt;span class="dt"&gt;TBool&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb72-6"&gt;&lt;a href="#cb72-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EVString&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EValue&lt;/span&gt; &lt;span class="dt"&gt;TString&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb72-7"&gt;&lt;a href="#cb72-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EVRecord&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Rec&lt;/span&gt; &lt;span class="dt"&gt;EValueField&lt;/span&gt; as &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EValue&lt;/span&gt; (&lt;span class="dt"&gt;TRecord&lt;/span&gt; as)&lt;/span&gt;
&lt;span id="cb72-8"&gt;&lt;a href="#cb72-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EVSum&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;Index&lt;/span&gt; as (l &lt;span class="op"&gt;:::&lt;/span&gt; a) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EValue&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EValue&lt;/span&gt; (&lt;span class="dt"&gt;TSum&lt;/span&gt; as)&lt;/span&gt;
&lt;span id="cb72-9"&gt;&lt;a href="#cb72-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EVFun&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; (&lt;span class="dt"&gt;EValue&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EValue&lt;/span&gt; b) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EValue&lt;/span&gt; (a &lt;span class="op"&gt;:-&amp;gt;&lt;/span&gt; b)&lt;/span&gt;
&lt;span id="cb72-10"&gt;&lt;a href="#cb72-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb72-11"&gt;&lt;a href="#cb72-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;eval ::&lt;/span&gt; &lt;span class="dt"&gt;Rec&lt;/span&gt; &lt;span class="dt"&gt;EValueField&lt;/span&gt; vs &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; vs t &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EValue&lt;/span&gt; t&lt;/span&gt;
&lt;span id="cb72-12"&gt;&lt;a href="#cb72-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;eval env &lt;span class="ot"&gt;=&lt;/span&gt; \&lt;span class="kw"&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb72-13"&gt;&lt;a href="#cb72-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; n) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EVInt&lt;/span&gt; n&lt;/span&gt;
&lt;span id="cb72-14"&gt;&lt;a href="#cb72-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PBool&lt;/span&gt; b) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EVBool&lt;/span&gt; b&lt;/span&gt;
&lt;span id="cb72-15"&gt;&lt;a href="#cb72-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PString&lt;/span&gt; s) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EVString&lt;/span&gt; s&lt;/span&gt;
&lt;span id="cb72-16"&gt;&lt;a href="#cb72-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EVar&lt;/span&gt; i &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;case&lt;/span&gt; indexRec i env &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb72-17"&gt;&lt;a href="#cb72-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;EVField&lt;/span&gt; v &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; v&lt;/span&gt;
&lt;span id="cb72-18"&gt;&lt;a href="#cb72-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;ELambda&lt;/span&gt; body &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb72-19"&gt;&lt;a href="#cb72-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;EVFun&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; \x &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; eval (&lt;span class="dt"&gt;EVField&lt;/span&gt; x &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; env) body&lt;/span&gt;
&lt;span id="cb72-20"&gt;&lt;a href="#cb72-20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EApply&lt;/span&gt; f x &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;case&lt;/span&gt; eval env f &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb72-21"&gt;&lt;a href="#cb72-21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;EVFun&lt;/span&gt; g &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; g (eval env x)&lt;/span&gt;
&lt;span id="cb72-22"&gt;&lt;a href="#cb72-22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EOp&lt;/span&gt; o x y &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;case&lt;/span&gt; (o, eval env x, eval env y) &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb72-23"&gt;&lt;a href="#cb72-23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    (&lt;span class="dt"&gt;OPlus&lt;/span&gt;, &lt;span class="dt"&gt;EVInt&lt;/span&gt; a, &lt;span class="dt"&gt;EVInt&lt;/span&gt; b) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EVInt&lt;/span&gt; (a &lt;span class="op"&gt;+&lt;/span&gt; b)&lt;/span&gt;
&lt;span id="cb72-24"&gt;&lt;a href="#cb72-24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    (&lt;span class="dt"&gt;OTimes&lt;/span&gt;, &lt;span class="dt"&gt;EVInt&lt;/span&gt; a, &lt;span class="dt"&gt;EVInt&lt;/span&gt; b) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EVInt&lt;/span&gt; (a &lt;span class="op"&gt;*&lt;/span&gt; b)&lt;/span&gt;
&lt;span id="cb72-25"&gt;&lt;a href="#cb72-25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    (&lt;span class="dt"&gt;OLte&lt;/span&gt;, &lt;span class="dt"&gt;EVInt&lt;/span&gt; a, &lt;span class="dt"&gt;EVInt&lt;/span&gt; b) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EVBool&lt;/span&gt; (a &lt;span class="op"&gt;&amp;lt;=&lt;/span&gt; b)&lt;/span&gt;
&lt;span id="cb72-26"&gt;&lt;a href="#cb72-26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    (&lt;span class="dt"&gt;OAnd&lt;/span&gt;, &lt;span class="dt"&gt;EVBool&lt;/span&gt; a, &lt;span class="dt"&gt;EVBool&lt;/span&gt; b) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EVBool&lt;/span&gt; (a &lt;span class="op"&gt;&amp;amp;&amp;amp;&lt;/span&gt; b)&lt;/span&gt;
&lt;span id="cb72-27"&gt;&lt;a href="#cb72-27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;ERecord&lt;/span&gt; xs &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb72-28"&gt;&lt;a href="#cb72-28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;EVRecord&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; mapRec (\(&lt;span class="dt"&gt;EField&lt;/span&gt; x) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EVField&lt;/span&gt; (eval env x)) xs&lt;/span&gt;
&lt;span id="cb72-29"&gt;&lt;a href="#cb72-29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EAccess&lt;/span&gt; e i &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;case&lt;/span&gt; eval env e &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb72-30"&gt;&lt;a href="#cb72-30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;EVRecord&lt;/span&gt; xs &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;case&lt;/span&gt; indexRec i xs &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb72-31"&gt;&lt;a href="#cb72-31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;EVField&lt;/span&gt; v &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; v&lt;/span&gt;
&lt;span id="cb72-32"&gt;&lt;a href="#cb72-32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EChoice&lt;/span&gt; i x &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;EVSum&lt;/span&gt; i (eval env x)&lt;/span&gt;
&lt;span id="cb72-33"&gt;&lt;a href="#cb72-33" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;ECase&lt;/span&gt; x hs &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;case&lt;/span&gt; eval env x &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb72-34"&gt;&lt;a href="#cb72-34" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;EVSum&lt;/span&gt; i y &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;case&lt;/span&gt; indexRec i hs &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb72-35"&gt;&lt;a href="#cb72-35" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;EHandler&lt;/span&gt; h &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; eval (&lt;span class="dt"&gt;EVField&lt;/span&gt; y &lt;span class="op"&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="sourceCode" id="cb73"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb73-1"&gt;&lt;a href="#cb73-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb73-2"&gt;&lt;a href="#cb73-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb73-3"&gt;&lt;a href="#cb73-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;plusThree ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; &amp;#39;[] (&lt;span class="dt"&gt;TInt&lt;/span&gt; &lt;span class="op"&gt;:-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;TInt&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb73-4"&gt;&lt;a href="#cb73-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;plusThree &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb73-5"&gt;&lt;a href="#cb73-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  eLambda &lt;span class="st"&gt;&amp;quot;x&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;EOp&lt;/span&gt; &lt;span class="dt"&gt;OPlus&lt;/span&gt; (eVar &lt;span class="st"&gt;&amp;quot;x&amp;quot;&lt;/span&gt;) (&lt;span class="dt"&gt;EPrim&lt;/span&gt; (&lt;span class="dt"&gt;PInt&lt;/span&gt; &lt;span class="dv"&gt;3&lt;/span&gt;)))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="sourceCode" id="cb74"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb74-1"&gt;&lt;a href="#cb74-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;case&lt;/span&gt; eval &lt;span class="dt"&gt;RNil&lt;/span&gt; plusThree &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb74-2"&gt;&lt;a href="#cb74-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;EVFun&lt;/span&gt; f &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;case&lt;/span&gt; f (&lt;span class="dt"&gt;EVInt&lt;/span&gt; &lt;span class="dv"&gt;4&lt;/span&gt;) &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb74-3"&gt;&lt;a href="#cb74-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;EVInt&lt;/span&gt; x &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;print&lt;/span&gt; x&lt;/span&gt;
&lt;span id="cb74-4"&gt;&lt;a href="#cb74-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dv"&gt;7&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id="pretty-printing-scoped-expressions"&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="sourceCode" id="cb75"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb75-1"&gt;&lt;a href="#cb75-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb75-2"&gt;&lt;a href="#cb75-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb75-3"&gt;&lt;a href="#cb75-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;NameField&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; (&lt;span class="dt"&gt;Symbol&lt;/span&gt;, &lt;span class="dt"&gt;Ty&lt;/span&gt;) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Type&lt;/span&gt; &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb75-4"&gt;&lt;a href="#cb75-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;NameField&lt;/span&gt;&lt;span class="ot"&gt; ::&lt;/span&gt; &lt;span class="dt"&gt;KnownSymbol&lt;/span&gt; l &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;NameField&lt;/span&gt; (l &lt;span class="op"&gt;:::&lt;/span&gt; a)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="sourceCode" id="cb76"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb76-1"&gt;&lt;a href="#cb76-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="op"&gt;:&lt;/span&gt;t &lt;span class="dt"&gt;NameField&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;hello&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; &lt;span class="dt"&gt;NameField&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;world&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; &lt;span class="dt"&gt;RNil&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb76-2"&gt;&lt;a href="#cb76-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="dt"&gt;Rec&lt;/span&gt; &lt;span class="dt"&gt;NameField&lt;/span&gt; [&lt;span class="st"&gt;&amp;quot;hello&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; a, &lt;span class="st"&gt;&amp;quot;world&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;:::&lt;/span&gt; b]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="sourceCode" id="cb77"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb77-1"&gt;&lt;a href="#cb77-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&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="cb77-2"&gt;&lt;a href="#cb77-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb77-3"&gt;&lt;a href="#cb77-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;ppPrim ::&lt;/span&gt; &lt;span class="dt"&gt;Prim&lt;/span&gt; t &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id="cb77-4"&gt;&lt;a href="#cb77-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ppPrim &lt;span class="ot"&gt;=&lt;/span&gt; \&lt;span class="kw"&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb77-5"&gt;&lt;a href="#cb77-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;PInt&lt;/span&gt; n &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; PP.pretty n&lt;/span&gt;
&lt;span id="cb77-6"&gt;&lt;a href="#cb77-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;PBool&lt;/span&gt; b &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;if&lt;/span&gt; b &lt;span class="kw"&gt;then&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;true&amp;quot;&lt;/span&gt; &lt;span class="kw"&gt;else&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb77-7"&gt;&lt;a href="#cb77-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;PString&lt;/span&gt; s &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; PP.pretty (&lt;span class="fu"&gt;show&lt;/span&gt; s)&lt;/span&gt;
&lt;span id="cb77-8"&gt;&lt;a href="#cb77-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb77-9"&gt;&lt;a href="#cb77-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;ppOp ::&lt;/span&gt; &lt;span class="dt"&gt;Op&lt;/span&gt; a b c &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id="cb77-10"&gt;&lt;a href="#cb77-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ppOp &lt;span class="ot"&gt;=&lt;/span&gt; \&lt;span class="kw"&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb77-11"&gt;&lt;a href="#cb77-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;OPlus&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;+&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb77-12"&gt;&lt;a href="#cb77-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;OTimes&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;*&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb77-13"&gt;&lt;a href="#cb77-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;OLte&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;&amp;lt;=&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb77-14"&gt;&lt;a href="#cb77-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;OAnd&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;&amp;amp;&amp;amp;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb77-15"&gt;&lt;a href="#cb77-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb77-16"&gt;&lt;a href="#cb77-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;ppFields ::&lt;/span&gt; &lt;span class="dt"&gt;Rec&lt;/span&gt; &lt;span class="dt"&gt;NameField&lt;/span&gt; vs &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Rec&lt;/span&gt; (&lt;span class="dt"&gt;ExprField&lt;/span&gt; vs) xs &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; [&lt;span class="dt"&gt;PP.Doc&lt;/span&gt; ann]&lt;/span&gt;
&lt;span id="cb77-17"&gt;&lt;a href="#cb77-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ppFields _ &lt;span class="dt"&gt;RNil&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; []&lt;/span&gt;
&lt;span id="cb77-18"&gt;&lt;a href="#cb77-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ppFields names (&lt;span class="dt"&gt;EField&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;l x &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; xs) &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb77-19"&gt;&lt;a href="#cb77-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  (PP.pretty (symbolVal (&lt;span class="dt"&gt;Proxy&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;l)) &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;=&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr names &lt;span class="dt"&gt;False&lt;/span&gt; x) &lt;span class="op"&gt;:&lt;/span&gt; ppFields names xs&lt;/span&gt;
&lt;span id="cb77-20"&gt;&lt;a href="#cb77-20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb77-21"&gt;&lt;a href="#cb77-21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;ppHandlers ::&lt;/span&gt; &lt;span class="dt"&gt;Rec&lt;/span&gt; &lt;span class="dt"&gt;NameField&lt;/span&gt; vs &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Rec&lt;/span&gt; (&lt;span class="dt"&gt;ExprHandler&lt;/span&gt; vs b) xs &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; [&lt;span class="dt"&gt;PP.Doc&lt;/span&gt; ann]&lt;/span&gt;
&lt;span id="cb77-22"&gt;&lt;a href="#cb77-22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ppHandlers _ &lt;span class="dt"&gt;RNil&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; []&lt;/span&gt;
&lt;span id="cb77-23"&gt;&lt;a href="#cb77-23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ppHandlers names (&lt;span class="dt"&gt;EHandler&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;n &lt;span class="op"&gt;@&lt;/span&gt;l body &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; xs) &lt;span class="ot"&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb77-24"&gt;&lt;a href="#cb77-24" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  ( PP.pretty (symbolVal (&lt;span class="dt"&gt;Proxy&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;l))&lt;/span&gt;
&lt;span id="cb77-25"&gt;&lt;a href="#cb77-25" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; PP.pretty (symbolVal (&lt;span class="dt"&gt;Proxy&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;n))&lt;/span&gt;
&lt;span id="cb77-26"&gt;&lt;a href="#cb77-26" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;-&amp;gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb77-27"&gt;&lt;a href="#cb77-27" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr (&lt;span class="dt"&gt;NameField&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;n &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; names) &lt;span class="dt"&gt;False&lt;/span&gt; body&lt;/span&gt;
&lt;span id="cb77-28"&gt;&lt;a href="#cb77-28" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  )&lt;/span&gt;
&lt;span id="cb77-29"&gt;&lt;a href="#cb77-29" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="op"&gt;:&lt;/span&gt; ppHandlers names xs&lt;/span&gt;
&lt;span id="cb77-30"&gt;&lt;a href="#cb77-30" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb77-31"&gt;&lt;a href="#cb77-31" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;ppExpr ::&lt;/span&gt; &lt;span class="dt"&gt;Rec&lt;/span&gt; &lt;span class="dt"&gt;NameField&lt;/span&gt; vs &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; vs t &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id="cb77-32"&gt;&lt;a href="#cb77-32" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ppExpr names paren &lt;span class="ot"&gt;=&lt;/span&gt; \&lt;span class="kw"&gt;case&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb77-33"&gt;&lt;a href="#cb77-33" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EPrim&lt;/span&gt; p &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; ppPrim p&lt;/span&gt;
&lt;span id="cb77-34"&gt;&lt;a href="#cb77-34" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EVar&lt;/span&gt; i &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;case&lt;/span&gt; indexRec i names &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb77-35"&gt;&lt;a href="#cb77-35" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;NameField&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;n &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; PP.pretty (symbolVal (&lt;span class="dt"&gt;Proxy&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;n))&lt;/span&gt;
&lt;span id="cb77-36"&gt;&lt;a href="#cb77-36" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;ELambda&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;n body &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb77-37"&gt;&lt;a href="#cb77-37" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    wrap &lt;span class="op"&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb77-38"&gt;&lt;a href="#cb77-38" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="st"&gt;&amp;quot;\\&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; PP.pretty (symbolVal (&lt;span class="dt"&gt;Proxy&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;n))&lt;/span&gt;
&lt;span id="cb77-39"&gt;&lt;a href="#cb77-39" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;-&amp;gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb77-40"&gt;&lt;a href="#cb77-40" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr (&lt;span class="dt"&gt;NameField&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;n &lt;span class="op"&gt;:&amp;amp;&lt;/span&gt; names) &lt;span class="dt"&gt;False&lt;/span&gt; body&lt;/span&gt;
&lt;span id="cb77-41"&gt;&lt;a href="#cb77-41" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EApply&lt;/span&gt; f x &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb77-42"&gt;&lt;a href="#cb77-42" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    wrap &lt;span class="op"&gt;$&lt;/span&gt; ppExpr names &lt;span class="dt"&gt;True&lt;/span&gt; f &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr names &lt;span class="dt"&gt;True&lt;/span&gt; x&lt;/span&gt;
&lt;span id="cb77-43"&gt;&lt;a href="#cb77-43" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EOp&lt;/span&gt; o x y &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb77-44"&gt;&lt;a href="#cb77-44" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    wrap &lt;span class="op"&gt;$&lt;/span&gt; ppExpr names &lt;span class="dt"&gt;True&lt;/span&gt; x &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppOp o &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr names &lt;span class="dt"&gt;True&lt;/span&gt; y&lt;/span&gt;
&lt;span id="cb77-45"&gt;&lt;a href="#cb77-45" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;ERecord&lt;/span&gt; xs &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb77-46"&gt;&lt;a href="#cb77-46" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    PP.encloseSep &lt;span class="st"&gt;&amp;quot;{ &amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot; }&amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;, &amp;quot;&lt;/span&gt; (ppFields names xs)&lt;/span&gt;
&lt;span id="cb77-47"&gt;&lt;a href="#cb77-47" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EAccess&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;l e _ &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb77-48"&gt;&lt;a href="#cb77-48" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ppExpr names &lt;span class="dt"&gt;True&lt;/span&gt; e &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;.&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;&amp;gt;&lt;/span&gt; PP.pretty (symbolVal (&lt;span class="dt"&gt;Proxy&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;l))&lt;/span&gt;
&lt;span id="cb77-49"&gt;&lt;a href="#cb77-49" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;EChoice&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;l _ x &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb77-50"&gt;&lt;a href="#cb77-50" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    wrap &lt;span class="op"&gt;$&lt;/span&gt; PP.pretty (symbolVal (&lt;span class="dt"&gt;Proxy&lt;/span&gt; &lt;span class="op"&gt;@&lt;/span&gt;l)) &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr names &lt;span class="dt"&gt;True&lt;/span&gt; x&lt;/span&gt;
&lt;span id="cb77-51"&gt;&lt;a href="#cb77-51" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;ECase&lt;/span&gt; x hs &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb77-52"&gt;&lt;a href="#cb77-52" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    wrap &lt;span class="op"&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb77-53"&gt;&lt;a href="#cb77-53" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      PP.sep&lt;/span&gt;
&lt;span id="cb77-54"&gt;&lt;a href="#cb77-54" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        [ &lt;span class="st"&gt;&amp;quot;case&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; ppExpr names &lt;span class="dt"&gt;False&lt;/span&gt; x &lt;span class="op"&gt;&amp;lt;+&amp;gt;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;of&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb77-55"&gt;&lt;a href="#cb77-55" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        , PP.encloseSep &lt;span class="st"&gt;&amp;quot;{ &amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot; }&amp;quot;&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;; &amp;quot;&lt;/span&gt; (ppHandlers names hs)&lt;/span&gt;
&lt;span id="cb77-56"&gt;&lt;a href="#cb77-56" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        ]&lt;/span&gt;
&lt;span id="cb77-57"&gt;&lt;a href="#cb77-57" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb77-58"&gt;&lt;a href="#cb77-58" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    wrap&lt;/span&gt;
&lt;span id="cb77-59"&gt;&lt;a href="#cb77-59" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="op"&gt;|&lt;/span&gt; paren &lt;span class="ot"&gt;=&lt;/span&gt; PP.parens&lt;/span&gt;
&lt;span id="cb77-60"&gt;&lt;a href="#cb77-60" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="fu"&gt;otherwise&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;id&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb77-61"&gt;&lt;a href="#cb77-61" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb77-62"&gt;&lt;a href="#cb77-62" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;prettyExpr ::&lt;/span&gt; &lt;span class="dt"&gt;Expr&lt;/span&gt; &amp;#39;[] t &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;PP.Doc&lt;/span&gt; ann&lt;/span&gt;
&lt;span id="cb77-63"&gt;&lt;a href="#cb77-63" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;prettyExpr &lt;span class="ot"&gt;=&lt;/span&gt; ppExpr &lt;span class="dt"&gt;RNil&lt;/span&gt; &lt;span class="dt"&gt;False&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="sourceCode" id="cb78"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb78-1"&gt;&lt;a href="#cb78-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;ghci&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; prettyExpr fifteen&lt;/span&gt;
&lt;span id="cb78-2"&gt;&lt;a href="#cb78-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;(\x &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; x &lt;span class="op"&gt;*&lt;/span&gt; &lt;span class="dv"&gt;3&lt;/span&gt;) &lt;span class="dv"&gt;5&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id="the-next-step"&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="https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/"&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="a-note-on-ai-coding"&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="special-thanks"&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="https://www.patreon.com/justinle/overview"&gt;patreon&lt;/a&gt;, Josh Vera! :)&lt;/p&gt;
&lt;section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn1"&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 href="#fnref1" class="footnote-back"
role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description><author>Justin Le</author><category>Haskell</category><guid isPermaLink="true">https://blog.jle.im/entry/extreme-haskell-typed-expression-edsls-1.html</guid><pubDate>Tue,  7 Jul 2026 17:11:34 UTC</pubDate><creator>Justin Le</creator><subject>Haskell</subject><date>2026-07-07</date></item><item><title>"Five-Point Haskell": Total Depravity (and Defensive Typing)</title><link>https://blog.jle.im/entry/five-point-haskell-part-1-total-depravity.html</link><description>&lt;p&gt;I have thought about distilling the principles by which I program Haskell,
and how I’ve been able to steer long-lived projects over years of growth,
refactorings, and changes in demands. I find myself coming back to a few
distinct and helpful “points” (“doctrines”, if you may allow me to say) that
have yet to lead me astray.&lt;/p&gt;
&lt;p&gt;With a new age of software development coming, what does it even mean to
write good, robust, correct code? It is long overdue to clarify the mindset we
use to define “good” coding principles.&lt;/p&gt;
&lt;p&gt;In this series, &lt;em&gt;&lt;a
href="https://blog.jle.im/entries/series/+five-point-haskell.html"&gt;Five-Point
Haskell&lt;/a&gt;&lt;/em&gt;, I’ll set out to establish a five-point framework for typed
functional programming (and Haskell-derived) design that aims to produce code
that is maintainable, correct, long-lasting, extensible, and beautiful to write
and work with. We’ll reference real-world case studies with actual examples when
we can, and also attempt to dispel thought-leader sound bites that have become
all too popular on Twitter (“heresies”, so to speak).&lt;/p&gt;
&lt;p&gt;Let’s jump right into point 1: the doctrine of &lt;strong&gt;Total
Depravity&lt;/strong&gt;, and why Haskell is perfectly primed to make living with it
as frictionless as possible.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Total Depravity: If your code’s correctness depends on keeping complicated
interconnected structure in your head, a devastating incident is not a matter of
&lt;em&gt;if&lt;/em&gt; but &lt;em&gt;when&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Therefore, delegate these concerns to tooling and a sufficiently powerful
compiler, use types to guard against errors, and free yourself to only mentally
track the actual important things.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="mix-ups-are-inevitable"&gt;Mix-ups Are Inevitable&lt;/h2&gt;
&lt;p&gt;Think about the stereotype of a “brilliant programmer” that an inexperienced
programmer has in their mind — someone who can hold every detail of a complex
system in their head, every intricate connection and relationship between each
component. There’s the classic &lt;a
href="https://www.monkeyuser.com/2018/focus/"&gt;Monkey User Comic&lt;/a&gt; that
valorizes this ideal.&lt;/p&gt;
&lt;figure&gt;
&lt;img src="/img/entries/five-point-haskell/79-focus.png"
title="Monkey User --- Focus" style="width:50%;height:auto;"
alt="Monkey User — Focus" /&gt;
&lt;figcaption aria-hidden="true"&gt;Monkey User — Focus&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The 10x developer is one who can carry the state and interconnectedness of an
entire system in their brain, and the bigger the state they can carry, the more
10x they are.&lt;/p&gt;
&lt;p&gt;This is the myth of the hero programmer. Did you have a bug? Well, you just
need to upgrade your mental awareness and your context window. You just need to
be better and better at keeping more in your mind.&lt;/p&gt;
&lt;p&gt;Actually &lt;em&gt;addressing&lt;/em&gt; these issues in most languages requires a lot of
overhead and clunkiness. But luckily we’re in Haskell.&lt;/p&gt;
&lt;h3 id="explicit-tags"&gt;Explicit Tags&lt;/h3&gt;
&lt;p&gt;The &lt;a
href="https://www.atlassian.com/blog/atlassian-engineering/post-incident-review-april-2022-outage"&gt;2022
Atlassian Outage&lt;/a&gt;, in part, was the result of passing the wrong type of ID.
The operators were intended to pass &lt;em&gt;App&lt;/em&gt; IDs, but instead passed
&lt;em&gt;Site&lt;/em&gt; IDs, and the errors cascaded from there. It goes without saying
that if you have a bunch of “naked” IDs, then mixing them up is eventually going
to backfire on you.&lt;/p&gt;
&lt;div class="sourceCode" id="cb1"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb1-1"&gt;&lt;a href="#cb1-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;Id&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Id&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-2"&gt;&lt;a href="#cb1-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb1-3"&gt;&lt;a href="#cb1-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; &lt;span class="dt"&gt;SiteId&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Id&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-4"&gt;&lt;a href="#cb1-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; &lt;span class="dt"&gt;AppId&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Id&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-5"&gt;&lt;a href="#cb1-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb1-6"&gt;&lt;a href="#cb1-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;getApps ::&lt;/span&gt; &lt;span class="dt"&gt;SiteId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; [&lt;span class="dt"&gt;AppId&lt;/span&gt;]&lt;/span&gt;
&lt;span id="cb1-7"&gt;&lt;a href="#cb1-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;deleteSite ::&lt;/span&gt; &lt;span class="dt"&gt;SiteId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="cb1-8"&gt;&lt;a href="#cb1-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;deleteApp ::&lt;/span&gt; &lt;span class="dt"&gt;AppId&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is convenient because you get functions for all IDs without any extra
work. Let’s say you want to serialize/print or deserialize/read these IDs — it
can be helpful to give them all the same type so that you can write this logic
in one place.&lt;/p&gt;
&lt;div class="sourceCode" id="cb2"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb2-1"&gt;&lt;a href="#cb2-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;instance&lt;/span&gt; &lt;span class="dt"&gt;ToJSON&lt;/span&gt; &lt;span class="dt"&gt;Id&lt;/span&gt; &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-2"&gt;&lt;a href="#cb2-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  toJSON (&lt;span class="dt"&gt;Id&lt;/span&gt; x) &lt;span class="ot"&gt;=&lt;/span&gt; object [ &lt;span class="st"&gt;&amp;quot;id&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;.=&lt;/span&gt; x ]&lt;/span&gt;
&lt;span id="cb2-3"&gt;&lt;a href="#cb2-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb2-4"&gt;&lt;a href="#cb2-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;instance&lt;/span&gt; &lt;span class="dt"&gt;FromJSON&lt;/span&gt; &lt;span class="dt"&gt;Id&lt;/span&gt; &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-5"&gt;&lt;a href="#cb2-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  parseJSON &lt;span class="ot"&gt;=&lt;/span&gt; withObject &lt;span class="st"&gt;&amp;quot;Id&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; \v &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb2-6"&gt;&lt;a href="#cb2-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Id&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;$&amp;gt;&lt;/span&gt; (v &lt;span class="op"&gt;.:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Convenient and effective, as long as you never accidentally use a
&lt;code&gt;SiteId&lt;/code&gt; as an &lt;code&gt;AppId&lt;/code&gt; or vice versa. And this is a very
easy delusion to fall into, if you don’t believe in total depravity. However,
sooner or later (maybe in a week, maybe in a year, maybe after you onboard that
new team member)…someone is going to accidentally pass a site ID where an app ID
is expected.&lt;/p&gt;
&lt;div class="sourceCode" id="cb3"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb3-1"&gt;&lt;a href="#cb3-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;main ::&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="cb3-2"&gt;&lt;a href="#cb3-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;main &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb3-3"&gt;&lt;a href="#cb3-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;let&lt;/span&gt; targetSites &lt;span class="ot"&gt;=&lt;/span&gt; [&lt;span class="dt"&gt;Id&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;abc&amp;quot;&lt;/span&gt;, &lt;span class="dt"&gt;Id&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;def&amp;quot;&lt;/span&gt;]&lt;/span&gt;
&lt;span id="cb3-4"&gt;&lt;a href="#cb3-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="fu"&gt;mapM_&lt;/span&gt; deleteApp targetSites&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And at that point it’s all over.&lt;/p&gt;
&lt;p&gt;Knowing this can happen, we can add a simple newtype wrapper so that
accidentally using the wrong ID is a compile error:&lt;/p&gt;
&lt;div class="sourceCode" id="cb4"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb4-1"&gt;&lt;a href="#cb4-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;SiteId&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;SiteId&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb4-2"&gt;&lt;a href="#cb4-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;AppId&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;AppId&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And now such a mis-call will never compile! Congratulations!&lt;/p&gt;
&lt;p&gt;We do have a downside now: we can no longer write code polymorphic over IDs
when we want to. In the untagged situation, we could &lt;em&gt;only&lt;/em&gt; write
polymorphic code, and in the new situation we can &lt;em&gt;only&lt;/em&gt; write code for
one ID type.&lt;/p&gt;
&lt;div class="sourceCode" id="cb5"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb5-1"&gt;&lt;a href="#cb5-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;instance&lt;/span&gt; &lt;span class="dt"&gt;FromJSON&lt;/span&gt; &lt;span class="dt"&gt;SiteId&lt;/span&gt; &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-2"&gt;&lt;a href="#cb5-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  parseJSON &lt;span class="ot"&gt;=&lt;/span&gt; withObject &lt;span class="st"&gt;&amp;quot;Id&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; \v &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-3"&gt;&lt;a href="#cb5-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    tag &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; v &lt;span class="op"&gt;.:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-4"&gt;&lt;a href="#cb5-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    unless (tag &lt;span class="op"&gt;==&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Site&amp;quot;&lt;/span&gt;) &lt;span class="op"&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-5"&gt;&lt;a href="#cb5-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;fail&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Parsed wrong type of ID!&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-6"&gt;&lt;a href="#cb5-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;SiteId&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;$&amp;gt;&lt;/span&gt; (v &lt;span class="op"&gt;.:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb5-7"&gt;&lt;a href="#cb5-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb5-8"&gt;&lt;a href="#cb5-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;instance&lt;/span&gt; &lt;span class="dt"&gt;ToJSON&lt;/span&gt; &lt;span class="dt"&gt;SiteId&lt;/span&gt; &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-9"&gt;&lt;a href="#cb5-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  toJSON (&lt;span class="dt"&gt;SiteId&lt;/span&gt; x) &lt;span class="ot"&gt;=&lt;/span&gt; object [ &lt;span class="st"&gt;&amp;quot;type&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;.=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Site&amp;quot;&lt;/span&gt;, &lt;span class="st"&gt;&amp;quot;id&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;.=&lt;/span&gt; x ]&lt;/span&gt;
&lt;span id="cb5-10"&gt;&lt;a href="#cb5-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb5-11"&gt;&lt;a href="#cb5-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;instance&lt;/span&gt; &lt;span class="dt"&gt;FromJSON&lt;/span&gt; &lt;span class="dt"&gt;AppId&lt;/span&gt; &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-12"&gt;&lt;a href="#cb5-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  parseJSON &lt;span class="ot"&gt;=&lt;/span&gt; withObject &lt;span class="st"&gt;&amp;quot;Id&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; \v &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-13"&gt;&lt;a href="#cb5-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    tag &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; v &lt;span class="op"&gt;.:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-14"&gt;&lt;a href="#cb5-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    unless (tag &lt;span class="op"&gt;==&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;App&amp;quot;&lt;/span&gt;) &lt;span class="op"&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-15"&gt;&lt;a href="#cb5-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;fail&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Parsed wrong type of ID!&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-16"&gt;&lt;a href="#cb5-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;AppId&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;$&amp;gt;&lt;/span&gt; (v &lt;span class="op"&gt;.:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb5-17"&gt;&lt;a href="#cb5-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb5-18"&gt;&lt;a href="#cb5-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;instance&lt;/span&gt; &lt;span class="dt"&gt;ToJSON&lt;/span&gt; &lt;span class="dt"&gt;AppId&lt;/span&gt; &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb5-19"&gt;&lt;a href="#cb5-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  toJSON (&lt;span class="dt"&gt;AppId&lt;/span&gt; x) &lt;span class="ot"&gt;=&lt;/span&gt; object [ &lt;span class="st"&gt;&amp;quot;type&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;.=&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;App&amp;quot;&lt;/span&gt;, &lt;span class="st"&gt;&amp;quot;id&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;.=&lt;/span&gt; x ]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;However, luckily, because we’re in Haskell, it’s easy to get the best of both
worlds with &lt;em&gt;phantom types&lt;/em&gt; (that don’t refer to anything inside the
actual data representation):&lt;/p&gt;
&lt;div class="sourceCode" id="cb6"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb6-1"&gt;&lt;a href="#cb6-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Id&lt;/span&gt; a &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Id&lt;/span&gt; {&lt;span class="ot"&gt; getId ::&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt; }&lt;/span&gt;
&lt;span id="cb6-2"&gt;&lt;a href="#cb6-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb6-3"&gt;&lt;a href="#cb6-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Site&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-4"&gt;&lt;a href="#cb6-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;App&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-5"&gt;&lt;a href="#cb6-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb6-6"&gt;&lt;a href="#cb6-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; &lt;span class="dt"&gt;SiteId&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Id&lt;/span&gt; &lt;span class="dt"&gt;Site&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-7"&gt;&lt;a href="#cb6-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; &lt;span class="dt"&gt;AppId&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Id&lt;/span&gt; &lt;span class="dt"&gt;App&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-8"&gt;&lt;a href="#cb6-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb6-9"&gt;&lt;a href="#cb6-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- using Typeable for demonstration purposes&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-10"&gt;&lt;a href="#cb6-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;instance&lt;/span&gt; &lt;span class="dt"&gt;Typeable&lt;/span&gt; a &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ToJSON&lt;/span&gt; (&lt;span class="dt"&gt;Id&lt;/span&gt; a) &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-11"&gt;&lt;a href="#cb6-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  toJSON (&lt;span class="dt"&gt;Id&lt;/span&gt; x) &lt;span class="ot"&gt;=&lt;/span&gt; object&lt;/span&gt;
&lt;span id="cb6-12"&gt;&lt;a href="#cb6-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    [ &lt;span class="st"&gt;&amp;quot;type&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;.=&lt;/span&gt; &lt;span class="fu"&gt;show&lt;/span&gt; (typeRep &lt;span class="op"&gt;@&lt;/span&gt;a)&lt;/span&gt;
&lt;span id="cb6-13"&gt;&lt;a href="#cb6-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    , &lt;span class="st"&gt;&amp;quot;id&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;.=&lt;/span&gt; x&lt;/span&gt;
&lt;span id="cb6-14"&gt;&lt;a href="#cb6-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    ]&lt;/span&gt;
&lt;span id="cb6-15"&gt;&lt;a href="#cb6-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb6-16"&gt;&lt;a href="#cb6-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;instance&lt;/span&gt; &lt;span class="dt"&gt;Typeable&lt;/span&gt; a &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;FromJSON&lt;/span&gt; (&lt;span class="dt"&gt;Id&lt;/span&gt; a) &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-17"&gt;&lt;a href="#cb6-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  parseJSON &lt;span class="ot"&gt;=&lt;/span&gt; withObject &lt;span class="st"&gt;&amp;quot;Id&amp;quot;&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; \v &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-18"&gt;&lt;a href="#cb6-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    tag &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; v &lt;span class="op"&gt;.:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-19"&gt;&lt;a href="#cb6-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    unless (tag &lt;span class="op"&gt;==&lt;/span&gt; &lt;span class="fu"&gt;show&lt;/span&gt; (typeRep &lt;span class="op"&gt;@&lt;/span&gt;a)) &lt;span class="op"&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-20"&gt;&lt;a href="#cb6-20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;fail&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Parsed wrong type of ID!&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb6-21"&gt;&lt;a href="#cb6-21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Id&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;$&amp;gt;&lt;/span&gt; (v &lt;span class="op"&gt;.:&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Type safety doesn’t necessarily mean inflexibility!&lt;/p&gt;
&lt;h3 id="phantom-powers"&gt;Phantom Powers&lt;/h3&gt;
&lt;p&gt;Phantom types give us a &lt;em&gt;lot&lt;/em&gt; of low-hanging fruit for preventing
inadvertent misuse.&lt;/p&gt;
&lt;p&gt;The &lt;a
href="https://www.theregister.com/2017/04/11/database_deletion_downed_digital_ocean_last_week/"&gt;2017
DigitalOcean outage&lt;/a&gt;, for example, was partially about the wrong environment
credentials being used.&lt;/p&gt;
&lt;p&gt;We could imagine a test harness that clears a test database using &lt;em&gt;&lt;a
href="https://hackage.haskell.org/package/postgresql-simple"&gt;postgresql-simple&lt;/a&gt;&lt;/em&gt;:&lt;/p&gt;
&lt;div class="sourceCode" id="cb7"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb7-1"&gt;&lt;a href="#cb7-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Warning: do NOT call this outside of test environment!&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb7-2"&gt;&lt;a href="#cb7-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;clearTestEnv ::&lt;/span&gt; &lt;span class="dt"&gt;Connection&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="cb7-3"&gt;&lt;a href="#cb7-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;clearTestEnv conn &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb7-4"&gt;&lt;a href="#cb7-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;putStrLn&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Are you sure you read the warning on this function? Well, too late now!&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb7-5"&gt;&lt;a href="#cb7-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  _ &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; execute_ conn &lt;span class="st"&gt;&amp;quot;DROP TABLE IF EXISTS users CASCADE&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb7-6"&gt;&lt;a href="#cb7-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;putStrLn&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Test data wiped.&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;However, somewhere down the line, someone is going to call
&lt;code&gt;clearTestEnv&lt;/code&gt; &lt;em&gt;deep&lt;/em&gt; inside a function inside a function
inside a function, which itself is called against the prod database. I guarantee
it.&lt;/p&gt;
&lt;p&gt;To ensure this never happens, we can use closed phantom types using
&lt;code&gt;DataKinds&lt;/code&gt; (made nicer with &lt;code&gt;TypeData&lt;/code&gt; post-GHC 9.6):&lt;/p&gt;
&lt;div class="sourceCode" id="cb8"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb8-1"&gt;&lt;a href="#cb8-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- type data = declare a closed kind and two type constructors at the type level using -XTypeData&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb8-2"&gt;&lt;a href="#cb8-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;type&lt;/span&gt; &lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;Env&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Prod&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Test&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb8-3"&gt;&lt;a href="#cb8-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb8-4"&gt;&lt;a href="#cb8-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;DbConnection&lt;/span&gt; (&lt;span class="ot"&gt;a ::&lt;/span&gt; &lt;span class="dt"&gt;Env&lt;/span&gt;) &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;DbConnection&lt;/span&gt; &lt;span class="dt"&gt;Connection&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb8-5"&gt;&lt;a href="#cb8-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb8-6"&gt;&lt;a href="#cb8-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;runQuery ::&lt;/span&gt; &lt;span class="dt"&gt;DbConnection&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Query&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; &lt;span class="dt"&gt;Int64&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb8-7"&gt;&lt;a href="#cb8-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;runQuery (&lt;span class="dt"&gt;DbConnection&lt;/span&gt; c) q &lt;span class="ot"&gt;=&lt;/span&gt; execute_ c q&lt;/span&gt;
&lt;span id="cb8-8"&gt;&lt;a href="#cb8-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb8-9"&gt;&lt;a href="#cb8-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Warning: Did you remember to charge your chromebook? Oh and this function&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb8-10"&gt;&lt;a href="#cb8-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- is safe by the way.&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb8-11"&gt;&lt;a href="#cb8-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;clearTestEnv ::&lt;/span&gt; &lt;span class="dt"&gt;DbConnection&lt;/span&gt; &lt;span class="dt"&gt;Test&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="cb8-12"&gt;&lt;a href="#cb8-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;clearTestEnv conn &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb8-13"&gt;&lt;a href="#cb8-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  _ &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; runQuery conn &lt;span class="st"&gt;&amp;quot;DROP TABLE IF EXISTS users CASCADE&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb8-14"&gt;&lt;a href="#cb8-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;putStrLn&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;Test data wiped.&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb8-15"&gt;&lt;a href="#cb8-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb8-16"&gt;&lt;a href="#cb8-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;connectProd ::&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;DbConnection&lt;/span&gt; &lt;span class="dt"&gt;Prod&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb8-17"&gt;&lt;a href="#cb8-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;connectProd &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;DbConnection&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;$&amp;gt;&lt;/span&gt; connectPostgreSQL &lt;span class="st"&gt;&amp;quot;host=prod...&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now, if you create a connection using &lt;code&gt;connectProd&lt;/code&gt;, you can use
&lt;code&gt;runQuery&lt;/code&gt; on it (because it can run any
&lt;code&gt;DbConnection a&lt;/code&gt;)…but if any sub-function of a sub-function calls
&lt;code&gt;clearTestEnv&lt;/code&gt;, it will have to unify with
&lt;code&gt;DbConnection Test&lt;/code&gt;, which is impossible for a prod connection.&lt;/p&gt;
&lt;p&gt;This is somewhat similar to using “mocking-only” subclasses for dependency
injection, but with a closed universe. I discuss patterns like this in my &lt;a
href="https://blog.jle.im/entries/series/+introduction-to-singletons.html"&gt;Introduction
to Singletons&lt;/a&gt; series.&lt;/p&gt;
&lt;h2 id="correct-representations"&gt;Correct Representations&lt;/h2&gt;
&lt;h3 id="semantic-phantoms"&gt;Semantic Phantoms&lt;/h3&gt;
&lt;p&gt;And sometimes, phantom types can do the work for you, not only preventing
mix-ups but also encoding business logic in their manipulation.&lt;/p&gt;
&lt;p&gt;Take, for instance, the &lt;a
href="https://en.wikipedia.org/wiki/Mars_Climate_Orbiter"&gt;Mars Climate Orbiter
failure&lt;/a&gt;, where the software module provided by Lockheed Martin expected US
Customary Units, and another one developed by NASA expected SI units.&lt;/p&gt;
&lt;p&gt;If I had a function like:&lt;/p&gt;
&lt;div class="sourceCode" id="cb9"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb9-1"&gt;&lt;a href="#cb9-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | In Newton-seconds&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb9-2"&gt;&lt;a href="#cb9-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;myMomentum ::&lt;/span&gt; &lt;span class="dt"&gt;Double&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb9-3"&gt;&lt;a href="#cb9-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;myMomentum &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dv"&gt;20&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb9-4"&gt;&lt;a href="#cb9-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb9-5"&gt;&lt;a href="#cb9-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | In Pounds-second&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb9-6"&gt;&lt;a href="#cb9-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;myImpulse ::&lt;/span&gt; &lt;span class="dt"&gt;Double&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb9-7"&gt;&lt;a href="#cb9-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;myImpulse &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dv"&gt;4&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb9-8"&gt;&lt;a href="#cb9-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb9-9"&gt;&lt;a href="#cb9-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Make sure these are both the same units!&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb9-10"&gt;&lt;a href="#cb9-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;applyImpulse ::&lt;/span&gt; &lt;span class="dt"&gt;Double&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Double&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Double&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb9-11"&gt;&lt;a href="#cb9-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;applyImpulse currentMomentum impulse &lt;span class="ot"&gt;=&lt;/span&gt; currentMomentum &lt;span class="op"&gt;+&lt;/span&gt; impulse&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is just &lt;em&gt;asking&lt;/em&gt; for someone to come along and provide newtons
alongside pounds. It isn’t even clear from the types what is expected!&lt;/p&gt;
&lt;p&gt;We can instead use the &lt;em&gt;&lt;a
href="https://hackage.haskell.org/package/dimensional"&gt;dimensional&lt;/a&gt;&lt;/em&gt;
library:&lt;/p&gt;
&lt;div class="sourceCode" id="cb10"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb10-1"&gt;&lt;a href="#cb10-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="kw"&gt;qualified&lt;/span&gt; &lt;span class="dt"&gt;Numeric.Units.Dimensional.Prelude&lt;/span&gt; &lt;span class="kw"&gt;as&lt;/span&gt; &lt;span class="dt"&gt;U&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb10-2"&gt;&lt;a href="#cb10-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;Numeric.Units.Dimensional&lt;/span&gt; ((*~))&lt;/span&gt;
&lt;span id="cb10-3"&gt;&lt;a href="#cb10-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;Numeric.Units.Dimensional.SIUnits&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb10-4"&gt;&lt;a href="#cb10-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="dt"&gt;Numeric.Units.Dimensional.NonSI&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb10-5"&gt;&lt;a href="#cb10-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb10-6"&gt;&lt;a href="#cb10-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;myMomentum ::&lt;/span&gt; &lt;span class="dt"&gt;Momentum&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb10-7"&gt;&lt;a href="#cb10-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;myMomentum &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dv"&gt;20&lt;/span&gt; &lt;span class="op"&gt;*~&lt;/span&gt; (newton &lt;span class="op"&gt;U.*&lt;/span&gt; seconds)&lt;/span&gt;
&lt;span id="cb10-8"&gt;&lt;a href="#cb10-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb10-9"&gt;&lt;a href="#cb10-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;myImpulse ::&lt;/span&gt; &lt;span class="dt"&gt;Impulse&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb10-10"&gt;&lt;a href="#cb10-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;myImpulse &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dv"&gt;4&lt;/span&gt; &lt;span class="op"&gt;*~&lt;/span&gt; (poundForce &lt;span class="op"&gt;U.*&lt;/span&gt; seconds)&lt;/span&gt;
&lt;span id="cb10-11"&gt;&lt;a href="#cb10-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb10-12"&gt;&lt;a href="#cb10-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Verify at compile-time that we can use &amp;#39;+&amp;#39; with Momentum and Impulse&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb10-13"&gt;&lt;a href="#cb10-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;applyImpulse ::&lt;/span&gt; &lt;span class="dt"&gt;Momentum&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Impulse&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Momentum&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb10-14"&gt;&lt;a href="#cb10-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;applyImpulse currentMomentum impulse &lt;span class="ot"&gt;=&lt;/span&gt; currentMomentum &lt;span class="op"&gt;+&lt;/span&gt; impulse&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now as long as momentum and impulse are provided in the correct types at API
boundaries, no mix-up will happen. No need to send 300 million dollars down the
drain! Libraries will just need to provide a unified &lt;code&gt;Momentum&lt;/code&gt; or
&lt;code&gt;Impulse&lt;/code&gt; type, and everything will work out.&lt;/p&gt;
&lt;h3 id="the-billion-dollar-mistake"&gt;The Billion-Dollar Mistake&lt;/h3&gt;
&lt;p&gt;Speaking of costly errors, there is one extremely egregious pattern that is
so pervasive, so alluring, and yet so inevitably devastating, it has been dubbed
the “Billion Dollar Mistake”. It’s the idea of a &lt;em&gt;sentinel value&lt;/em&gt;, or
in-band signaling.&lt;/p&gt;
&lt;p&gt;There are examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;String.indexOf()&lt;/code&gt;, &lt;code&gt;str.find()&lt;/code&gt;, etc. in many
languages return -1 if the substring is not found&lt;/li&gt;
&lt;li&gt;C’s &lt;code&gt;fgetc()&lt;/code&gt;, &lt;code&gt;getchar()&lt;/code&gt;, return -1 for
&lt;code&gt;EOF&lt;/code&gt;. And if you cast to &lt;code&gt;char&lt;/code&gt;, you basically can’t
distinguish EOF from &lt;code&gt;0xff&lt;/code&gt; (&lt;code&gt;ÿ&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;malloc()&lt;/code&gt; returning the pointer 0 means not enough memory&lt;/li&gt;
&lt;li&gt;Some languages have a special &lt;code&gt;NULL&lt;/code&gt; pointer value as well — or
even a value &lt;code&gt;null&lt;/code&gt; that can be passed in for any expected type or
object or value.&lt;/li&gt;
&lt;li&gt;JavaScript’s &lt;code&gt;parseInt&lt;/code&gt; returns not &lt;code&gt;null&lt;/code&gt;, but rather
&lt;code&gt;NaN&lt;/code&gt; for a bad parse — giving two distinct sentinel values&lt;/li&gt;
&lt;li&gt;A lot of Unix scripting uses the empty string &lt;code&gt;""&lt;/code&gt; for
non-presence&lt;/li&gt;
&lt;li&gt;Sensor firmware often reports values like &lt;code&gt;-999&lt;/code&gt; for a bad
reading…but sometimes &lt;code&gt;-999&lt;/code&gt; might actually be a valid value!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It should be evident that these are just accidents and ticking time bombs
waiting to happen. Some caller just needs to forget to handle the sentinel
value, or to falsely assume that the sentinel value is impossible to occur in
any situation.&lt;/p&gt;
&lt;p&gt;It’s called the billion dollar mistake, but it’s definitely arguable that the
cumulative damage has been much higher. High-profile incidents include &lt;a
href="https://www.rapid7.com/db/modules/exploit/linux/local/sock_sendpage/"&gt;sock_sendpage&lt;/a&gt;
and the &lt;a
href="https://www.thousandeyes.com/blog/google-cloud-outage-analysis-june-12-2025"&gt;2025
GCP outage&lt;/a&gt;, but if you’re reading this and you are honest with yourself,
it’s probably happened to you multiple times and has been the source of many
frustrating bug hunts.&lt;/p&gt;
&lt;p&gt;There’s also &lt;a
href="https://www.invicti.com/web-application-vulnerabilities/openssl-improper-input-validation-vulnerability-cve-2008-5077"&gt;CVE-2008-5077&lt;/a&gt;,
because &lt;a
href="https://docs.openssl.org/1.1.1/man3/EVP_VerifyInit/"&gt;EVP_VerifyInit&lt;/a&gt;
returns &lt;code&gt;0&lt;/code&gt; for false, &lt;code&gt;1&lt;/code&gt; for true, and &lt;code&gt;-1&lt;/code&gt;
for error! So some OpenSSL code did a simple if-then-else check
(&lt;code&gt;result != 0&lt;/code&gt;) and treated error and true the same way. Whoops.&lt;/p&gt;
&lt;p&gt;Why do we do this to ourselves? Because it is convenient. In the case of
&lt;code&gt;EVP_VerifyInit&lt;/code&gt;, we can define an enum instead…&lt;/p&gt;
&lt;div class="sourceCode" id="cb11"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb11-1"&gt;&lt;a href="#cb11-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;VerifyResult&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Success&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Failure&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Error&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;However, it’s not easy to make an “integer or not found” type in C or
JavaScript without some sort of side-channel. Imagine if JavaScript’s
&lt;code&gt;String.indexOf()&lt;/code&gt; instead expected continuations on success and
failure and became much less usable as a result:&lt;/p&gt;
&lt;div class="sourceCode" id="cb12"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb12-1"&gt;&lt;a href="#cb12-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;unsafeIndexOf ::&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb12-2"&gt;&lt;a href="#cb12-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb12-3"&gt;&lt;a href="#cb12-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- vs.&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb12-4"&gt;&lt;a href="#cb12-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb12-5"&gt;&lt;a href="#cb12-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- takes a success continuation and a failure continuation&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb12-6"&gt;&lt;a href="#cb12-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;indexOf ::&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; (&lt;span class="dt"&gt;Int&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; r) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; (() &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; r) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; r&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;All of this just to &lt;a
href="https://blog.jle.im/entry/faking-adts-and-gadts.html"&gt;fake having actual
sum types&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We don’t really have an excuse in Haskell, since we can just return
&lt;code&gt;Maybe&lt;/code&gt;:&lt;/p&gt;
&lt;div class="sourceCode" id="cb13"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb13-1"&gt;&lt;a href="#cb13-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- from Data.Vector&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb13-2"&gt;&lt;a href="#cb13-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;elemIndex ::&lt;/span&gt; &lt;span class="dt"&gt;Eq&lt;/span&gt; a &lt;span class="ot"&gt;=&amp;gt;&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Vector&lt;/span&gt; a &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Int&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Returning &lt;code&gt;Maybe&lt;/code&gt; or &lt;code&gt;Option&lt;/code&gt; forces the caller to
handle:&lt;/p&gt;
&lt;div class="sourceCode" id="cb14"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb14-1"&gt;&lt;a href="#cb14-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;case&lt;/span&gt; elemIndex &lt;span class="dv"&gt;3&lt;/span&gt; myVec &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb14-2"&gt;&lt;a href="#cb14-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;Just&lt;/span&gt; i &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="co"&gt;-- ..&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb14-3"&gt;&lt;a href="#cb14-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="dt"&gt;Nothing&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="co"&gt;-- ..&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and this handling is compiler-enforced. Provided, of course, you don’t &lt;a
href="https://blog.cloudflare.com/18-november-2025-outage/"&gt;intentionally throw
away your type-safety and compiler checks for no reason&lt;/a&gt;. You can even return
&lt;code&gt;Either&lt;/code&gt; with an enum for richer responses, and very easily &lt;a
href="https://blog.jle.im/entry/inside-my-world-ode-to-functor-and-monad.html"&gt;chain
erroring operations using Functor and Monad&lt;/a&gt;. In fact, with cheap ADTs, you
can define your own rich result type, like in &lt;em&gt;&lt;a
href="https://hackage-content.haskell.org/package/unix"&gt;unix&lt;/a&gt;&lt;/em&gt;’s
&lt;code&gt;ProcessStatus&lt;/code&gt;:&lt;/p&gt;
&lt;div class="sourceCode" id="cb15"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb15-1"&gt;&lt;a href="#cb15-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;ProcessStatus&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb15-2"&gt;&lt;a href="#cb15-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;   &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Exited&lt;/span&gt; &lt;span class="dt"&gt;ExitCode&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb15-3"&gt;&lt;a href="#cb15-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;   &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Terminated&lt;/span&gt; &lt;span class="dt"&gt;Signal&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb15-4"&gt;&lt;a href="#cb15-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;   &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Stopped&lt;/span&gt; &lt;span class="dt"&gt;Signal&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Imagine trying to cram all of that information into an &lt;code&gt;int&lt;/code&gt;!&lt;/p&gt;
&lt;h2 id="unmarked-assumptions"&gt;Unmarked Assumptions&lt;/h2&gt;
&lt;p&gt;Assumptions kill, and a lot of times we arrive at implicit assumptions in our
code. Unfortunately, even if we add these assumptions in our documentation, it
only takes a minor refactor or lapse in memory for these to cause catastrophic
incidents.&lt;/p&gt;
&lt;p&gt;There are the simple cases — consider a &lt;code&gt;mean&lt;/code&gt; function:&lt;/p&gt;
&lt;div class="sourceCode" id="cb16"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb16-1"&gt;&lt;a href="#cb16-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Warning: do not give an empty list!&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb16-2"&gt;&lt;a href="#cb16-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;mean ::&lt;/span&gt; [&lt;span class="dt"&gt;Double&lt;/span&gt;] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Double&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb16-3"&gt;&lt;a href="#cb16-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;mean xs &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;sum&lt;/span&gt; xs &lt;span class="op"&gt;/&lt;/span&gt; &lt;span class="fu"&gt;fromIntegral&lt;/span&gt; (&lt;span class="fu"&gt;length&lt;/span&gt; xs)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But are you &lt;em&gt;really&lt;/em&gt; going to remember to check if your list is empty
&lt;em&gt;every&lt;/em&gt; time you give it to &lt;code&gt;mean&lt;/code&gt;? No, of course not.
Instead, make it a compiler-enforced constraint.&lt;/p&gt;
&lt;div class="sourceCode" id="cb17"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb17-1"&gt;&lt;a href="#cb17-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;mean ::&lt;/span&gt; &lt;span class="dt"&gt;NonEmpty&lt;/span&gt; &lt;span class="dt"&gt;Double&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Double&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb17-2"&gt;&lt;a href="#cb17-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;mean xs &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;sum&lt;/span&gt; xs &lt;span class="op"&gt;/&lt;/span&gt; &lt;span class="fu"&gt;fromIntegral&lt;/span&gt; (&lt;span class="fu"&gt;length&lt;/span&gt; xs)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now &lt;code&gt;mean&lt;/code&gt; takes a &lt;code&gt;NonEmpty&lt;/code&gt; list, which can only be
created safely using &lt;code&gt;nonEmpty :: [a] -&amp;gt; Maybe (NonEmpty a)&lt;/code&gt;
(where the caller has to explicitly handle the empty list case, so they’ll never
forget) or from functions that already return &lt;code&gt;NonEmpty&lt;/code&gt; by default
(like &lt;code&gt;some :: f a -&amp;gt; f (NonEmpty a)&lt;/code&gt; or
&lt;code&gt;group :: Eq a =&amp;gt; [a] -&amp;gt; [NonEmpty a]&lt;/code&gt;), allowing you to
beautifully chain post-conditions directly into pre-conditions.&lt;/p&gt;
&lt;p&gt;Accessing containers is, in general, very fraught…even things like indexing
lists can send us into a graveyard spiral. Sometimes the issue is more subtle.
This is our reminder to never let these implicit assumptions go unnoticed.&lt;/p&gt;
&lt;h3 id="separate-processed-data"&gt;Separate Processed Data&lt;/h3&gt;
&lt;p&gt;“Shotgun parsing” involves mixing validated and unvalidated data at different
levels in your program. Oftentimes it is considered “fine” because you just need
to remember which inputs are validated and which aren’t…right? In truth, all it
takes is a simple temporary lapse of mental model, a time delay between working
on code, or uncoordinated contributions before things fall apart.&lt;/p&gt;
&lt;p&gt;Consider a situation where we validate usernames only on write to the
database.&lt;/p&gt;
&lt;div class="sourceCode" id="cb18"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb18-1"&gt;&lt;a href="#cb18-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;validUsername ::&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb18-2"&gt;&lt;a href="#cb18-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;validUsername s &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;all&lt;/span&gt; &lt;span class="fu"&gt;isAlphaNum&lt;/span&gt; s &lt;span class="op"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="fu"&gt;all&lt;/span&gt; &lt;span class="fu"&gt;isLower&lt;/span&gt; s&lt;/span&gt;
&lt;span id="cb18-3"&gt;&lt;a href="#cb18-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb18-4"&gt;&lt;a href="#cb18-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Returns &amp;#39;Nothing&amp;#39; if username is invalid or insertion failed&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb18-5"&gt;&lt;a href="#cb18-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;saveUser ::&lt;/span&gt; &lt;span class="dt"&gt;Connection&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;UUID&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb18-6"&gt;&lt;a href="#cb18-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;saveUser conn s&lt;/span&gt;
&lt;span id="cb18-7"&gt;&lt;a href="#cb18-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; validUsername s &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb18-8"&gt;&lt;a href="#cb18-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      newId &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; query conn &lt;span class="st"&gt;&amp;quot;INSERT INTO users (username) VALUES (?) returning user_id&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;Only&lt;/span&gt; s)&lt;/span&gt;
&lt;span id="cb18-9"&gt;&lt;a href="#cb18-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="fu"&gt;pure&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="kw"&gt;case&lt;/span&gt; newId &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb18-10"&gt;&lt;a href="#cb18-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        [] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb18-11"&gt;&lt;a href="#cb18-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        &lt;span class="dt"&gt;Only&lt;/span&gt; i &lt;span class="op"&gt;:&lt;/span&gt; _ &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Just&lt;/span&gt; i&lt;/span&gt;
&lt;span id="cb18-12"&gt;&lt;a href="#cb18-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="fu"&gt;otherwise&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="fu"&gt;pure&lt;/span&gt; &lt;span class="dt"&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb18-13"&gt;&lt;a href="#cb18-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb18-14"&gt;&lt;a href="#cb18-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;getUser ::&lt;/span&gt; &lt;span class="dt"&gt;Connection&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;UUID&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb18-15"&gt;&lt;a href="#cb18-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;getUser conn uid &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb18-16"&gt;&lt;a href="#cb18-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  unames &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; query conn &lt;span class="st"&gt;&amp;quot;SELECT username FROM users where user_id = ?&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;Only&lt;/span&gt; uid)&lt;/span&gt;
&lt;span id="cb18-17"&gt;&lt;a href="#cb18-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;pure&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="kw"&gt;case&lt;/span&gt; unames &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb18-18"&gt;&lt;a href="#cb18-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    [] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb18-19"&gt;&lt;a href="#cb18-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Only&lt;/span&gt; s &lt;span class="op"&gt;:&lt;/span&gt; _ &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Just&lt;/span&gt; s&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It &lt;em&gt;should&lt;/em&gt; be fine as long as you only ever use &lt;code&gt;saveUser&lt;/code&gt;
and &lt;code&gt;getUser&lt;/code&gt;…and nobody else has access to the database. But, if
someone hooks up a custom connector, or does some manual modifications, then the
&lt;code&gt;users&lt;/code&gt; table will now have an invalid username, bypassing Haskell.
And because of that, &lt;code&gt;getUser&lt;/code&gt; can return an invalid string!&lt;/p&gt;
&lt;p&gt;Don’t assume that these inconsequential slip-ups won’t happen; assume that
it’s only a matter of time.&lt;/p&gt;
&lt;p&gt;Instead, we can bake the state of a validated string into the type
itself:&lt;/p&gt;
&lt;div class="sourceCode" id="cb19"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb19-1"&gt;&lt;a href="#cb19-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;newtype&lt;/span&gt; &lt;span class="dt"&gt;Username&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;UnsafeUsername&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb19-2"&gt;&lt;a href="#cb19-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;deriving&lt;/span&gt; (&lt;span class="dt"&gt;Show&lt;/span&gt;, &lt;span class="dt"&gt;Eq&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb19-3"&gt;&lt;a href="#cb19-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb19-4"&gt;&lt;a href="#cb19-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Our &amp;quot;Smart Constructor&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb19-5"&gt;&lt;a href="#cb19-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;mkUsername ::&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Username&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb19-6"&gt;&lt;a href="#cb19-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;mkUsername s&lt;/span&gt;
&lt;span id="cb19-7"&gt;&lt;a href="#cb19-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; validUsername s &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Just&lt;/span&gt; (&lt;span class="dt"&gt;UnsafeUsername&lt;/span&gt; s)&lt;/span&gt;
&lt;span id="cb19-8"&gt;&lt;a href="#cb19-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="fu"&gt;otherwise&lt;/span&gt;       &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb19-9"&gt;&lt;a href="#cb19-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb19-10"&gt;&lt;a href="#cb19-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Access the raw string if needed&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb19-11"&gt;&lt;a href="#cb19-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;unUsername ::&lt;/span&gt; &lt;span class="dt"&gt;Username&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb19-12"&gt;&lt;a href="#cb19-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;unUsername (&lt;span class="dt"&gt;UnsafeUsername&lt;/span&gt; s) &lt;span class="ot"&gt;=&lt;/span&gt; s&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;Username&lt;/code&gt; and &lt;code&gt;String&lt;/code&gt; themselves are not structurally
different — instead, &lt;code&gt;Username&lt;/code&gt; is a compiler-enforced tag specifying
it went through a specific required validation function &lt;em&gt;within Haskell&lt;/em&gt;,
not just externally verified.&lt;/p&gt;
&lt;p&gt;Now &lt;code&gt;saveUser&lt;/code&gt; and &lt;code&gt;getUser&lt;/code&gt; are safe at the
boundaries:&lt;/p&gt;
&lt;div class="sourceCode" id="cb20"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb20-1"&gt;&lt;a href="#cb20-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;saveUser ::&lt;/span&gt; &lt;span class="dt"&gt;Connection&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Username&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;UUID&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb20-2"&gt;&lt;a href="#cb20-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;saveUser conn s &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb20-3"&gt;&lt;a href="#cb20-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  newId &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; query conn &lt;span class="st"&gt;&amp;quot;INSERT INTO users (username) VALUES (?) returning user_id&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;Only&lt;/span&gt; (unUsername s))&lt;/span&gt;
&lt;span id="cb20-4"&gt;&lt;a href="#cb20-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;pure&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="kw"&gt;case&lt;/span&gt; newId &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb20-5"&gt;&lt;a href="#cb20-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    [] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb20-6"&gt;&lt;a href="#cb20-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Only&lt;/span&gt; i &lt;span class="op"&gt;:&lt;/span&gt; _ &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Just&lt;/span&gt; i&lt;/span&gt;
&lt;span id="cb20-7"&gt;&lt;a href="#cb20-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb20-8"&gt;&lt;a href="#cb20-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;getUser ::&lt;/span&gt; &lt;span class="dt"&gt;Connection&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;UUID&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Username&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb20-9"&gt;&lt;a href="#cb20-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;getUser conn uid &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb20-10"&gt;&lt;a href="#cb20-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  unames &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; query conn &lt;span class="st"&gt;&amp;quot;SELECT username FROM users where user_id = ?&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;Only&lt;/span&gt; uid)&lt;/span&gt;
&lt;span id="cb20-11"&gt;&lt;a href="#cb20-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;pure&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="kw"&gt;case&lt;/span&gt; unames &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb20-12"&gt;&lt;a href="#cb20-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    [] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb20-13"&gt;&lt;a href="#cb20-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Only&lt;/span&gt; s &lt;span class="op"&gt;:&lt;/span&gt; _ &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; mkUsername s&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(In real code, of course, we would use a more usable indication of failure
than &lt;code&gt;Maybe&lt;/code&gt;)&lt;/p&gt;
&lt;p&gt;We can even hook this into Haskell’s typeclass system to make this even more
rigorous: &lt;code&gt;Username&lt;/code&gt; could have its own &lt;code&gt;FromField&lt;/code&gt; and
&lt;code&gt;ToField&lt;/code&gt; instances that push the validation to the driver level.&lt;/p&gt;
&lt;div class="sourceCode" id="cb21"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb21-1"&gt;&lt;a href="#cb21-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;instance&lt;/span&gt; &lt;span class="dt"&gt;FromField&lt;/span&gt; &lt;span class="dt"&gt;Username&lt;/span&gt; &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb21-2"&gt;&lt;a href="#cb21-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  fromField f mdata &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb21-3"&gt;&lt;a href="#cb21-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;    s ::&lt;/span&gt; &lt;span class="dt"&gt;String&lt;/span&gt; &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; fromField f mdata&lt;/span&gt;
&lt;span id="cb21-4"&gt;&lt;a href="#cb21-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="kw"&gt;case&lt;/span&gt; mkUsername s &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb21-5"&gt;&lt;a href="#cb21-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;Just&lt;/span&gt; u  &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="fu"&gt;pure&lt;/span&gt; u&lt;/span&gt;
&lt;span id="cb21-6"&gt;&lt;a href="#cb21-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="dt"&gt;Nothing&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; returnError &lt;span class="dt"&gt;ConversionFailed&lt;/span&gt; f (&lt;span class="st"&gt;&amp;quot;Invalid username format: &amp;quot;&lt;/span&gt; &lt;span class="op"&gt;++&lt;/span&gt; s)&lt;/span&gt;
&lt;span id="cb21-7"&gt;&lt;a href="#cb21-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb21-8"&gt;&lt;a href="#cb21-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;instance&lt;/span&gt; &lt;span class="dt"&gt;ToField&lt;/span&gt; &lt;span class="dt"&gt;Username&lt;/span&gt; &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb21-9"&gt;&lt;a href="#cb21-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  toField &lt;span class="ot"&gt;=&lt;/span&gt; toField &lt;span class="op"&gt;.&lt;/span&gt; unUsername&lt;/span&gt;
&lt;span id="cb21-10"&gt;&lt;a href="#cb21-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb21-11"&gt;&lt;a href="#cb21-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;saveUser ::&lt;/span&gt; &lt;span class="dt"&gt;Connection&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Username&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;UUID&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb21-12"&gt;&lt;a href="#cb21-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;saveUser conn s &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb21-13"&gt;&lt;a href="#cb21-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  newId &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; query conn &lt;span class="st"&gt;&amp;quot;INSERT INTO users (username) VALUES (?) returning user_id&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;Only&lt;/span&gt; s)&lt;/span&gt;
&lt;span id="cb21-14"&gt;&lt;a href="#cb21-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;pure&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="kw"&gt;case&lt;/span&gt; newId &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb21-15"&gt;&lt;a href="#cb21-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    [] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb21-16"&gt;&lt;a href="#cb21-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Only&lt;/span&gt; i &lt;span class="op"&gt;:&lt;/span&gt; _ &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Just&lt;/span&gt; i&lt;/span&gt;
&lt;span id="cb21-17"&gt;&lt;a href="#cb21-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb21-18"&gt;&lt;a href="#cb21-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;getUser ::&lt;/span&gt; &lt;span class="dt"&gt;Connection&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;UUID&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Maybe&lt;/span&gt; &lt;span class="dt"&gt;Username&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb21-19"&gt;&lt;a href="#cb21-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;getUser conn uid &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb21-20"&gt;&lt;a href="#cb21-20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  unames &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; query conn &lt;span class="st"&gt;&amp;quot;SELECT username FROM users where user_id = ?&amp;quot;&lt;/span&gt; (&lt;span class="dt"&gt;Only&lt;/span&gt; uid)&lt;/span&gt;
&lt;span id="cb21-21"&gt;&lt;a href="#cb21-21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="fu"&gt;pure&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="kw"&gt;case&lt;/span&gt; unames &lt;span class="kw"&gt;of&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb21-22"&gt;&lt;a href="#cb21-22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    [] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Nothing&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb21-23"&gt;&lt;a href="#cb21-23" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="dt"&gt;Only&lt;/span&gt; s &lt;span class="op"&gt;:&lt;/span&gt; _ &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Just&lt;/span&gt; s&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Pushing it to the driver level will also unify everything with the driver’s
error-handling system.&lt;/p&gt;
&lt;p&gt;These ideas are elaborated further in one of the best Haskell posts of all
time, &lt;a
href="https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/"&gt;Parse,
Don’t Validate&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="boolean-blindness"&gt;Boolean Blindness&lt;/h3&gt;
&lt;p&gt;At the heart of it, the previous examples’ cardinal sin was “boolean
blindness”. If we have a predicate like
&lt;code&gt;validUsername :: String -&amp;gt; Bool&lt;/code&gt;, we will branch on that
&lt;code&gt;Bool&lt;/code&gt; once and throw it away. Instead, by having a function like
&lt;code&gt;mkUsername :: String -&amp;gt; Maybe Username&lt;/code&gt;, we &lt;em&gt;keep&lt;/em&gt; the
proof alongside the value for the entire lifetime of the value. We basically
pair the string with its proof forever, making them inseparable.&lt;/p&gt;
&lt;p&gt;There was another example of such a thing earlier: instead of using
&lt;code&gt;null :: [a] -&amp;gt; Bool&lt;/code&gt; and gating a call to &lt;code&gt;mean&lt;/code&gt; with
&lt;code&gt;null&lt;/code&gt;, we instead use
&lt;code&gt;nonEmpty :: [a] -&amp;gt; Maybe (NonEmpty a)&lt;/code&gt;, and pass along the proof
of non-emptiness alongside the value itself. And, for the rest of that list’s
life, it will always be paired with its non-emptiness proof.&lt;/p&gt;
&lt;p&gt;Embracing total depravity means always keeping these proofs together, with
the witnesses bundled with the value itself, because if you don’t, someone is
going to assume it exists when it doesn’t, or drop it unnecessarily.&lt;/p&gt;
&lt;p&gt;Boolean blindness also has another facet, which is where &lt;code&gt;Bool&lt;/code&gt;
itself is not a semantically meaningful type. This is “semantic boolean
blindness”.&lt;/p&gt;
&lt;p&gt;The classic example is
&lt;code&gt;filter :: (a -&amp;gt; Bool) -&amp;gt; [a] -&amp;gt; [a]&lt;/code&gt;. It might sound silly
until it happens to you, but it is pretty easy to mix up if &lt;code&gt;True&lt;/code&gt;
means “keep” or “discard”. After all, a “water filter” only lets water through,
but a “profanity filter” only rejects profanity. Instead, how about
&lt;code&gt;mapMaybe :: (a -&amp;gt; Maybe b) -&amp;gt; [a] -&amp;gt; [b]&lt;/code&gt;? In that case, it
is clear that &lt;code&gt;Just&lt;/code&gt; results are kept, and the &lt;code&gt;Nothing&lt;/code&gt;
results are discarded.&lt;/p&gt;
&lt;p&gt;Sometimes, the boolean is ambiguous as to what it means. You can sort of
interpret the &lt;a href="https://en.wikipedia.org/wiki/Mars_Polar_Lander"&gt;1999
Mars Polar Lander&lt;/a&gt; crash this way. Its functions took a boolean based on the
state of the legs:&lt;/p&gt;
&lt;div class="sourceCode" id="cb22"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb22-1"&gt;&lt;a href="#cb22-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;deployThrusters ::&lt;/span&gt; &lt;span class="dt"&gt;Bool&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and &lt;code&gt;True&lt;/code&gt; and &lt;code&gt;False&lt;/code&gt; were misinterpreted. Instead,
they could have considered semantically meaningful types: (simplified)&lt;/p&gt;
&lt;div class="sourceCode" id="cb23"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb23-1"&gt;&lt;a href="#cb23-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;data&lt;/span&gt; &lt;span class="dt"&gt;LegState&lt;/span&gt; &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="dt"&gt;Extended&lt;/span&gt; &lt;span class="op"&gt;|&lt;/span&gt; &lt;span class="dt"&gt;Retracted&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb23-2"&gt;&lt;a href="#cb23-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb23-3"&gt;&lt;a href="#cb23-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;deployThrusters ::&lt;/span&gt; &lt;span class="dt"&gt;LegState&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note that &lt;code&gt;Maybe&lt;/code&gt; itself is not immune from “semantic blindness” —
if you find yourself using a lot of anonymous combinators like
&lt;code&gt;Maybe&lt;/code&gt; and &lt;code&gt;Either&lt;/code&gt; to get around boolean blindness, be
aware of falling into &lt;a
href="https://github.com/quchen/articles/blob/master/algebraic-blindness.md"&gt;algebraic
blindness&lt;/a&gt;!&lt;/p&gt;
&lt;h3 id="resource-cleanup"&gt;Resource Cleanup&lt;/h3&gt;
&lt;p&gt;Clean-up of finite system resources is another area that is very easy to
assume you have a handle on before it gets out of hand and sneaks up on you.&lt;/p&gt;
&lt;div class="sourceCode" id="cb24"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb24-1"&gt;&lt;a href="#cb24-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;process ::&lt;/span&gt; &lt;span class="dt"&gt;Handle&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="cb24-2"&gt;&lt;a href="#cb24-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb24-3"&gt;&lt;a href="#cb24-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;doTheThing ::&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="cb24-4"&gt;&lt;a href="#cb24-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;doTheThing path &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb24-5"&gt;&lt;a href="#cb24-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  h &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; openFile path &lt;span class="dt"&gt;ReadMode&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb24-6"&gt;&lt;a href="#cb24-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  process h&lt;/span&gt;
&lt;span id="cb24-7"&gt;&lt;a href="#cb24-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  hClose h&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A bunch of things could go wrong —&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You might forget to always &lt;code&gt;hClose&lt;/code&gt; a file handle, and if your
files come at you dynamically, you’re going to run out of file descriptors, or
hold on to locks longer than you should&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;process&lt;/code&gt; throws an exception, we never get to
&lt;code&gt;hClose&lt;/code&gt;, and the same issues happen&lt;/li&gt;
&lt;li&gt;If another thread throws an asynchronous exception (like a thread
cancellation), you have to make sure the close still happens!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The typical solution that other languages (like Python, modern Java) take is
to put everything inside a “block” where quitting the block guarantees the
closure. In Haskell we have the &lt;code&gt;bracket&lt;/code&gt; pattern:&lt;/p&gt;
&lt;div class="sourceCode" id="cb25"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb25-1"&gt;&lt;a href="#cb25-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- strongly discourage using `openFile` and `hClose` directly&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb25-2"&gt;&lt;a href="#cb25-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;withFile ::&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; (&lt;span class="dt"&gt;Handle&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; r) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; r&lt;/span&gt;
&lt;span id="cb25-3"&gt;&lt;a href="#cb25-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;withFile path &lt;span class="ot"&gt;=&lt;/span&gt; bracket (openFile path &lt;span class="dt"&gt;ReadMode&lt;/span&gt;) hClose&lt;/span&gt;
&lt;span id="cb25-4"&gt;&lt;a href="#cb25-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb25-5"&gt;&lt;a href="#cb25-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;doTheThing ::&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="cb25-6"&gt;&lt;a href="#cb25-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;doTheThing path &lt;span class="ot"&gt;=&lt;/span&gt; withFile path &lt;span class="op"&gt;$&lt;/span&gt; \h &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb25-7"&gt;&lt;a href="#cb25-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  process h&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you never use &lt;code&gt;openFile&lt;/code&gt; directly, and always use
&lt;code&gt;withFile&lt;/code&gt;, all file usage is safe!&lt;/p&gt;
&lt;p&gt;But, admittedly, continuations can be annoying to work with. For example,
what if you wanted to safely open a list of files?&lt;/p&gt;
&lt;div class="sourceCode" id="cb26"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb26-1"&gt;&lt;a href="#cb26-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;processAll ::&lt;/span&gt; [&lt;span class="dt"&gt;Handle&lt;/span&gt;] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="cb26-2"&gt;&lt;a href="#cb26-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb26-3"&gt;&lt;a href="#cb26-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;doTheThings ::&lt;/span&gt; [&lt;span class="dt"&gt;FilePath&lt;/span&gt;] &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="cb26-4"&gt;&lt;a href="#cb26-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;doTheThings paths &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="co"&gt;-- uh...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;All of a sudden, not so fun. And what if you had, for example, a Map of
files, like &lt;code&gt;Map Username FilePath&lt;/code&gt;?&lt;/p&gt;
&lt;div class="sourceCode" id="cb27"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb27-1"&gt;&lt;a href="#cb27-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;processAll ::&lt;/span&gt; &lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;Username&lt;/span&gt; &lt;span class="dt"&gt;Handle&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="cb27-2"&gt;&lt;a href="#cb27-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb27-3"&gt;&lt;a href="#cb27-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;doTheThings ::&lt;/span&gt; &lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;Username&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="cb27-4"&gt;&lt;a href="#cb27-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;doTheThings paths &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="co"&gt;-- uh...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In another language, at this point, we might just give up and resort to
manual opening and closing of files.&lt;/p&gt;
&lt;p&gt;But this is Haskell. We have a better solution: cleanup-tracking monads!&lt;/p&gt;
&lt;p&gt;This is a classic usage of &lt;code&gt;ContT&lt;/code&gt; to let you chain bracket-like
continuations:&lt;/p&gt;
&lt;div class="sourceCode" id="cb28"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb28-1"&gt;&lt;a href="#cb28-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;processTwo ::&lt;/span&gt; &lt;span class="dt"&gt;Handle&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;Handle&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="cb28-2"&gt;&lt;a href="#cb28-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb28-3"&gt;&lt;a href="#cb28-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;doTwoThings ::&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="cb28-4"&gt;&lt;a href="#cb28-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;doTwoThings path1 path2 &lt;span class="ot"&gt;=&lt;/span&gt; evalContT &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb28-5"&gt;&lt;a href="#cb28-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    h1 &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="dt"&gt;ContT&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; withFile path1&lt;/span&gt;
&lt;span id="cb28-6"&gt;&lt;a href="#cb28-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    h2 &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="dt"&gt;ContT&lt;/span&gt; &lt;span class="op"&gt;$&lt;/span&gt; withFile path2&lt;/span&gt;
&lt;span id="cb28-7"&gt;&lt;a href="#cb28-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    liftIO &lt;span class="op"&gt;$&lt;/span&gt; processTwo h1 h2&lt;/span&gt;
&lt;span id="cb28-8"&gt;&lt;a href="#cb28-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb28-9"&gt;&lt;a href="#cb28-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;processAll ::&lt;/span&gt; &lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;Username&lt;/span&gt; &lt;span class="dt"&gt;Handle&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="cb28-10"&gt;&lt;a href="#cb28-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb28-11"&gt;&lt;a href="#cb28-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;doTheThings ::&lt;/span&gt; &lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;Username&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="cb28-12"&gt;&lt;a href="#cb28-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;doTheThings paths &lt;span class="ot"&gt;=&lt;/span&gt; evalContT &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb28-13"&gt;&lt;a href="#cb28-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    handles &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="fu"&gt;traverse&lt;/span&gt; (&lt;span class="dt"&gt;ContT&lt;/span&gt; &lt;span class="op"&gt;.&lt;/span&gt; withFile) paths&lt;/span&gt;
&lt;span id="cb28-14"&gt;&lt;a href="#cb28-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    liftIO &lt;span class="op"&gt;$&lt;/span&gt; processAll handles&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;However, using &lt;code&gt;ContT&lt;/code&gt; doesn’t allow you to do things like early
cleanups or canceling cleanup events. It forces us into a last-in, first-out
sort of cleanup pattern. If you want to deviate, this might cause you to, for
convenience, go for manual resource management. However, we have tools for more
fine-grained control, we have things like &lt;em&gt;&lt;a
href="https://hackage.haskell.org/package/resourcet"&gt;resourcet&lt;/a&gt;&lt;/em&gt;
&lt;code&gt;ResourceT&lt;/code&gt;, which lets you manually control the order of clean-up
events, with the guarantee that all of them &lt;em&gt;eventually&lt;/em&gt; happen.&lt;/p&gt;
&lt;div class="sourceCode" id="cb29"&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code class="sourceCode haskell"&gt;&lt;span id="cb29-1"&gt;&lt;a href="#cb29-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;import&lt;/span&gt; &lt;span class="kw"&gt;qualified&lt;/span&gt; &lt;span class="dt"&gt;Data.Map&lt;/span&gt; &lt;span class="kw"&gt;as&lt;/span&gt; &lt;span class="dt"&gt;M&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb29-2"&gt;&lt;a href="#cb29-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb29-3"&gt;&lt;a href="#cb29-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- | Returns set of usernames to close&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb29-4"&gt;&lt;a href="#cb29-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;processAll ::&lt;/span&gt; &lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;Username&lt;/span&gt; &lt;span class="dt"&gt;Handle&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;Set&lt;/span&gt; &lt;span class="dt"&gt;Username&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb29-5"&gt;&lt;a href="#cb29-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb29-6"&gt;&lt;a href="#cb29-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;allocateFile ::&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ResourceT&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; (&lt;span class="dt"&gt;ReleaseKey&lt;/span&gt;, &lt;span class="dt"&gt;Handle&lt;/span&gt;)&lt;/span&gt;
&lt;span id="cb29-7"&gt;&lt;a href="#cb29-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;allocateFile fp &lt;span class="ot"&gt;=&lt;/span&gt; allocate (openFile fp &lt;span class="dt"&gt;ReadMode&lt;/span&gt;) hClose&lt;/span&gt;
&lt;span id="cb29-8"&gt;&lt;a href="#cb29-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id="cb29-9"&gt;&lt;a href="#cb29-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;-- Guarantees that all handles will eventually close, even if `go` crashes&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb29-10"&gt;&lt;a href="#cb29-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;doTheThings ::&lt;/span&gt; &lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;Username&lt;/span&gt; &lt;span class="dt"&gt;FilePath&lt;/span&gt; &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="cb29-11"&gt;&lt;a href="#cb29-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;doTheThings paths &lt;span class="ot"&gt;=&lt;/span&gt; runResourceT &lt;span class="op"&gt;$&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb29-12"&gt;&lt;a href="#cb29-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    releasersAndHandlers &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="fu"&gt;traverse&lt;/span&gt; allocateFile paths&lt;/span&gt;
&lt;span id="cb29-13"&gt;&lt;a href="#cb29-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    go releasersAndHandlers&lt;/span&gt;
&lt;span id="cb29-14"&gt;&lt;a href="#cb29-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;  &lt;span class="kw"&gt;where&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb29-15"&gt;&lt;a href="#cb29-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    &lt;span class="co"&gt;-- normal operation: slowly releases handlers as we drop them&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb29-16"&gt;&lt;a href="#cb29-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ot"&gt;    go ::&lt;/span&gt; &lt;span class="dt"&gt;Map&lt;/span&gt; &lt;span class="dt"&gt;Username&lt;/span&gt; (&lt;span class="dt"&gt;ReleaseKey&lt;/span&gt;, &lt;span class="dt"&gt;Handle&lt;/span&gt;) &lt;span class="ot"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="dt"&gt;ResourceT&lt;/span&gt; &lt;span class="dt"&gt;IO&lt;/span&gt; ()&lt;/span&gt;
&lt;span id="cb29-17"&gt;&lt;a href="#cb29-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;    go currOpen &lt;span class="ot"&gt;=&lt;/span&gt; &lt;span class="kw"&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb29-18"&gt;&lt;a href="#cb29-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      toClose &lt;span class="ot"&gt;&amp;lt;-&lt;/span&gt; liftIO &lt;span class="op"&gt;$&lt;/span&gt; processAll (&lt;span class="fu"&gt;snd&lt;/span&gt; &lt;span class="op"&gt;&amp;lt;$&amp;gt;&lt;/span&gt; currOpen)&lt;/span&gt;
&lt;span id="cb29-19"&gt;&lt;a href="#cb29-19" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      traverse_ (release &lt;span class="op"&gt;.&lt;/span&gt; &lt;span class="fu"&gt;fst&lt;/span&gt;) (currOpen &lt;span class="ot"&gt;`M.restrictKeys`&lt;/span&gt; toClose)&lt;/span&gt;
&lt;span id="cb29-20"&gt;&lt;a href="#cb29-20" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      &lt;span class="kw"&gt;let&lt;/span&gt; newOpen &lt;span class="ot"&gt;=&lt;/span&gt; currOpen &lt;span class="ot"&gt;`M.withoutKeys`&lt;/span&gt; toClose&lt;/span&gt;
&lt;span id="cb29-21"&gt;&lt;a href="#cb29-21" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;      unless (M.null newOpen) &lt;span class="op"&gt;$&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb29-22"&gt;&lt;a href="#cb29-22" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;        go newOpen&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here we get the best of both worlds: the ability to manually close handlers
when they are no longer needed, but also the guarantee that they will eventually
be closed.&lt;/p&gt;
&lt;h2 id="embracing-total-depravity"&gt;Embracing Total Depravity&lt;/h2&gt;
&lt;p&gt;Hopefully these examples, and similar situations, should feel relatable.
We’ve all experienced the biting pain of too much self-trust. Or, too much trust
in our ability to communicate with team members. Or, too much trust in ourselves
6 months from now. The traumas described here &lt;em&gt;should&lt;/em&gt; resonate with you
if you have programmed in any capacity for more than a couple of scripts.&lt;/p&gt;
&lt;p&gt;The doctrine of total depravity does not mean that we don’t recognize the
ability to write sloppy code that works, or that flow states can enable some
great feats. After all, we all program with a certain sense of &lt;em&gt;imago
machinae&lt;/em&gt;. Instead, it means that all such states are &lt;em&gt;fundamentally
unstable&lt;/em&gt; in their nature and will always fail at some point. The “total”
doesn’t mean we are totally cooked, it means this eventual reckoning applies to
&lt;em&gt;all&lt;/em&gt; such shortcuts.&lt;/p&gt;
&lt;p&gt;The problem won’t be solved by “get good”. The problem is solved by utilizing
the tooling we are given, especially since Haskell makes them so accessible and
easy to pull in.&lt;/p&gt;
&lt;p&gt;There’s another layer here that comes as a result of embracing this mindset:
you’ll find that you have more mental space to dedicate to things that actually
matter! Instead of worrying about inconsequential minutiae and details of your
flawed abstractions, you can actually think about your business logic, the flow
of your program, and architecting that castle of beauty I know you are capable
of.&lt;/p&gt;
&lt;h3 id="in-the-age-of-agentic-coding"&gt;In the Age of Agentic Coding&lt;/h3&gt;
&lt;p&gt;Before we end, let’s address the elephant in the room. We’re writing this in
2026, in the middle of one of the biggest revolutions in software engineering in
the history of the field. A lot of people have claimed that types and safety are
now no longer important in the age of LLMs and agentic coding.&lt;/p&gt;
&lt;p&gt;However, these claims seem to miss the fact that the fundamental issue being
addressed here exists both in LLMs and humans: the limited “context window” and
attention. Humans might be barely able to keep a dozen things in our heads, LLMs
might be able to keep a dozen dozen things, but it will still be ultimately
finite. So, the more we can move concerns out of our context window (be it
biological or mechanical), the less crowded our context windows will be, and the
more productive we will be.&lt;/p&gt;
&lt;p&gt;Agentic coding is progressing quickly, and over the past few months I have
been exploring this a lot, using models hands-on. One conclusion I have found
(and, this agrees with everyone else I’ve asked who has been trying the same
thing) is that Haskell’s types, in many ways, are the killer productivity secret
of agentic coding.&lt;/p&gt;
&lt;p&gt;Many of my Haskell coding tasks for an LLM agent often involve:&lt;/p&gt;
&lt;ol type="1"&gt;
&lt;li&gt;How will the types change, or what should the types be?&lt;/li&gt;
&lt;li&gt;Ralph Wiggum loop to death until the program typechecks, using
&lt;code&gt;ghci&lt;/code&gt; and &lt;code&gt;cabal&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And, this isn’t 100% effective, but from personal experience it is much more
effective than the similar situation without typed guardrails for fast feedback,
and without instant compiler feedback. The feedback loop is tighter, the
objectives clearer, the constraints more resilient, the tooling more
utilized.&lt;/p&gt;
&lt;p&gt;I have noticed, also, that my LLM agents often check the types of the APIs
using &lt;code&gt;ghci :type&lt;/code&gt;, and rarely the documentation of the functions
using &lt;code&gt;ghci :docs&lt;/code&gt;. So, any “documentation-based contracts” are
definitely much more likely to explode in your face in this new world than
type-based contracts.&lt;/p&gt;
&lt;p&gt;I’m not sure how quickly LLM-based agentic coding will progress, but I am
sure that the accidental “dropping” of concerns will continue to be a
bottleneck. All of the traits described in this post for humans will continue to
be traits of limited context windows for LLMs.&lt;/p&gt;
&lt;p&gt;If anything, limited “brain space” might be &lt;em&gt;the&lt;/em&gt; bottleneck, for both
humans and LLMs. If provide LLMs with properly “depravity-aware” typed code (and
encourage them to write it by giving them the right iterative tooling), I truly
believe that we have the key to unlocking the full potential of agentic
coding.&lt;/p&gt;
&lt;p&gt;And…not whatever &lt;a
href="https://x.com/rywalker/status/2003525268821188746"&gt;this tweet is&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="the-next-step"&gt;The Next Step&lt;/h3&gt;
&lt;p&gt;Total depravity is all about using types to &lt;em&gt;prevent errors&lt;/em&gt;. However,
you can only go so far with defensive programming and carefully picking the
structure of your types. Sometimes, it feels like you are expending a lot of
energy and human effort just picking the perfectly designed data type, only for
things out of your hand to ruin your typed castle.&lt;/p&gt;
&lt;p&gt;In the next chapter, we’ll see how a little-discussed aspect of Haskell’s
type system gives you a powerful tool for opening your mind to new avenues of
design that were impossible before. At the same time, we’ll see how we can
leverage universal properties of mathematics itself to help us analyze our code
in unexpected ways.&lt;/p&gt;
&lt;p&gt;Let’s explore this further in the next principle of &lt;a
href="https://blog.jle.im/entries/series/+five-point-haskell.html"&gt;Five-Point
Haskell&lt;/a&gt;, &lt;strong&gt;Unconditional Election&lt;/strong&gt;!&lt;/p&gt;
&lt;h2 id="special-thanks"&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="https://www.patreon.com/justinle/overview"&gt;patreon&lt;/a&gt;, Josh Vera! :)&lt;/p&gt;
&lt;p&gt;Also thanks to &lt;a
href="https://www.reddit.com/r/haskell/comments/1qtxnsm/comment/o3889uy"&gt;&lt;em&gt;jackdk&lt;/em&gt;’s
comment&lt;/a&gt; for highlighting extra resources and context that I believe are very
useful and relevant!&lt;/p&gt;</description><author>Justin Le</author><category>Haskell</category><guid isPermaLink="true">https://blog.jle.im/entry/five-point-haskell-part-1-total-depravity.html</guid><pubDate>Mon,  2 Feb 2026 15:06:46 UTC</pubDate><creator>Justin Le</creator><subject>Haskell</subject><date>2026-02-02</date></item><item><title>Advent of Code 2025: Haskell Solution Reflections for all 12 Days</title><link>https://blog.jle.im/entry/advent-of-code-2025.html</link><description>&lt;p&gt;Merry Christmas all! This is my annual &lt;a
href="http://adventofcode.com/"&gt;Advent of Code&lt;/a&gt; post! Advent of Code is a
series of (this year) 12 daily Christmas-themed programming puzzles that are
meant to be fun diversions from your daily life, help you find a bit of whimsy
in your world, give you a chance to explore new ideas and program together with
your friends. I always enjoy discussing creative ways to solve these puzzles
every day, and it’s become a bit of an annual highlight for me and a lot of
others. My favorite part about these puzzles is that they are open ended enough
that there are usually many different interesting ways to solve them — it’s not
like a stressful interview question where you have to recite the obscure
incantation to pass the test. In the past I’ve leveraged &lt;a
href="https://blog.jle.im/entry/alchemical-groups.html"&gt;group theory&lt;/a&gt;, &lt;a
href="https://blog.jle.im/entry/shifting-the-stars.html"&gt;galilean
transformations and linear algebra&lt;/a&gt;, and &lt;a
href="https://blog.jle.im/entry/shuffling-things-up.html"&gt;more group
theory&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Haskell is especially fun for these because if you set up your abstractions
in just the right way, the puzzles seem to solve themselves. It’s a good
opportunity every year to get exposed to different parts of the Haskell
ecosystem! Last year, I moved almost all of my Haskell code to &lt;a
href="https://github.com/mstksg/advent-of-code"&gt;an Advent of Code Megarepo&lt;/a&gt;,
and I also write up my favorite ways to solve each one in the &lt;a
href="https://github.com/mstksg/advent-of-code/wiki"&gt;megarepo wiki&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;All of this year’s 12 puzzles &lt;a
href="https://github.com/mstksg/advent-of-code/wiki/Reflections-2025"&gt;are
here&lt;/a&gt;, but I’ve also included links to each individual one in this post. I’m
also considering expanding some of these into full on blog posts, so be on the
look out, or let me know if there are any that you might want fully expanded!
And if you haven’t, why not try these out yourself? Be sure to drop by the
libera-chat &lt;code&gt;##advent-of-code&lt;/code&gt; channel to discuss any fun ways you
solve them, or any questions! Thanks again to Eric for a great new fresh take on
the event this year!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a
href="https://github.com/mstksg/advent-of-code/blob/main/reflections/2025/day01.md"&gt;Day
1 - Secret Entrance&lt;/a&gt; — The classic Day 1 &lt;code&gt;scanl&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://github.com/mstksg/advent-of-code/blob/main/reflections/2025/day02.md"&gt;Day
2 - Gift Shop&lt;/a&gt; — The super efficient &lt;code&gt;IntSet&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://github.com/mstksg/advent-of-code/blob/main/reflections/2025/day03.md"&gt;Day
3 - Lobby&lt;/a&gt; — &lt;code&gt;StateT&lt;/code&gt; + &lt;code&gt;[]&lt;/code&gt; = backtracking search
monad&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://github.com/mstksg/advent-of-code/blob/main/reflections/2025/day04.md"&gt;Day
4 - Printing Department&lt;/a&gt; — 2D cellular automata&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://github.com/mstksg/advent-of-code/blob/main/reflections/2025/day05.md"&gt;Day
5 - Cafeteria&lt;/a&gt; — The power of the &lt;code&gt;data-interval&lt;/code&gt; library&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://github.com/mstksg/advent-of-code/blob/main/reflections/2025/day06.md"&gt;Day
6 - Trash Compactor&lt;/a&gt; — &lt;code&gt;Data.List&lt;/code&gt; manipulations&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://github.com/mstksg/advent-of-code/blob/main/reflections/2025/day07.md"&gt;Day
7 - Laboratories&lt;/a&gt; — Tying the knot&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://github.com/mstksg/advent-of-code/blob/main/reflections/2025/day08.md"&gt;Day
8 - Playground&lt;/a&gt; — Iterative Clustering&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://github.com/mstksg/advent-of-code/blob/main/reflections/2025/day09.md"&gt;Day
9 - Movie Theater&lt;/a&gt; — &lt;code&gt;IntervalSet&lt;/code&gt; and
&lt;code&gt;IntervalMap&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://github.com/mstksg/advent-of-code/blob/main/reflections/2025/day10.md"&gt;Day
10 - Factory&lt;/a&gt; — Guassian Elimation, Type-safe Mutable Vectors&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://github.com/mstksg/advent-of-code/blob/main/reflections/2025/day11.md"&gt;Day
11 - Reactor&lt;/a&gt; — More Knot Tying and DP!&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://github.com/mstksg/advent-of-code/blob/main/reflections/2025/day12.md"&gt;Day
12 - Christmas Tree Farm&lt;/a&gt; — Counting&lt;/li&gt;
&lt;/ul&gt;</description><author>Justin Le</author><category>Haskell</category><guid isPermaLink="true">https://blog.jle.im/entry/advent-of-code-2025.html</guid><pubDate>Wed, 24 Dec 2025 20:44:05 UTC</pubDate><creator>Justin Le</creator><subject>Haskell</subject><date>2025-12-24</date></item><language>en</language><copyright>Copyright 2020 Justin Le</copyright><managingEditor>justin@jle.im (Justin Le)</managingEditor><webMaster>justin@jle.im (Justin Le)</webMaster><lastBuildDate>Tue,  4 Aug 2026 18:15:09 UTC</lastBuildDate><generator>feed-1.0.0.0 (Sigbjorn Finne)</generator><image><url>https://blog.jle.im/img/site_logo.jpg</url><title>in Code</title><link>https://blog.jle.im/</link></image><creator>Justin Le</creator><language>en</language><rights>Copyright 2020 Justin Le</rights><date>2026-08-04</date><description>Weblog of Justin Le, covering various adventures in programming and explorations in the worlds of computation physics, and knowledge.
</description></channel></rss>