<rss version="2.0">
    <channel>
        <title>welltypedwit.ch</title>
        <link>https://welltypedwit.ch</link>
        <description>welltypedwitch's blog</description>
        <language>en-us</language>
        <lastBuildDate>Sat, 03 Jan 2026 15:51:19 +0100</lastBuildDate>
        <item>
    <title>runST does not prevent resources from escaping</title>
    <link>https://welltypedwit.ch/posts/runst-does-not-prevent-resources-from-escaping.html</link>
    <guid isPermaLink="true">https://welltypedwit.ch/posts/runst-does-not-prevent-resources-from-escaping.html</guid>
    <description><![CDATA[<p> A common pattern one might see in Haskell-adjacent
programming languages is the use of higher-rank types as a mechanism for
delimiting the scope in which certain values can be accessed, similar to
lifetimes or regions in other languages. This is sometimes called “the
<a
href="https://hackage-content.haskell.org/package/base-4.22.0.0/docs/Control-Monad-ST.html#v:runST"><code>runST</code></a>
trick”, after its namesake</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ot">runST ::</span> (<span class="kw">forall</span> s<span class="op">.</span> <span class="dt">ST</span> s a) <span class="ot">-&gt;</span> a </span></code></pre></div>
<p><code>runST</code> enables Haskell to use local mutation without
leaking any of the side effects to the outside. The higher-rank function
parameter ensures that this is safe, and references cannot be accessed
outside the call to <code>runST</code>.</p>
<p>…</p>
<p>You know what. It’s nearly 2026. Why am <em>I</em> explaining this
when you could ask an LLM.<a href="#fn1" class="footnote-ref"
id="fnref1" role="doc-noteref"><sup>1</sup></a> (This is ChatGPT. I’ll
spare you the rambling)</p>
<p>
<div class='block'>
<div class='block-contents'>
<div class='block-contents-inline-code-wrapper'>
</p>
<h3 id="why-this-is-safe">🔐 Why This Is Safe</h3>
<p>The <code>s</code> type parameter ensures referential
transparency:</p>
<p>Mutable references inside an <code>ST</code> block are tagged with
<code>s</code>.</p>
<p>Because <code>s</code> is universally quantified at the call site
(<code>forall s</code>), you cannot return an <code>STRef s ...</code>
out of runST.</p>
<p>This prevents mutation from leaking into the pure world.</p>
<p>So you can’t do this:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="ot">bad ::</span> <span class="dt">STRef</span> s <span class="dt">Int</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>bad <span class="ot">=</span> runST (newSTRef <span class="dv">0</span>)</span></code></pre></div>
<p>The type system prevents it.</p>
<p>
</div>
</div>
</div>
</p>
<p>Okay, that <code>bad</code> snippet does indeed not compile! So
clearly this must be how <code>ST</code> works (and LLMs are always
correct anyway obviously).</p>
<p>Let’s play with this a little and, let’s say, write a safe wrapper
for <a
href="https://hackage-content.haskell.org/package/base-4.22.0.0/docs/Foreign-Marshal-Alloc.html#v:alloca"><code>alloca</code></a>.</p>
<p><code>alloca</code> is unsafe because leaking the <code>Ptr</code>
and accessing it after the end of the continuation leads to
use-after-free.</p>
<p>If we add a type parameter to our pointer type and universally
quantify over it in <code>allocaSafe</code>, then ChatGPT told us that
the pointer cannot escape its continuation. So as long as we make sure
there is no way to get the underlying pointer back out, this should be
safe!<a href="#fn2" class="footnote-ref" id="fnref2"
role="doc-noteref"><sup>2</sup></a></p>
<div class="sourceCode" id="cb3"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- abstract</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">SafePtr</span> s a <span class="ot">=</span> <span class="dt">MkSafePtr</span> (<span class="dt">Ptr</span> a)</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> role <span class="dt">SafePtr</span> nominal representational <span class="co">-- would you have thought of this? ^^</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="ot">peekSafe ::</span> <span class="dt">Storable</span> a <span class="ot">=&gt;</span> <span class="dt">SafePtr</span> s a <span class="ot">-&gt;</span> <span class="dt">IO</span> a</span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>peekSafe (<span class="dt">MkSafePtr</span> pointer) <span class="ot">=</span> peek pointer</span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a><span class="ot">pokeSafe ::</span> <span class="dt">Storable</span> a <span class="ot">=&gt;</span> <span class="dt">SafePtr</span> s a <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">IO</span> ()</span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a>pokeSafe (<span class="dt">MkSafePtr</span> pointer) x <span class="ot">=</span> poke pointer x</span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a><span class="ot">allocaSafe ::</span> <span class="dt">Storable</span> a <span class="ot">=&gt;</span> (<span class="kw">forall</span> s<span class="op">.</span> <span class="dt">SafePtr</span> s a <span class="ot">-&gt;</span> <span class="dt">IO</span> b) <span class="ot">-&gt;</span> <span class="dt">IO</span> b</span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a>allocaSafe f <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a>   pointer <span class="ot">&lt;-</span> malloc</span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a>   result <span class="ot">&lt;-</span> f (<span class="dt">MkSafePtr</span> pointer)</span>
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true" tabindex="-1"></a>   free pointer</span>
<span id="cb3-16"><a href="#cb3-16" aria-hidden="true" tabindex="-1"></a>   <span class="fu">pure</span> result</span></code></pre></div>
<p>If we try this, we can see that the following code <em>is</em>
rightfully rejected</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>allocaSafe <span class="op">@</span><span class="dt">Int</span> \safePtr <span class="ot">-&gt;</span> <span class="fu">pure</span> safePtr</span></code></pre></div>
<p><strong></p>
<pre><code>allocasafe.hs:24:48: error: [GHC-46956]
    • Couldn&#39;t match expected type ‘a0’
                  with actual type ‘SafePtr s Int’
        because type variable ‘s’ would escape its scope</code></pre>
<p></strong></p>
<p>So we’re safe, right?</p>
<h2 id="there-exists-a-problem">There exists a problem</h2>
<p>A seemingly quite unrelated feature of Haskell and many other
languages is called <em>existential types</em>. Whereas a
<em>universally</em> quantified type of the form
<code>forall a. ...</code> can be instantiated to use <em>any</em>
possible type for <code>a</code>, an existential type of the form
<code>exists a. ...</code> uses one specific type <code>a</code> but
doesn’t expose what it is (it only exposes that one such type
“exists”).</p>
<p>Haskell — like most other languages — doesn’t directly expose an
existential quantifier, but it still allows existentials in GADTs. For
example, this defines a type <code>SomeList</code> that contains a list
but doesn’t tell us what the type of its elements is.</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">SomeList</span> <span class="kw">where</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>   <span class="dt">MkSomeList</span><span class="ot"> ::</span> [a] <span class="ot">-&gt;</span> <span class="dt">SomeList</span></span></code></pre></div>
<p>So, if we wrap <code>SafePtr</code> in an existential, we can hide
the <code>s</code> parameter we obtained from
<code>allocaSafe</code>!</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">NotSoSafePtr</span> a <span class="kw">where</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>   <span class="dt">MkNotSoSafePtr</span><span class="ot"> ::</span> <span class="dt">SafePtr</span> s a <span class="ot">-&gt;</span> <span class="dt">NotSoSafePtr</span> a</span></code></pre></div>
<p>Does this mean we can…</p>
<h2 id="use-after-free">Use-after-free</h2>
<div class="sourceCode" id="cb8"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="ot">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>    <span class="dt">MkNotSoSafePtr</span> pointer <span class="ot">&lt;-</span> allocaSafe <span class="op">@</span><span class="dt">Int</span> \safePtr <span class="ot">-&gt;</span> <span class="fu">pure</span> (<span class="dt">MkNotSoSafePtr</span> safePtr)</span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>    pokeSafe pointer <span class="dv">42</span></span></code></pre></div>
<pre><code>$ valgrind safeptr
==230152== Memcheck, a memory error detector
[...]
==230569== Invalid write of size 8
==230569==    at 0x409C10: ghczminternal_GHCziInternalziForeignziStorable_zdfStorableInt1_info (in /home/prophet/temp/safeptr/safeptr)
==230569==  Address 0x4e69200 is 0 bytes inside a block of size 8 free&#39;d
==230569==    at 0x484C8EF: free (vg_replace_malloc.c:989)
==230569==    by 0x409811: ghczminternal_GHCziInternalziForeignziMarshalziAlloc_free1_info (in /home/prophet/temp/safeptr/safeptr)
==230569==  Block was alloc&#39;d at
==230569==    at 0x48497A8: malloc (vg_replace_malloc.c:446)
==230569==    by 0x40974E: ghczminternal_GHCziInternalziForeignziMarshalziAlloc_malloc_info (in /home/prophet/temp/safeptr/safeptr)</code></pre>
<h2 id="so-how-does-st-actually-work">So how does <code>ST</code>
<em>actually</em> work?</h2>
<p>The guarantee <code>ST</code> gives is that an <code>STRef</code> (or
similar) can only be read from or written to <em>in the same
<code>runST</code> invocation that created it</em>.</p>
<p>The higher-rank continuation doesn’t directly contribute to this
safety guarantee at all. It only creates a fresh type-level <em>tag</em>
that uniquely identifies the <code>runST</code> invocation and links the
<code>STRef</code> to it.</p>
<p>Leaking the <code>STRef</code> (or any other resource tagged this
way) is absolutely possible. It just cannot be <em>accessed</em> after
the leakage because any other <code>runST</code> call will use an
<code>ST</code> monad with a different <code>s</code> variable.</p>
<h2 id="bonus-we-dont-even-need-existentials">Bonus: We don’t even need
existentials</h2>
<p>Using regular higher-rank types, we can encode an existential type
like <code>exists s. T s</code> as a rank-2 function
<code>forall r. (forall s. T s -&gt; r) -&gt; r</code>.</p>
<p>And that’s still enough for a use-after-free!<a href="#fn3"
class="footnote-ref" id="fnref3" role="doc-noteref"><sup>3</sup></a></p>
<div class="sourceCode" id="cb10"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">NotSoSafePtr</span> a <span class="ot">=</span> <span class="dt">MkNotSoSafePtr</span> (<span class="kw">forall</span> r<span class="op">.</span> (<span class="kw">forall</span> (<span class="ot">s ::</span> <span class="dt">Type</span>)<span class="op">.</span> <span class="dt">SafePtr</span> s a <span class="ot">-&gt;</span> r) <span class="ot">-&gt;</span> r)</span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a><span class="ot">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>    <span class="dt">MkNotSoSafePtr</span> usePtr <span class="ot">&lt;-</span> allocaSafe <span class="op">@</span><span class="dt">Int</span> \safePtr <span class="ot">-&gt;</span> <span class="fu">pure</span> (<span class="dt">MkNotSoSafePtr</span> \f <span class="ot">-&gt;</span> f safePtr)</span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a>    usePtr \pointer <span class="ot">-&gt;</span> pokeSafe pointer <span class="dv">42</span>    </span></code></pre></div>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>A bit more seriously: I think this works as a decent
proxy for what the average haskeller thinks. At a minimum, its
explanation lines up with what I used to believe.<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>If you’re wondering why I’m defining
<code>allocaSafe</code> in terms of <a
href="https://hackage-content.haskell.org/package/base-4.22.0.0/docs/Foreign-Marshal-Alloc.html#v:malloc"><code>malloc</code></a>
and <a
href="https://hackage-content.haskell.org/package/base-4.22.0.0/docs/Foreign-Marshal-Alloc.html#v:free"><code>free</code></a>
instead of <a
href="https://hackage-content.haskell.org/package/base-4.22.0.0/docs/Foreign-Marshal-Alloc.html#v:alloca"><code>alloca</code></a>,
it’s because <code>alloca</code> actually doesn’t use
<code>malloc</code>! It <a
href="https://hackage-content.haskell.org/package/ghc-internal-9.1401.0/docs/src/GHC.Internal.Foreign.Marshal.Alloc.html#allocaBytesAlignedAndUnchecked">allocates
a byte array on the garbage collected heap and then takes an unmanaged
pointer to its contents</a> because that’s faster than actually going
through <code>malloc</code> and <code>free</code>. So if we leaked the
pointer out of <code>alloca</code>, there would still be a risk of
use-after-free but it would only trigger after a garbage collection and
wouldn’t be on the C heap so it would be hard to detect.<a
href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>The <code>s :: Type</code> kind signature in this type
is necessary, since otherwise GHC will produce a very confusing error
message about how “a newtype constructor cannot contain existential type
variables” because it introduces an implicit kind variable
<code>k</code> that gives <code>MkNotSoSafePtr</code> type
<code>forall {k}. (forall r. (forall (s :: k). SafePtr s a -&gt; r) -&gt; r) -&gt; NotSoSafePtr a</code>,
where the <code>k</code> is an existential.<br />
The <code>s</code> parameter of <code>ST</code> has kind
<code>Type</code>, so this is exactly how it would work in that case and
we don’t gain anything useful from the additional kind polymorphism
anyway.<a href="#fnref3" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
    <pubDate>Wed, 31 Dec 2025 00:00:00 +0100</pubDate>
</item><item>
    <title>Violating memory safety with Haskell's value restriction</title>
    <link>https://welltypedwit.ch/posts/value-restriction.html</link>
    <guid isPermaLink="true">https://welltypedwit.ch/posts/value-restriction.html</guid>
    <description><![CDATA[<p></p>
<p>A common issue in impure ML-style languages with polymorphism and
mutable references is the possibility of <em>polymorphic
references</em>.</p>
<p>In a hypothetical impure language that had both these features, but
no mitigations against polymorphic references, the following code would
be extremely unsafe.</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ot">unsafeCoerce ::</span> a <span class="ot">-&gt;</span> b</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>unsafeCoerce x <span class="ot">=</span> </span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> dangerous <span class="ot">=</span> ref <span class="dt">Nothing</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>    dangerous <span class="op">:=</span> <span class="dt">Just</span> x</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">case</span> dangerous <span class="kw">of</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Nothing</span> <span class="ot">-&gt;</span> <span class="fu">error</span> <span class="st">&quot;unreachable&quot;</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Just</span> y <span class="ot">-&gt;</span> y</span></code></pre></div>
<p>This code creates a reference <code>dangerous</code> with an initial
value of <code>Nothing</code>, writes <code>x</code> to it, and then
reads from it again. But because this language doesn’t prevent
polymorphic references and <code>Nothing</code> has type
<code>forall a. Maybe a</code>, <code>dangerous</code> is actually
<em>generalized</em> to <code>forall a. Ref (Maybe a)</code>. This means
that in the line that writes to it, <code>dangerous</code> is
instantiated to <code>Maybe a</code>, whereas in the line that
<em>reads</em> from it, it is instantiated to <code>Maybe b</code>,
although the value stored in it still has type <code>a</code>, breaking
type safety and consequently memory safety!</p>
<p>Scary, right?</p>
<p>You might think that you could prevent this by just preventing
generalization of reference types, but references can be hidden behind
closures, so languages need a slightly blunter hammer: the <em>value
restriction</em>.</p>
<p>The value restriction says that a let binding can only ever be given
a polymorphic type if its bound expression is syntactically a “value”,
i.e. an expression that obviously will not perform any computation.
<code>5</code> is a value. So is <code>Nothing</code>. But
<code>sqrt 42</code> and (crucially) <code>ref Nothing</code> are
<em>not</em> values and will not be generalized.<a href="#fn1"
class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a></p>
<h2
id="haskells-let-bindings-do-not-have-a-value-restriction.">Haskell’s
let bindings do not have a value restriction.</h2>
<p>So, does this mean that Haskell’s type system is deeply unsound and
we just never noticed?</p>
<p>No! If we translate the original example to Haskell, we will hit a
type error, telling us that <code>dangerous</code> was <em>not</em>
generalized.</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="ot">unsafeCoerce ::</span> a <span class="ot">-&gt;</span> b</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>unsafeCoerce x <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>    dangerous <span class="ot">&lt;-</span> newIORef <span class="dt">Nothing</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>    writeIORef dangerous (<span class="dt">Just</span> x)</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>    result <span class="ot">&lt;-</span> readIORef dangerous</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">case</span> result <span class="kw">of</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Nothing</span> <span class="ot">-&gt;</span> <span class="fu">error</span> <span class="st">&quot;unreachable&quot;</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Just</span> y <span class="ot">-&gt;</span> y</span></code></pre></div>
<!-- ghc output -->
<pre><div style="font-family: "><div><span style="font-weight: bold;">MonadGen.hs:82:19: </span><span style="color: #cd3131; font-weight: bold;">error</span><span style="font-weight: bold;">: [</span><span style="font-weight: bold; text-decoration: underline;">GHC-25897</span><span style="font-weight: bold;">]</span><span>
</span></div><div><span></span><span style="font-weight: bold;">    • Couldn't match type ‘a’ with ‘b’</span></div><div><span></span><span style="font-weight: bold;">      Expected: IO b</span></div><div><span style="font-weight: bold;">        Actual: IO a</span></div></div></pre>
<!-- /ghc output -->
<p>But the interesting question here is: <em>Why</em> was it not
generalized? To answer that, we will have to take a small step back.</p>
<h2 id="what-even-is-an-io">What even is an IO</h2>
<p>The important detail in this Haskell code is that
<code>dangerous</code> was <em>not</em> bound in a <code>let</code>
binding. It was bound in a monadic <code>do</code>-binding.</p>
<p><code>IO</code> is famously a monad, so a <code>do</code>-binding
like this is just syntactic sugar for an application of
<code>(&gt;&gt;=)</code>, which (specialized to <code>IO</code>) has the
following type.</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="ot">(&gt;&gt;=) ::</span> <span class="kw">forall</span> a b<span class="op">.</span> <span class="dt">IO</span> a <span class="ot">-&gt;</span> (a <span class="ot">-&gt;</span> <span class="dt">IO</span> b) <span class="ot">-&gt;</span> <span class="dt">IO</span> b</span></code></pre></div>
<p>So the value passed to the continuation (corresponding to the
variable in the let binding) has whatever type is wrapped
<em>inside</em> the <code>IO</code> type constructor of its first
argument.</p>
<p>Now, <code>newIORef Nothing</code> can itself have a polymorphic
type.</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>newIORef <span class="dt">Nothing</span><span class="ot"> ::</span> <span class="kw">forall</span> a<span class="op">.</span> <span class="dt">IO</span> (<span class="dt">IORef</span> (<span class="dt">Maybe</span> a))</span></code></pre></div>
<p>However, notice that the polymorphic forall quantifier occurs
<em>outside</em> the <code>IO</code>! This means that the value passed
to the continuation of <code>(newIORef Nothing &gt;&gt;=)</code> will
always have type <code>IORef _</code> and therefore be
<em>monomorphic</em>. We can instantiate the <code>a</code> with
<code>forall a. Maybe a</code>, but that only gives us a perfectly safe
<code>IORef (forall a. Maybe a)</code><a href="#fn2"
class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a>,
<em>not</em> a <code>forall a. IORef (Maybe a)</code>.</p>
<p>That’s the magic! The placement of the <code>IO</code> in the types
prevents giving <code>dangerous</code> a polymorphic type.</p>
<p>What I really want you to appreciate here is just how similar this is
to the traditional value restriction. If we’re allowed to do arbitrary
effects, we might create a polymorphic reference, so ML bans all let
bindings that look like they might perform effects, whereas Haskell
already has a distinction between pure and effectful let bindings
(<code>&gt;&gt;=</code>) and just needs to prevent the second group from
being generalized.</p>
<h2 id="generalizable-monads">Generalizable Monads</h2>
<p>This hopefully all seems reasonable so far. <code>IO</code> can
create mutable references so we need to prevent it from generalizing
them and that’s why the monadic interface imposes something resembling
the value restriction.</p>
<p>But… <code>IO</code> is not the only monad. If we look at <a
href="https://hackage.haskell.org/package/base-4.21.0.0/docs/Data-Functor-Identity.html#t:Identity"><code>Identity</code></a>,
it’s a monad that quite literally does nothing, so a
<code>do</code>-binding in <code>Identity</code> is just a pure
<code>let</code>-binding. Shouldn’t we at least be able to generalize
<code>do</code>-bindings in a trivial monad like this?</p>
<p>Let’s think through what that would mean. Above, we couldn’t
generalize <code>newIORef Nothing</code> because it had type
<code>forall a. IO (IORef (Maybe a))</code> with the <code>forall</code>
on the <em>outside</em>. If it had type
<code>IO (forall a. IORef (Maybe a))</code>, we could instantiate the
<code>a</code> parameter to <code>(&gt;&gt;=)</code> with
<code>forall a. IORef (Maybe a)</code> and therefore generalize it.</p>
<p>Coming back to <code>Identity</code>, we can generalize Identity
bindings, if for any context <code>f</code>
(e.g. <code>f ~ IORef</code>), we can turn something of type
<code>forall a. Identity (f a)</code> into something of type
<code>Identity (forall a. f a)</code>. More generally, we can define a
type class for monads where we can generalize bindings this way.</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> (<span class="dt">Monad</span> m) <span class="ot">=&gt;</span> <span class="dt">MonadGen</span> m <span class="kw">where</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="ot">    generalize ::</span> <span class="kw">forall</span> f<span class="op">.</span> (<span class="kw">forall</span> a<span class="op">.</span> m (f a)) <span class="ot">-&gt;</span> m (<span class="kw">forall</span> a<span class="op">.</span> f a)</span></code></pre></div>
<p>So, can we define this for Identity? Yes!<a href="#fn3"
class="footnote-ref" id="fnref3" role="doc-noteref"><sup>3</sup></a></p>
<div class="sourceCode" id="cb6"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">MonadGen</span> <span class="dt">Identity</span> <span class="kw">where</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>    generalize m <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>        <span class="kw">let</span> (<span class="dt">Identity</span> x) <span class="ot">=</span> m</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Identity</span> x</span></code></pre></div>
<p>If we use this new fancy function, our monadic bindings in
<code>Identity</code> can be just as powerful as regular let bindings!
(though a little less convenient since we need newtypes)</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">Endo</span> a <span class="ot">=</span> <span class="dt">Endo</span> (a <span class="ot">-&gt;</span> a)</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="ot">applyEndo ::</span> <span class="dt">Endo</span> a <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> a</span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>applyEndo (<span class="dt">Endo</span> f) x <span class="ot">=</span> f x</span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a><span class="ot">blah ::</span> <span class="dt">Identity</span> (<span class="dt">Bool</span>, <span class="dt">Char</span>)</span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a>blah <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- f :: forall a. Endo a &lt;- pure (Endo (\x -&gt; x))  -- fails</span></span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a><span class="ot">    f ::</span> <span class="kw">forall</span> a<span class="op">.</span> <span class="dt">Endo</span> a <span class="ot">&lt;-</span> generalize (<span class="fu">pure</span> (<span class="dt">Endo</span> (\x <span class="ot">-&gt;</span> x))) <span class="co">-- succeeds</span></span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a>    <span class="fu">pure</span> (applyEndo f <span class="dt">True</span>, applyEndo f <span class="ch">&#39;a&#39;</span>)</span></code></pre></div>
<p>Nice! Since we made this a type class, you’re probably already
wondering which other monads we can implement it for. Turns out, there
are actually quite a few! For reasons that will become apparent in a
moment, let’s look at…</p>
<h2 id="statestate">State<a href="#fn4" class="footnote-ref" id="fnref4"
role="doc-noteref"><sup>4</sup></a></h2>
<p>The <code>State</code> monad in Haskell is defined as<a href="#fn5"
class="footnote-ref" id="fnref5" role="doc-noteref"><sup>5</sup></a></p>
<div class="sourceCode" id="cb8"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">State</span> s a <span class="ot">=</span> <span class="dt">State</span> (s <span class="ot">-&gt;</span> (s, a))</span></code></pre></div>
<p>In order to simulate mutable state, this definition represents
computations as functions that take the current state as a parameter and
return a new state value. As it turns out, if we just keep plumbing
those state values around, nothing stops us from binding the result of
this function in a let binding and thereby generalizing the result of
the computation!</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">MonadGen</span> (<span class="dt">State</span> s) <span class="kw">where</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>    generalize m <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>        <span class="kw">let</span> (<span class="dt">State</span> f) <span class="ot">=</span> m</span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>        <span class="dt">State</span> \s <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>            <span class="kw">let</span> (s&#39;, result) <span class="ot">=</span> f s</span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a>            (s&#39;, result)</span></code></pre></div>
<p>Great! So it seems like many pure monads do support binding
generalization. Then there must be something about the internal
structure of <code>IO</code> that is somehow special and prevents us
from implementing <code>MonadGen IO</code>, right?</p>
<p>Right?</p>
<h2 id="what-is-an-io-really">What is an IO, <em>really</em>?</h2>
<p>A popular metaphor for impure functions in pure languages is that
instead of modifying the world around it, a function like
<code>putStrLn</code> essentially takes the real world as a parameter
and returns a modified version of it where a string has been written to
<code>stdout</code>. Interestingly enough, this is very close to how
<code>IO</code> works internally!</p>
<div class="sourceCode" id="cb10"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">IO</span> a <span class="ot">=</span> <span class="dt">IO</span> (<span class="dt">State</span><span class="op">#</span> <span class="dt">RealWorld</span> <span class="ot">-&gt;</span> (<span class="op">#</span> <span class="dt">State</span><span class="op">#</span> <span class="dt">RealWorld</span>, a <span class="op">#</span>))</span></code></pre></div>
<p>Of course, we cannot literally modify the real world as a pure value,
so internally, <code>putStrLn</code> is an actual, impure function.</p>
<p>But the <code>State#</code> values still act both as capabilities
(ensuring that impure functions can only be called from impure
functions) and data dependencies (to ensure that impure functions are
evaluated in the correct order despite laziness).</p>
<p>Using this constructor directly can be unsafe, since the illusion of
purely modifying the real world (and <code>IO</code>’s sequencing
guarantees) only apply if the <code>State# RealWorld</code> tokens are
passed around <em>linearly</em>, i.e. are never duplicated or dropped.
However, if we manually make sure to uphold this invariant and we don’t
use any further GHC internals, common knowledge suggests that we should
be safe.</p>
<h2 id="that-type-definition-looks-familiar">That type definition looks
familiar</h2>
<p>It uses an unboxed tuple instead of a boxed one and is specialized to
(zero-sized) unboxed <code>State# RealWorld</code> tokens, but otherwise
<code>IO</code> is really just a state monad! So, if we were able to
implement <code>MonadGen</code> for <code>State</code>, shouldn’t we be
able to implement it for <code>IO</code> as well?</p>
<p>If we tried to copy the <code>State</code> definition directly, we
would hit a quite awkwardly phrased error message<a href="#fn6"
class="footnote-ref" id="fnref6" role="doc-noteref"><sup>6</sup></a></p>
<div class="sourceCode" id="cb11"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">MonadGen</span> <span class="dt">IO</span> <span class="kw">where</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>    generalize m <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>        <span class="kw">let</span> (<span class="dt">IO</span> f) <span class="ot">=</span> m</span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>        <span class="dt">IO</span> \s <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>            <span class="kw">let</span> (<span class="op">#</span> s&#39;, result <span class="op">#</span>) <span class="ot">=</span> f s</span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>            (<span class="op">#</span> s&#39;, result <span class="op">#</span>)</span></code></pre></div>
<pre><div style="font-family: "><div><span></span><span style="font-weight: bold;">MonadGen.hs:51:17: </span><span style="color: #cd3131; font-weight: bold;">error</span><span style="font-weight: bold;">: [</span><span style="font-weight: bold; text-decoration: underline;">GHC-20036</span><span style="font-weight: bold;">]</span></div><div><span></span><span style="font-weight: bold;">    You can't mix polymorphic and unlifted bindings:</span></div><div><span></span><span style="font-weight: bold;">      (# s', result #) = f s</span></div><div><span style="font-weight: bold;">    Suggested fix: Add a type signature.</span></div></div></pre>
<p>Unfortunately, the suggested fix doesn’t help us. Giving
<code>result</code> a polymorphic type is the whole point here!</p>
<p>Fortunately, we can just box the <code>State# RealWorld</code> token
first and avoid the issue.</p>
<div class="sourceCode" id="cb12"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">BoxedState</span> s <span class="ot">=</span> <span class="dt">BoxedState</span> {<span class="ot">state ::</span> <span class="dt">State</span><span class="op">#</span> s}</span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a><span class="ot">liftState ::</span> (<span class="op">#</span> <span class="dt">State</span><span class="op">#</span> s, b <span class="op">#</span>) <span class="ot">-&gt;</span> (<span class="dt">BoxedState</span> s, b)</span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>liftState (<span class="op">#</span> s, b <span class="op">#</span>) <span class="ot">=</span> (<span class="dt">BoxedState</span> s, b)</span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">MonadGen</span> <span class="dt">IO</span> <span class="kw">where</span></span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a>    generalize m <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a>        <span class="kw">let</span> (<span class="dt">IO</span> f) <span class="ot">=</span> m</span>
<span id="cb12-9"><a href="#cb12-9" aria-hidden="true" tabindex="-1"></a>        <span class="dt">IO</span> \s <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb12-10"><a href="#cb12-10" aria-hidden="true" tabindex="-1"></a>            <span class="kw">let</span> (boxedState, result) <span class="ot">=</span> liftState (f s)</span>
<span id="cb12-11"><a href="#cb12-11" aria-hidden="true" tabindex="-1"></a>            <span class="kw">let</span> (<span class="dt">BoxedState</span>{state}) <span class="ot">=</span> boxedState</span>
<span id="cb12-12"><a href="#cb12-12" aria-hidden="true" tabindex="-1"></a>            (<span class="op">#</span> state, result <span class="op">#</span>)</span></code></pre></div>
<p>And this compiles! So, does that mean…</p>
<h2 id="yes">Yes!</h2>
<div class="sourceCode" id="cb13"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">MaybeRef</span> a <span class="ot">=</span> <span class="dt">MaybeRef</span> (<span class="dt">IORef</span> (<span class="dt">Maybe</span> a))</span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a><span class="ot">unsafeCoerceIO ::</span> <span class="kw">forall</span> a b<span class="op">.</span> a <span class="ot">-&gt;</span> <span class="dt">IO</span> b</span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>unsafeCoerceIO x <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a>    maybeRef <span class="ot">&lt;-</span> generalize (<span class="dt">MaybeRef</span> <span class="op">&lt;$&gt;</span> newIORef <span class="dt">Nothing</span>)</span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> <span class="dt">MaybeRef</span> ref <span class="ot">=</span> maybeRef</span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a>    writeIORef ref (<span class="dt">Just</span> x)</span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a>    readIORef ref <span class="op">&gt;&gt;=</span> \<span class="kw">case</span></span>
<span id="cb13-9"><a href="#cb13-9" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Just</span> y <span class="ot">-&gt;</span> <span class="fu">pure</span> y</span>
<span id="cb13-10"><a href="#cb13-10" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Nothing</span> <span class="ot">-&gt;</span> <span class="fu">error</span> <span class="st">&quot;unreachable&quot;</span></span></code></pre></div>
<p><span></span></p>
<div class="sourceCode" id="cb14"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> unsafeCoerceIO <span class="op">@</span>_ <span class="op">@</span><span class="dt">String</span> <span class="fu">id</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;fish: Job 1, &#39;ghci MonadGen.hs&#39; terminated by signal SIGSEGV (Address boundary error)</span></span></code></pre></div>
<h2 id="conclusion">Conclusion</h2>
<p>What I want you to take away from this is that</p>
<ul>
<li>Despite its purity, Haskell <em>does</em> need something resembling
the value restriction, just like every other ML with references.</li>
<li>However, this value restriction is only given by the monadic
interface of <code>IO</code> and <em>not</em> inherent to its
definition.</li>
<li>Contrary to popular belief, unwrapping the <code>IO</code>
constructor is deeply unsafe and can violate memory safety, even if
<code>State#</code> tokens are never duplicated or dropped.</li>
</ul>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>This is quite a strong restriction, so languages like
OCaml use <a
href="https://caml.inria.fr/pub/papers/garrigue-value_restriction-fiwflp04.pdf">a
slightly more flexible approach</a>. The core idea of restricting
generalization of function calls that don’t clearly return values that
are safe to generalize remains though.<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>It’s just a reference that can only store values of the
form <code>Nothing</code>, <code>Just undefined</code> or
<code>undefined</code>.<a href="#fnref2" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>Even though it looks a little strange, the let binding
to bind <code>Identity x</code> is necessary! Directly matching on
<code>m</code> wouldn’t allow it to be generalized. This also relies on
<code>MonoLocalBinds</code> (implied by <code>TypeFamilies</code>,
<code>GADTs</code> and <code>LinearTypes</code>) being off for this
module, since that would prevent generalization of the let binding that
mentions a variable from an outer scope.<a href="#fnref3"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn4"><p>If you know a little about GHC internals, you might see
where I’m going with this.<a href="#fnref4" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn5"><p>The <a
href="https://hackage-content.haskell.org/package/transformers-0.6.2.0/docs/Control-Monad-Trans-State-Strict.html#t:State">actual
definition</a> in <code>transformers</code> is a type synonym for
<code>StateT Identity</code>. It’s possible to define a
<code>MonadGen</code> instance for <code>StateT m</code> (provided
<code>m</code> implements <code>MonadGen</code>), but that only detracts
from the main point, so we will use the non-transformer
<code>State</code>. I’ve also changed the argument order to make it a
little more sensible.<a href="#fnref5" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn6"><p>That’s how you know you’re using the fun parts of GHC<a
href="#fnref6" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
    <pubDate>Sat, 17 May 2025 00:00:00 +0200</pubDate>
</item><item>
    <title>Newtypes Are Better Than Abstract Type Synonyms</title>
    <link>https://welltypedwit.ch/posts/newtypes.html</link>
    <guid isPermaLink="true">https://welltypedwit.ch/posts/newtypes.html</guid>
    <description><![CDATA[<p> One of OCaml’s flagship features is what they call
“abstract types”. In essence, this lets programmers declare a type, even
as a type synonym inside a module and, by hiding its definition in the
signature, make it appear abstract to the outside world.</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode ocaml"><code class="sourceCode ocaml"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">module</span> Unix : <span class="kw">sig</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">type</span> file_descr <span class="co">(* abstract *)</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">val</span> open_file : <span class="dt">string</span> -&gt; file_descr</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">val</span> read_file : file_descr -&gt; <span class="dt">string</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="kw">end</span> = <span class="kw">struct</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">type</span> file_descr = <span class="dt">int</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>    </span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> open_file file = some_internal_c_code_that_returns_an_int file</span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>    </span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> read_file file_descr = some_internal_c_code_that_takes_an_int file_descr</span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a><span class="kw">end</span></span></code></pre></div>
<p>From the perspective of writing modules like this, this feature is
great! It means that the code inside the module can treat the type
exactly as its underlying type and make whatever assumptions it needs to
make without any additional ceremony because, inside the module, they
<em>are</em> exactly equal!<br />
But from the outside, you get a fully abstract type that users can make
no assumptions about other than what you expose to them via the module
signature.</p>
<h2 id="newtypes">Newtypes</h2>
<p>Since Haskell’s module system is significantly less powerful than
OCaml’s, it cannot implement abstract types in the same way. Instead,
abstract types are implemented as data types or newtypes that don’t
export their constructor.</p>
<p>While this achieves roughly the same effect, it means that any code
inside the module that uses the underlying type needs to wrap and unwrap
the newtype constructors <em>everywhere</em>.</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">module</span> <span class="dt">Unix</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>  ( <span class="dt">FileDescr</span> <span class="co">-- does not export its constructor (MkFileDescr)</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>  , openFile</span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>  , <span class="fu">readFile</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>  )</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">FileDescr</span> <span class="ot">=</span> <span class="dt">MkFileDescr</span> <span class="dt">Int</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a><span class="ot">openFile ::</span> <span class="dt">FilePath</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> <span class="dt">FileDescr</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>openFile path <span class="ot">=</span> <span class="dt">MkFileDescr</span> (someInternalCCodeThatReturnsAnInt path)</span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a><span class="fu">readFile</span><span class="ot"> ::</span> <span class="dt">FileDescr</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> <span class="dt">String</span></span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a>readFIle (<span class="dt">MkFileDescr</span> fileDescr) <span class="ot">=</span> someInternalCCodeThatTakesAnInt fileDescr</span></code></pre></div>
<p>With a small example like this, the amount of wrapping/unwrapping
might not seem all that important, but in real code, these can add up
and get quite annoying! Implementing modules with abstract type synonyms
is much more convenient.</p>
<h2 id="wait-thats-not-what-you-said-in-the-title">Wait that’s not what
you said in the title!</h2>
<p>While I honestly believe that <em>inside</em> a module, abstract type
synonyms are much more convenient than abstract types implemented
through newtypes, they have one fatal flaw that already appears in OCaml
and would be significantly exacerbated in a language with type
classes:</p>
<p>Abstract type synonyms <strong>hide too much
information</strong>.</p>
<p>In particular, they hide the information that an abstract type is
<strong>not</strong> equal to another type.</p>
<p>To demonstrate this, let’s look at a (slightly contrived) example
involving GADTs in both OCaml and Haskell.</p>
<div class="sourceCode" id="cb3"><pre
class="sourceCode ocaml"><code class="sourceCode ocaml"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> _ some_gadt =</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>   | AnInt : <span class="dt">int</span> -&gt; <span class="dt">int</span> some_gadt</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>   | SomethingElse : &#39;a -&gt; &#39;a some_gadt</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> some_pattern_match : file_descr some_gadt -&gt; file_descr =</span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">function</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>    | SomethingElse descr -&gt; descr</span></code></pre></div>
<p><span></span></p>
<div class="sourceCode" id="cb4"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">SomeGADT</span> a <span class="kw">where</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>    <span class="dt">AnInt</span><span class="ot"> ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">SomeGADT</span> <span class="dt">Int</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>    <span class="dt">SomethingElse</span><span class="ot"> ::</span> a <span class="ot">-&gt;</span> <span class="dt">SomeGADT</span> a</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a><span class="ot">somePatternMatch ::</span> <span class="dt">SomeGADT</span> <span class="dt">FileDescr</span> <span class="ot">-&gt;</span> <span class="dt">FileDescr</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>somePatternMatch (<span class="dt">SomethingElse</span> descr) <span class="ot">=</span> descr</span></code></pre></div>
<p>Seems pretty harmless so far, doesn’t it?</p>
<p>Well, if you tried to run this, you would see that only the OCaml
version would complain that you haven’t provided a case for
<code>AnInt</code>!</p>
<p>And if you think about it, that seems wrong! <code>AnInt _</code> has
type <code>int some_gadt</code> and you have a
<code>file_descr some_gadt</code> here so it couldn’t possibly be
<code>AnInt _</code>, could it?</p>
<h2 id="yes-it-could">Yes, it could!</h2>
<p>Inside the <code>Unix</code> module, <code>file_descr</code>
<em>is</em> equal to <code>int</code>, so
<code>file_descr some_gadt</code> is also equal to
<code>int some_gadt</code>!</p>
<p>The compiler needs to assume that you could have created an
<code>AnInt _</code> inside that module and exposed it as a
<code>file_descr some_gadt</code> that you’re now passing to
<code>some_pattern_match</code>.</p>
<p>Even worse, because the compiler cannot leak the fact that
<code>file_descr</code> is an <code>int</code> internally (which would
defeat the whole point of abstract types), it cannot make any
assumptions about <em>any</em> other types! It also cannot assume that a
<code>file_descr some_gadt</code> is not a <code>string some_gadt</code>
or a <code>float some_gadt</code>, etc.</p>
<p>So as long as you have abstract type synonyms in the language, the
compiler can never eliminate any pattern matches involving abstract
types.</p>
<p>Newtypes avoid this issue because <code>FileDescr</code> and
<code>Int</code> are <em>always</em> separate types. It’s just that they
can be converted seamlessly without runtime costs. <a href="#fn1"
class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a></p>
<h2 id="what-was-that-about-type-classes">What was that about type
classes?</h2>
<p>In a language with globally coherent type classes, type class
instances cannot be implemented on abstract type synonyms.</p>
<p>Global coherence means that every type class instance for a type is
equal, so it doesn’t matter where you get your <code>Eq Int</code>
instance from.</p>
<p>This is important for types like Haskell’s <a
href="https://www.stackage.org/haddock/lts-22.37/containers-0.6.7/Data-Map.html">Map</a>,
a binary search tree whose structure depends on the <code>Ord</code>
instance of its keys.</p>
<p>If you could create a <code>Map</code> with one instance of, say,
<code>Ord Int</code> and then later access it with a different one, you
could violate the internal invariants of the <code>Map</code> data
structure.</p>
<p>And if you could implement type class instances on abstract type
synonyms, you could do exactly that!</p>
<div class="sourceCode" id="cb5"><pre
class="sourceCode ocaml"><code class="sourceCode ocaml"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>instance Ord <span class="dt">int</span> = ...</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="kw">module</span> Unix : <span class="kw">sig</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">type</span> file_descr</span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">val</span> some_map : (file_descr, <span class="dt">string</span>) map</span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">val</span> some_descriptor : file_descr</span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a><span class="kw">end</span> = <span class="kw">struct</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>    <span class="kw">type</span> t = <span class="dt">int</span></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> some_map = <span class="dt">Map</span>.from_list [(<span class="dv">1</span>, <span class="st">&quot;a&quot;</span>), (<span class="dv">2</span>, <span class="st">&quot;b&quot;</span>), (<span class="dv">3</span>, <span class="st">&quot;c&quot;</span>)]</span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> some_descriptor = <span class="dv">2</span></span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a><span class="kw">end</span></span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a>instance Ord file_descr = ...</span>
<span id="cb5-14"><a href="#cb5-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-15"><a href="#cb5-15" aria-hidden="true" tabindex="-1"></a><span class="dt">Map</span>.lookup Unix.some_map Unix.some_descriptor</span></code></pre></div>
<p>The <code>Map.from_list</code> call uses the <code>Ord int</code>
instance defined above, but the <code>Map.lookup</code> call uses the
second <code>Ord file_descr</code> instance which might be
different!</p>
<p>Therefore, in a language like this, it would be impossible to
implement any type class instances for any abstract type, including file
descriptors, stacks, and many more.</p>
<p>And that’s why newtypes are better than abstract type synonyms!</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>One caveat you might be thinking of is that <a
href="https://www.stackage.org/haddock/lts-22.37/base-4.18.2.1/Data-Coerce.html#t:Coercible">Coercible</a>
lets you convert a <code>[Int]</code> to a <code>[FileDescr]</code>.
However, for exactly the reasons discussed here, GADTs like this always
have <code>type role nominal</code> so Coercible will not allow you to
convert a <code>SomeGADT Int</code> to a
<code>SomeGADT FileDescr</code>.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
    <pubDate>Mon, 07 Oct 2024 00:00:00 +0200</pubDate>
</item><item>
    <title>Blazingly Fast™ Type Class Resolution with Tries</title>
    <link>https://welltypedwit.ch/posts/classTries.html</link>
    <guid isPermaLink="true">https://welltypedwit.ch/posts/classTries.html</guid>
    <description><![CDATA[<p></p>
<p>One of the more fundamental hurdles when implementing type classes is
instance resolution. A programmer might write any possible number of
instances for a given class, so how do we find the one we are looking
for?</p>
<p>For the remaining examples, let’s assume that our program contains
the following instances</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">C</span>(a)</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">C</span>(<span class="dt">Int</span>)</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">C</span>(<span class="dt">List</span>(<span class="dt">Bool</span>))</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">C</span>(<span class="dt">List</span>(<span class="dt">String</span>))</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="kw">forall</span> a<span class="op">.</span> <span class="dt">C</span>((a, <span class="dt">Int</span>))</span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="kw">forall</span> a<span class="op">.</span> <span class="dt">C</span>((<span class="dt">Bool</span>, a))</span></code></pre></div>
<p>Now, the easiest way to find an instance for a constraint, say
<code>C((String, Int))</code>, is to linearly search through every
single instance until one matches the constraint arguments.</p>
<p>For example, in this case, we would try (and fail) to match every
single instance until we hit <code>forall a. C((a, Int))</code>.</p>
<p>Somewhat surprisingly, this is actually the strategy GHC uses.<a
href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a> But with a large number of
instances, this is not exactly efficient and as it turns out, with a
little effort, we can do much better!</p>
<h2 id="we-need-to-trie-hardersorry">We need to trie harder<a
href="#fn2" class="footnote-ref" id="fnref2"
role="doc-noteref"><sup>2</sup></a></h2>
<p>If you already know what tries are, the context in which you learned
about them was probably very different.</p>
<p>The traditional use case for tries is matching sequences of text. The
prime example here is text auto-completion. Imagine that our set of
valid words consists of
<code>["dog", "cat", "car", "candle",  "dune", "can", "current", "dose", "bat", "category"]</code>
and the user has typed in <code>"cat"</code>. How do we find the set of
valid completions?</p>
<p>Just like above, we could linearly walk through the set of valid
words and pick out all the ones that contain the prefix
<code>cat</code>. For reasons that will become apparent soon, we can
visualize this flat set of all valid words as a flat tree.</p>
<p><div class="dot-output"><?xml version="1.0" encoding="UTF-8" standalone="no"?>

<!-- Generated by graphviz version 14.0.5 (0)
 -->
<!-- Pages: 1 -->
<svg width="886pt" height="116pt"
 viewBox="0.00 0.00 886.00 116.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 112)">
<g id="node1" class="node">
<title></title>
<ellipse fill="none"  cx="404.64" cy="-90" rx="27" ry="18"/>
</g>
<!-- dog -->
<g id="node2" class="node">
<title>dog</title>
<ellipse fill="none"  cx="29.64" cy="-18" rx="29.64" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="29.64" y="-13.32" font-family="Times,serif" font-size="14.00">dog</text>
</g>
<!-- &#45;&gt;dog -->
<g id="edge1" class="edge">
<title>&#45;&gt;dog</title>
<path fill="none"  d="M377.56,-87.08C319.79,-82.47 180.61,-68.65 68.64,-36 66.79,-35.46 64.9,-34.85 63.02,-34.2"/>
<polygon   points="64.37,-30.97 53.78,-30.61 61.84,-37.49 64.37,-30.97"/>
</g>
<!-- cat -->
<g id="node3" class="node">
<title>cat</title>
<ellipse fill="none"  cx="104.64" cy="-18" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="104.64" y="-13.32" font-family="Times,serif" font-size="14.00">cat</text>
</g>
<!-- &#45;&gt;cat -->
<g id="edge2" class="edge">
<title>&#45;&gt;cat</title>
<path fill="none"  d="M377.86,-85.81C329.54,-79.59 224.96,-63.91 140.64,-36 139.08,-35.48 137.5,-34.92 135.92,-34.31"/>
<polygon   points="137.57,-31.21 127,-30.54 134.84,-37.66 137.57,-31.21"/>
</g>
<!-- car -->
<g id="node4" class="node">
<title>car</title>
<ellipse fill="none"  cx="176.64" cy="-18" rx="27.01" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="176.64" y="-13.32" font-family="Times,serif" font-size="14.00">car</text>
</g>
<!-- &#45;&gt;car -->
<g id="edge3" class="edge">
<title>&#45;&gt;car</title>
<path fill="none"  d="M379.04,-83.41C341.81,-74.96 270.83,-57.59 212.64,-36 211.1,-35.43 209.54,-34.82 207.97,-34.18"/>
<polygon   points="209.65,-31.09 199.08,-30.29 206.84,-37.51 209.65,-31.09"/>
</g>
<!-- candle -->
<g id="node5" class="node">
<title>candle</title>
<ellipse fill="none"  cx="265.64" cy="-18" rx="43.84" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="265.64" y="-13.32" font-family="Times,serif" font-size="14.00">candle</text>
</g>
<!-- &#45;&gt;candle -->
<g id="edge4" class="edge">
<title>&#45;&gt;candle</title>
<path fill="none"  d="M383.53,-78.37C362.17,-67.61 328.7,-50.76 302.87,-37.75"/>
<polygon   points="304.54,-34.67 294.04,-33.3 301.39,-40.93 304.54,-34.67"/>
</g>
<!-- dune -->
<g id="node6" class="node">
<title>dune</title>
<ellipse fill="none"  cx="363.64" cy="-18" rx="35.95" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="363.64" y="-13.32" font-family="Times,serif" font-size="14.00">dune</text>
</g>
<!-- &#45;&gt;dune -->
<g id="edge5" class="edge">
<title>&#45;&gt;dune</title>
<path fill="none"  d="M395.13,-72.76C390.38,-64.67 384.53,-54.66 379.15,-45.49"/>
<polygon   points="382.22,-43.8 374.14,-36.94 376.18,-47.34 382.22,-43.8"/>
</g>
<!-- can -->
<g id="node7" class="node">
<title>can</title>
<ellipse fill="none"  cx="446.64" cy="-18" rx="28.59" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="446.64" y="-13.32" font-family="Times,serif" font-size="14.00">can</text>
</g>
<!-- &#45;&gt;can -->
<g id="edge6" class="edge">
<title>&#45;&gt;can</title>
<path fill="none"  d="M414.38,-72.76C419.36,-64.46 425.55,-54.15 431.16,-44.79"/>
<polygon   points="434.03,-46.82 436.17,-36.45 428.02,-43.22 434.03,-46.82"/>
</g>
<!-- current -->
<g id="node8" class="node">
<title>current</title>
<ellipse fill="none"  cx="541.64" cy="-18" rx="48.58" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="541.64" y="-13.32" font-family="Times,serif" font-size="14.00">current</text>
</g>
<!-- &#45;&gt;current -->
<g id="edge7" class="edge">
<title>&#45;&gt;current</title>
<path fill="none"  d="M425.74,-78.22C446.59,-67.56 478.92,-51.04 504.14,-38.16"/>
<polygon   points="505.46,-41.42 512.77,-33.75 502.27,-35.18 505.46,-41.42"/>
</g>
<!-- dose -->
<g id="node9" class="node">
<title>dose</title>
<ellipse fill="none"  cx="642.64" cy="-18" rx="34.37" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="642.64" y="-13.32" font-family="Times,serif" font-size="14.00">dose</text>
</g>
<!-- &#45;&gt;dose -->
<g id="edge8" class="edge">
<title>&#45;&gt;dose</title>
<path fill="none"  d="M429.84,-83.1C467.25,-74.13 539.55,-55.98 599.64,-36 601.61,-35.34 603.62,-34.65 605.64,-33.93"/>
<polygon   points="606.87,-37.2 615.01,-30.43 604.42,-30.65 606.87,-37.2"/>
</g>
<!-- bat -->
<g id="node10" class="node">
<title>bat</title>
<ellipse fill="none"  cx="722.64" cy="-18" rx="27.53" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="722.64" y="-13.32" font-family="Times,serif" font-size="14.00">bat</text>
</g>
<!-- &#45;&gt;bat -->
<g id="edge9" class="edge">
<title>&#45;&gt;bat</title>
<path fill="none"  d="M431.52,-86.15C482.17,-80.29 594.82,-64.95 685.64,-36 687.36,-35.45 689.11,-34.84 690.86,-34.19"/>
<polygon   points="692.17,-37.44 700.07,-30.38 689.49,-30.97 692.17,-37.44"/>
</g>
<!-- category -->
<g id="node11" class="node">
<title>category</title>
<ellipse fill="none"  cx="822.64" cy="-18" rx="54.89" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="822.64" y="-13.32" font-family="Times,serif" font-size="14.00">category</text>
</g>
<!-- &#45;&gt;category -->
<g id="edge10" class="edge">
<title>&#45;&gt;category</title>
<path fill="none"  d="M431.1,-86.11C490.33,-79.41 637.94,-61.41 759.64,-36 763.47,-35.2 767.41,-34.31 771.37,-33.36"/>
<polygon   points="772.16,-36.77 781.01,-30.95 770.46,-29.98 772.16,-36.77"/>
</g>
</g>
</svg></div></p>
<p>This is obviously pretty inefficient. If you were to try and optimize
this, you might try the following: All words that contain the prefix
<code>cat</code> start with a <code>c</code>, so we can group our words
by their first character to immediately filter out all the ones that
don’t start with a <code>c</code>.</p>
<p>With this optimization, our tree, now represented as a map from
characters to sets of words, looks like this.</p>
<p><div class="dot-output"><?xml version="1.0" encoding="UTF-8" standalone="no"?>

<!-- Generated by graphviz version 14.0.5 (0)
 -->
<!-- Pages: 1 -->
<svg width="883pt" height="188pt"
 viewBox="0.00 0.00 883.00 188.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 184)">
<g id="node1" class="node">
<title></title>
<ellipse fill="none"  cx="486.64" cy="-162" rx="27" ry="18"/>
</g>
<!-- d -->
<g id="node2" class="node">
<title>d</title>
<ellipse fill="none"  cx="157.64" cy="-90" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="157.64" y="-85.33" font-family="Times,serif" font-size="14.00">d</text>
</g>
<!-- &#45;&gt;d -->
<g id="edge1" class="edge">
<title>&#45;&gt;d</title>
<path fill="none"  d="M461.1,-155.57C403.15,-143.24 261.56,-113.11 194.29,-98.8"/>
<polygon   points="195.38,-95.45 184.87,-96.79 193.92,-102.3 195.38,-95.45"/>
</g>
<!-- c -->
<g id="node3" class="node">
<title>c</title>
<ellipse fill="none"  cx="486.64" cy="-90" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="486.64" y="-85.33" font-family="Times,serif" font-size="14.00">c</text>
</g>
<!-- &#45;&gt;c -->
<g id="edge2" class="edge">
<title>&#45;&gt;c</title>
<path fill="none"  d="M486.64,-143.7C486.64,-136.41 486.64,-127.73 486.64,-119.54"/>
<polygon   points="490.14,-119.62 486.64,-109.62 483.14,-119.62 490.14,-119.62"/>
</g>
<!-- b -->
<g id="node4" class="node">
<title>b</title>
<ellipse fill="none"  cx="725.64" cy="-90" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="725.64" y="-85.33" font-family="Times,serif" font-size="14.00">b</text>
</g>
<!-- &#45;&gt;b -->
<g id="edge3" class="edge">
<title>&#45;&gt;b</title>
<path fill="none"  d="M510.87,-153.9C553.28,-141.48 641.11,-115.76 690.3,-101.35"/>
<polygon   points="691.28,-104.71 699.89,-98.54 689.31,-97.99 691.28,-104.71"/>
</g>
<!-- dog -->
<g id="node5" class="node">
<title>dog</title>
<ellipse fill="none"  cx="29.64" cy="-18" rx="29.64" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="29.64" y="-13.32" font-family="Times,serif" font-size="14.00">dog</text>
</g>
<!-- d&#45;&gt;dog -->
<g id="edge4" class="edge">
<title>d&#45;&gt;dog</title>
<path fill="none"  d="M137.07,-77.75C116.51,-66.51 84.63,-49.07 60.93,-36.11"/>
<polygon   points="62.79,-33.14 52.33,-31.41 59.43,-39.28 62.79,-33.14"/>
</g>
<!-- dune -->
<g id="node9" class="node">
<title>dune</title>
<ellipse fill="none"  cx="113.64" cy="-18" rx="35.95" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="113.64" y="-13.32" font-family="Times,serif" font-size="14.00">dune</text>
</g>
<!-- d&#45;&gt;dune -->
<g id="edge5" class="edge">
<title>d&#45;&gt;dune</title>
<path fill="none"  d="M147.65,-73.12C142.44,-64.82 135.93,-54.46 130,-45.03"/>
<polygon   points="132.98,-43.19 124.69,-36.59 127.05,-46.92 132.98,-43.19"/>
</g>
<!-- dose -->
<g id="node12" class="node">
<title>dose</title>
<ellipse fill="none"  cx="201.64" cy="-18" rx="34.37" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="201.64" y="-13.32" font-family="Times,serif" font-size="14.00">dose</text>
</g>
<!-- d&#45;&gt;dose -->
<g id="edge6" class="edge">
<title>d&#45;&gt;dose</title>
<path fill="none"  d="M167.62,-73.12C172.84,-64.82 179.35,-54.46 185.27,-45.03"/>
<polygon   points="188.22,-46.92 190.58,-36.59 182.3,-43.19 188.22,-46.92"/>
</g>
<!-- cat -->
<g id="node6" class="node">
<title>cat</title>
<ellipse fill="none"  cx="280.64" cy="-18" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="280.64" y="-13.32" font-family="Times,serif" font-size="14.00">cat</text>
</g>
<!-- c&#45;&gt;cat -->
<g id="edge7" class="edge">
<title>c&#45;&gt;cat</title>
<path fill="none"  d="M461.78,-82.42C428.32,-73.3 367.19,-55.71 316.64,-36 315.11,-35.4 313.55,-34.77 311.99,-34.12"/>
<polygon   points="313.69,-31.04 303.13,-30.18 310.85,-37.44 313.69,-31.04"/>
</g>
<!-- car -->
<g id="node7" class="node">
<title>car</title>
<ellipse fill="none"  cx="352.64" cy="-18" rx="27.01" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="352.64" y="-13.32" font-family="Times,serif" font-size="14.00">car</text>
</g>
<!-- c&#45;&gt;car -->
<g id="edge8" class="edge">
<title>c&#45;&gt;car</title>
<path fill="none"  d="M465.7,-78.06C443.67,-66.56 408.77,-48.32 383.57,-35.16"/>
<polygon   points="385.25,-32.09 374.77,-30.56 382.01,-38.29 385.25,-32.09"/>
</g>
<!-- candle -->
<g id="node8" class="node">
<title>candle</title>
<ellipse fill="none"  cx="441.64" cy="-18" rx="43.84" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="441.64" y="-13.32" font-family="Times,serif" font-size="14.00">candle</text>
</g>
<!-- c&#45;&gt;candle -->
<g id="edge9" class="edge">
<title>c&#45;&gt;candle</title>
<path fill="none"  d="M476.43,-73.12C471.17,-64.94 464.62,-54.76 458.63,-45.44"/>
<polygon   points="461.61,-43.59 453.25,-37.07 455.72,-47.37 461.61,-43.59"/>
</g>
<!-- can -->
<g id="node10" class="node">
<title>can</title>
<ellipse fill="none"  cx="531.64" cy="-18" rx="28.59" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="531.64" y="-13.32" font-family="Times,serif" font-size="14.00">can</text>
</g>
<!-- c&#45;&gt;can -->
<g id="edge10" class="edge">
<title>c&#45;&gt;can</title>
<path fill="none"  d="M496.85,-73.12C502.31,-64.61 509.18,-53.94 515.36,-44.32"/>
<polygon   points="518.18,-46.4 520.65,-36.09 512.3,-42.61 518.18,-46.4"/>
</g>
<!-- current -->
<g id="node11" class="node">
<title>current</title>
<ellipse fill="none"  cx="626.64" cy="-18" rx="48.58" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="626.64" y="-13.32" font-family="Times,serif" font-size="14.00">current</text>
</g>
<!-- c&#45;&gt;current -->
<g id="edge11" class="edge">
<title>c&#45;&gt;current</title>
<path fill="none"  d="M507.9,-78.37C529.15,-67.75 562.28,-51.18 588.15,-38.24"/>
<polygon   points="589.65,-41.41 597.03,-33.8 586.52,-35.14 589.65,-41.41"/>
</g>
<!-- category -->
<g id="node14" class="node">
<title>category</title>
<ellipse fill="none"  cx="747.64" cy="-18" rx="54.89" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="747.64" y="-13.32" font-family="Times,serif" font-size="14.00">category</text>
</g>
<!-- c&#45;&gt;category -->
<g id="edge12" class="edge">
<title>c&#45;&gt;category</title>
<path fill="none"  d="M511.65,-82.32C549.21,-72.29 622.44,-52.72 684.64,-36 688.14,-35.06 691.75,-34.09 695.39,-33.11"/>
<polygon   points="696.09,-36.54 704.84,-30.56 694.27,-29.78 696.09,-36.54"/>
</g>
<!-- bat -->
<g id="node13" class="node">
<title>bat</title>
<ellipse fill="none"  cx="847.64" cy="-18" rx="27.53" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="847.64" y="-13.32" font-family="Times,serif" font-size="14.00">bat</text>
</g>
<!-- b&#45;&gt;bat -->
<g id="edge13" class="edge">
<title>b&#45;&gt;bat</title>
<path fill="none"  d="M745.78,-77.44C765.3,-66.24 795.14,-49.12 817.48,-36.3"/>
<polygon   points="819.22,-39.34 826.15,-31.33 815.73,-33.27 819.22,-39.34"/>
</g>
</g>
</svg></div></p>
<p>Cool! This already cut the number of words we need to search through
roughly in half. To speed things up further, you might notice that
exactly the same argument applies to the second character, as well as
the third, fourth, and every one after that!</p>
<p>So if we apply this optimization to <em>every</em> character,
effectively unrolling the words into fancy interlinked lists of
characters, we end up with a <strong>trie</strong>!</p>
<p><div class="dot-output"><?xml version="1.0" encoding="UTF-8" standalone="no"?>

<!-- Generated by graphviz version 14.0.5 (0)
 -->
<!-- Pages: 1 -->
<svg width="566pt" height="620pt"
 viewBox="0.00 0.00 566.00 620.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 616)">
<g id="node1" class="node">
<title></title>
<ellipse fill="none"  cx="369" cy="-594" rx="27" ry="18"/>
</g>
<!-- d -->
<g id="node2" class="node">
<title>d</title>
<ellipse fill="none"  cx="171" cy="-522" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="171" y="-517.33" font-family="Times,serif" font-size="14.00">d</text>
</g>
<!-- &#45;&gt;d -->
<g id="edge1" class="edge">
<title>&#45;&gt;d</title>
<path fill="none"  d="M345.51,-584.7C310.75,-572.41 245.42,-549.31 205.3,-535.13"/>
<polygon   points="206.48,-531.83 195.89,-531.8 204.15,-538.43 206.48,-531.83"/>
</g>
<!-- c -->
<g id="node3" class="node">
<title>c</title>
<ellipse fill="none"  cx="369" cy="-522" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="369" y="-517.33" font-family="Times,serif" font-size="14.00">c</text>
</g>
<!-- &#45;&gt;c -->
<g id="edge2" class="edge">
<title>&#45;&gt;c</title>
<path fill="none"  d="M369,-575.7C369,-568.41 369,-559.73 369,-551.54"/>
<polygon   points="372.5,-551.62 369,-541.62 365.5,-551.62 372.5,-551.62"/>
</g>
<!-- b -->
<g id="node4" class="node">
<title>b</title>
<ellipse fill="none"  cx="481" cy="-522" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="481" y="-517.33" font-family="Times,serif" font-size="14.00">b</text>
</g>
<!-- &#45;&gt;b -->
<g id="edge3" class="edge">
<title>&#45;&gt;b</title>
<path fill="none"  d="M388.25,-580.97C405.8,-570 431.97,-553.64 452.04,-541.1"/>
<polygon   points="453.71,-544.18 460.34,-535.91 450,-538.24 453.71,-544.18"/>
</g>
<!-- do -->
<g id="node5" class="node">
<title>do</title>
<ellipse fill="none"  cx="99" cy="-450" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="99" y="-445.32" font-family="Times,serif" font-size="14.00">o</text>
</g>
<!-- d&#45;&gt;do -->
<g id="edge4" class="edge">
<title>d&#45;&gt;do</title>
<path fill="none"  d="M156.08,-506.5C146.23,-496.92 133.14,-484.19 121.97,-473.34"/>
<polygon   points="124.59,-471 114.98,-466.54 119.71,-476.02 124.59,-471"/>
</g>
<!-- du -->
<g id="node9" class="node">
<title>du</title>
<ellipse fill="none"  cx="171" cy="-450" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="171" y="-445.32" font-family="Times,serif" font-size="14.00">u</text>
</g>
<!-- d&#45;&gt;du -->
<g id="edge8" class="edge">
<title>d&#45;&gt;du</title>
<path fill="none"  d="M171,-503.7C171,-496.41 171,-487.73 171,-479.54"/>
<polygon   points="174.5,-479.62 171,-469.62 167.5,-479.62 174.5,-479.62"/>
</g>
<!-- ca -->
<g id="node12" class="node">
<title>ca</title>
<ellipse fill="none"  cx="324" cy="-450" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="324" y="-445.32" font-family="Times,serif" font-size="14.00">a</text>
</g>
<!-- c&#45;&gt;ca -->
<g id="edge11" class="edge">
<title>c&#45;&gt;ca</title>
<path fill="none"  d="M358.79,-505.12C353.32,-496.61 346.46,-485.94 340.28,-476.32"/>
<polygon   points="343.34,-474.61 334.99,-468.09 337.45,-478.4 343.34,-474.61"/>
</g>
<!-- cu -->
<g id="node24" class="node">
<title>cu</title>
<ellipse fill="none"  cx="414" cy="-450" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="414" y="-445.32" font-family="Times,serif" font-size="14.00">u</text>
</g>
<!-- c&#45;&gt;cu -->
<g id="edge23" class="edge">
<title>c&#45;&gt;cu</title>
<path fill="none"  d="M379.21,-505.12C384.68,-496.61 391.54,-485.94 397.72,-476.32"/>
<polygon   points="400.55,-478.4 403.01,-468.09 394.66,-474.61 400.55,-478.4"/>
</g>
<!-- ba -->
<g id="node30" class="node">
<title>ba</title>
<ellipse fill="none"  cx="522" cy="-450" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="522" y="-445.32" font-family="Times,serif" font-size="14.00">a</text>
</g>
<!-- b&#45;&gt;ba -->
<g id="edge29" class="edge">
<title>b&#45;&gt;ba</title>
<path fill="none"  d="M490.51,-504.76C495.37,-496.46 501.41,-486.15 506.89,-476.79"/>
<polygon   points="509.74,-478.85 511.78,-468.45 503.7,-475.31 509.74,-478.85"/>
</g>
<!-- dog -->
<g id="node6" class="node">
<title>dog</title>
<ellipse fill="none"  cx="27" cy="-378" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="27" y="-373.32" font-family="Times,serif" font-size="14.00">g</text>
</g>
<!-- do&#45;&gt;dog -->
<g id="edge5" class="edge">
<title>do&#45;&gt;dog</title>
<path fill="none"  d="M84.08,-434.5C74.23,-424.92 61.14,-412.19 49.97,-401.34"/>
<polygon   points="52.59,-399 42.98,-394.54 47.71,-404.02 52.59,-399"/>
</g>
<!-- dos -->
<g id="node7" class="node">
<title>dos</title>
<ellipse fill="none"  cx="99" cy="-378" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="99" y="-373.32" font-family="Times,serif" font-size="14.00">s</text>
</g>
<!-- do&#45;&gt;dos -->
<g id="edge6" class="edge">
<title>do&#45;&gt;dos</title>
<path fill="none"  d="M99,-431.7C99,-424.41 99,-415.73 99,-407.54"/>
<polygon   points="102.5,-407.62 99,-397.62 95.5,-407.62 102.5,-407.62"/>
</g>
<!-- dose -->
<g id="node8" class="node">
<title>dose</title>
<ellipse fill="none"  cx="99" cy="-306" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="99" y="-301.32" font-family="Times,serif" font-size="14.00">e</text>
</g>
<!-- dos&#45;&gt;dose -->
<g id="edge7" class="edge">
<title>dos&#45;&gt;dose</title>
<path fill="none"  d="M99,-359.7C99,-352.41 99,-343.73 99,-335.54"/>
<polygon   points="102.5,-335.62 99,-325.62 95.5,-335.62 102.5,-335.62"/>
</g>
<!-- dun -->
<g id="node10" class="node">
<title>dun</title>
<ellipse fill="none"  cx="171" cy="-378" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="171" y="-373.32" font-family="Times,serif" font-size="14.00">n</text>
</g>
<!-- du&#45;&gt;dun -->
<g id="edge9" class="edge">
<title>du&#45;&gt;dun</title>
<path fill="none"  d="M171,-431.7C171,-424.41 171,-415.73 171,-407.54"/>
<polygon   points="174.5,-407.62 171,-397.62 167.5,-407.62 174.5,-407.62"/>
</g>
<!-- dune -->
<g id="node11" class="node">
<title>dune</title>
<ellipse fill="none"  cx="171" cy="-306" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="171" y="-301.32" font-family="Times,serif" font-size="14.00">e</text>
</g>
<!-- dun&#45;&gt;dune -->
<g id="edge10" class="edge">
<title>dun&#45;&gt;dune</title>
<path fill="none"  d="M171,-359.7C171,-352.41 171,-343.73 171,-335.54"/>
<polygon   points="174.5,-335.62 171,-325.62 167.5,-335.62 174.5,-335.62"/>
</g>
<!-- cat -->
<g id="node13" class="node">
<title>cat</title>
<ellipse fill="none"  cx="243" cy="-378" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="243" y="-373.32" font-family="Times,serif" font-size="14.00">t</text>
</g>
<!-- ca&#45;&gt;cat -->
<g id="edge12" class="edge">
<title>ca&#45;&gt;cat</title>
<path fill="none"  d="M308,-435.17C296.46,-425.2 280.67,-411.56 267.55,-400.21"/>
<polygon   points="269.97,-397.68 260.11,-393.79 265.39,-402.98 269.97,-397.68"/>
</g>
<!-- car -->
<g id="node19" class="node">
<title>car</title>
<ellipse fill="none"  cx="315" cy="-378" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="315" y="-373.32" font-family="Times,serif" font-size="14.00">r</text>
</g>
<!-- ca&#45;&gt;car -->
<g id="edge18" class="edge">
<title>ca&#45;&gt;car</title>
<path fill="none"  d="M321.78,-431.7C320.83,-424.32 319.7,-415.52 318.63,-407.25"/>
<polygon   points="322.14,-407.08 317.39,-397.61 315.2,-407.97 322.14,-407.08"/>
</g>
<!-- can -->
<g id="node20" class="node">
<title>can</title>
<ellipse fill="none"  cx="387" cy="-378" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="387" y="-373.32" font-family="Times,serif" font-size="14.00">n</text>
</g>
<!-- ca&#45;&gt;can -->
<g id="edge19" class="edge">
<title>ca&#45;&gt;can</title>
<path fill="none"  d="M337.36,-434.15C345.71,-424.87 356.65,-412.73 366.13,-402.19"/>
<polygon   points="368.56,-404.72 372.65,-394.95 363.35,-400.04 368.56,-404.72"/>
</g>
<!-- cate -->
<g id="node14" class="node">
<title>cate</title>
<ellipse fill="none"  cx="243" cy="-306" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="243" y="-301.32" font-family="Times,serif" font-size="14.00">e</text>
</g>
<!-- cat&#45;&gt;cate -->
<g id="edge13" class="edge">
<title>cat&#45;&gt;cate</title>
<path fill="none"  d="M243,-359.7C243,-352.41 243,-343.73 243,-335.54"/>
<polygon   points="246.5,-335.62 243,-325.62 239.5,-335.62 246.5,-335.62"/>
</g>
<!-- categ -->
<g id="node15" class="node">
<title>categ</title>
<ellipse fill="none"  cx="243" cy="-234" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="243" y="-229.32" font-family="Times,serif" font-size="14.00">g</text>
</g>
<!-- cate&#45;&gt;categ -->
<g id="edge14" class="edge">
<title>cate&#45;&gt;categ</title>
<path fill="none"  d="M243,-287.7C243,-280.41 243,-271.73 243,-263.54"/>
<polygon   points="246.5,-263.62 243,-253.62 239.5,-263.62 246.5,-263.62"/>
</g>
<!-- catego -->
<g id="node16" class="node">
<title>catego</title>
<ellipse fill="none"  cx="243" cy="-162" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="243" y="-157.32" font-family="Times,serif" font-size="14.00">o</text>
</g>
<!-- categ&#45;&gt;catego -->
<g id="edge15" class="edge">
<title>categ&#45;&gt;catego</title>
<path fill="none"  d="M243,-215.7C243,-208.41 243,-199.73 243,-191.54"/>
<polygon   points="246.5,-191.62 243,-181.62 239.5,-191.62 246.5,-191.62"/>
</g>
<!-- categor -->
<g id="node17" class="node">
<title>categor</title>
<ellipse fill="none"  cx="243" cy="-90" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="243" y="-85.33" font-family="Times,serif" font-size="14.00">r</text>
</g>
<!-- catego&#45;&gt;categor -->
<g id="edge16" class="edge">
<title>catego&#45;&gt;categor</title>
<path fill="none"  d="M243,-143.7C243,-136.41 243,-127.73 243,-119.54"/>
<polygon   points="246.5,-119.62 243,-109.62 239.5,-119.62 246.5,-119.62"/>
</g>
<!-- category -->
<g id="node18" class="node">
<title>category</title>
<ellipse fill="none"  cx="243" cy="-18" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="243" y="-13.32" font-family="Times,serif" font-size="14.00">y</text>
</g>
<!-- categor&#45;&gt;category -->
<g id="edge17" class="edge">
<title>categor&#45;&gt;category</title>
<path fill="none"  d="M243,-71.7C243,-64.41 243,-55.73 243,-47.54"/>
<polygon   points="246.5,-47.62 243,-37.62 239.5,-47.62 246.5,-47.62"/>
</g>
<!-- cand -->
<g id="node21" class="node">
<title>cand</title>
<ellipse fill="none"  cx="387" cy="-306" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="387" y="-301.32" font-family="Times,serif" font-size="14.00">d</text>
</g>
<!-- can&#45;&gt;cand -->
<g id="edge20" class="edge">
<title>can&#45;&gt;cand</title>
<path fill="none"  d="M387,-359.7C387,-352.41 387,-343.73 387,-335.54"/>
<polygon   points="390.5,-335.62 387,-325.62 383.5,-335.62 390.5,-335.62"/>
</g>
<!-- candl -->
<g id="node22" class="node">
<title>candl</title>
<ellipse fill="none"  cx="387" cy="-234" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="387" y="-229.32" font-family="Times,serif" font-size="14.00">l</text>
</g>
<!-- cand&#45;&gt;candl -->
<g id="edge21" class="edge">
<title>cand&#45;&gt;candl</title>
<path fill="none"  d="M387,-287.7C387,-280.41 387,-271.73 387,-263.54"/>
<polygon   points="390.5,-263.62 387,-253.62 383.5,-263.62 390.5,-263.62"/>
</g>
<!-- candle -->
<g id="node23" class="node">
<title>candle</title>
<ellipse fill="none"  cx="387" cy="-162" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="387" y="-157.32" font-family="Times,serif" font-size="14.00">e</text>
</g>
<!-- candl&#45;&gt;candle -->
<g id="edge22" class="edge">
<title>candl&#45;&gt;candle</title>
<path fill="none"  d="M387,-215.7C387,-208.41 387,-199.73 387,-191.54"/>
<polygon   points="390.5,-191.62 387,-181.62 383.5,-191.62 390.5,-191.62"/>
</g>
<!-- cur -->
<g id="node25" class="node">
<title>cur</title>
<ellipse fill="none"  cx="459" cy="-378" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="459" y="-373.32" font-family="Times,serif" font-size="14.00">r</text>
</g>
<!-- cu&#45;&gt;cur -->
<g id="edge24" class="edge">
<title>cu&#45;&gt;cur</title>
<path fill="none"  d="M424.21,-433.12C429.68,-424.61 436.54,-413.94 442.72,-404.32"/>
<polygon   points="445.55,-406.4 448.01,-396.09 439.66,-402.61 445.55,-406.4"/>
</g>
<!-- curr -->
<g id="node26" class="node">
<title>curr</title>
<ellipse fill="none"  cx="459" cy="-306" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="459" y="-301.32" font-family="Times,serif" font-size="14.00">r</text>
</g>
<!-- cur&#45;&gt;curr -->
<g id="edge25" class="edge">
<title>cur&#45;&gt;curr</title>
<path fill="none"  d="M459,-359.7C459,-352.41 459,-343.73 459,-335.54"/>
<polygon   points="462.5,-335.62 459,-325.62 455.5,-335.62 462.5,-335.62"/>
</g>
<!-- curre -->
<g id="node27" class="node">
<title>curre</title>
<ellipse fill="none"  cx="459" cy="-234" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="459" y="-229.32" font-family="Times,serif" font-size="14.00">e</text>
</g>
<!-- curr&#45;&gt;curre -->
<g id="edge26" class="edge">
<title>curr&#45;&gt;curre</title>
<path fill="none"  d="M459,-287.7C459,-280.41 459,-271.73 459,-263.54"/>
<polygon   points="462.5,-263.62 459,-253.62 455.5,-263.62 462.5,-263.62"/>
</g>
<!-- curren -->
<g id="node28" class="node">
<title>curren</title>
<ellipse fill="none"  cx="459" cy="-162" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="459" y="-157.32" font-family="Times,serif" font-size="14.00">n</text>
</g>
<!-- curre&#45;&gt;curren -->
<g id="edge27" class="edge">
<title>curre&#45;&gt;curren</title>
<path fill="none"  d="M459,-215.7C459,-208.41 459,-199.73 459,-191.54"/>
<polygon   points="462.5,-191.62 459,-181.62 455.5,-191.62 462.5,-191.62"/>
</g>
<!-- current -->
<g id="node29" class="node">
<title>current</title>
<ellipse fill="none"  cx="459" cy="-90" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="459" y="-85.33" font-family="Times,serif" font-size="14.00">t</text>
</g>
<!-- curren&#45;&gt;current -->
<g id="edge28" class="edge">
<title>curren&#45;&gt;current</title>
<path fill="none"  d="M459,-143.7C459,-136.41 459,-127.73 459,-119.54"/>
<polygon   points="462.5,-119.62 459,-109.62 455.5,-119.62 462.5,-119.62"/>
</g>
<!-- bat -->
<g id="node31" class="node">
<title>bat</title>
<ellipse fill="none"  cx="531" cy="-378" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="531" y="-373.32" font-family="Times,serif" font-size="14.00">t</text>
</g>
<!-- ba&#45;&gt;bat -->
<g id="edge30" class="edge">
<title>ba&#45;&gt;bat</title>
<path fill="none"  d="M524.22,-431.7C525.17,-424.32 526.3,-415.52 527.37,-407.25"/>
<polygon   points="530.8,-407.97 528.61,-397.61 523.86,-407.08 530.8,-407.97"/>
</g>
</g>
</svg></div></p>
<p>Now, instead of being linear in the number of words times their
length, our search is only linear in the size of the prefix we are
looking for. In practice, where words tend to share prefixes, this turns
out to be <em>much</em> more efficient!</p>
<h2 id="back-to-the-world-of-types">Back to the world of types</h2>
<p>So, how can we use tries for type classes? Well, first of all, we
need a way to unroll our complicated nested types into a linear string
of atomic units that play a similar role to the characters in our word
trie.</p>
<p>For most types, this will be pretty straightforward. We can unroll
each of them into a linear string of <em>head constructors</em>. You can
view this transformation as a depth-first search on our type that
separates every type constructor from its arguments in every step. For
example, <code>Either(List(String), Array((Int, Bool)))</code> will be
unrolled into
<code>Either(_, _) -&gt; List(_) -&gt; String -&gt; Array(_) -&gt; (_, _) -&gt; Int -&gt; Bool</code>.</p>
<p>We can now already construct a trie to hold our instances from
above.</p>
<p><div class="dot-output"><?xml version="1.0" encoding="UTF-8" standalone="no"?>

<!-- Generated by graphviz version 14.0.5 (0)
 -->
<!-- Pages: 1 -->
<svg width="338pt" height="260pt"
 viewBox="0.00 0.00 338.00 260.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 256)">
<!-- C -->
<g id="node1" class="node">
<title>C</title>
<ellipse fill="none"  cx="125.32" cy="-234" rx="30.69" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="125.32" y="-229.32" font-family="Times,serif" font-size="14.00">C(_)</text>
</g>
<!-- Int -->
<g id="node2" class="node">
<title>Int</title>
<ellipse fill="none"  cx="38.32" cy="-162" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="38.32" y="-157.32" font-family="Times,serif" font-size="14.00">Int</text>
</g>
<!-- C&#45;&gt;Int -->
<g id="edge1" class="edge">
<title>C&#45;&gt;Int</title>
<path fill="none"  d="M107.71,-218.83C95.09,-208.68 77.89,-194.83 63.77,-183.47"/>
<polygon   points="66.18,-180.92 56.19,-177.38 61.79,-186.38 66.18,-180.92"/>
</g>
<!-- List(_) -->
<g id="node3" class="node">
<title>List(_)</title>
<ellipse fill="none"  cx="125.32" cy="-162" rx="42.26" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="125.32" y="-157.32" font-family="Times,serif" font-size="14.00">List(_)</text>
</g>
<!-- C&#45;&gt;List(_) -->
<g id="edge2" class="edge">
<title>C&#45;&gt;List(_)</title>
<path fill="none"  d="M125.32,-215.7C125.32,-208.41 125.32,-199.73 125.32,-191.54"/>
<polygon   points="128.82,-191.62 125.32,-181.62 121.82,-191.62 128.82,-191.62"/>
</g>
<!-- (\_, \_) -->
<g id="node6" class="node">
<title>(\_, \_)</title>
<ellipse fill="none"  cx="220.32" cy="-162" rx="34.37" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="220.32" y="-157.32" font-family="Times,serif" font-size="14.00">(_, _)</text>
</g>
<!-- C&#45;&gt;(\_, \_) -->
<g id="edge5" class="edge">
<title>C&#45;&gt;(\_, \_)</title>
<path fill="none"  d="M143.64,-219.5C157.3,-209.44 176.22,-195.49 191.85,-183.98"/>
<polygon   points="193.89,-186.82 199.86,-178.07 189.74,-181.19 193.89,-186.82"/>
</g>
<!-- Bool -->
<g id="node4" class="node">
<title>Bool</title>
<ellipse fill="none"  cx="33.32" cy="-90" rx="33.32" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="33.32" y="-85.33" font-family="Times,serif" font-size="14.00">Bool</text>
</g>
<!-- List(_)&#45;&gt;Bool -->
<g id="edge3" class="edge">
<title>List(_)&#45;&gt;Bool</title>
<path fill="none"  d="M105.36,-145.81C92.35,-135.92 75.21,-122.87 60.91,-111.99"/>
<polygon   points="63.27,-109.39 53.19,-106.12 59.03,-114.96 63.27,-109.39"/>
</g>
<!-- String -->
<g id="node5" class="node">
<title>String</title>
<ellipse fill="none"  cx="127.32" cy="-90" rx="42.79" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="127.32" y="-85.33" font-family="Times,serif" font-size="14.00">String</text>
</g>
<!-- List(_)&#45;&gt;String -->
<g id="edge4" class="edge">
<title>List(_)&#45;&gt;String</title>
<path fill="none"  d="M125.81,-143.7C126.02,-136.41 126.27,-127.73 126.5,-119.54"/>
<polygon   points="130,-119.71 126.79,-109.62 123,-119.51 130,-119.71"/>
</g>
<!-- a -->
<g id="node7" class="node">
<title>a</title>
<ellipse fill="none"  cx="218.32" cy="-90" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="218.32" y="-85.33" font-family="Times,serif" font-size="14.00">a</text>
</g>
<!-- (\_, \_)&#45;&gt;a -->
<g id="edge6" class="edge">
<title>(\_, \_)&#45;&gt;a</title>
<path fill="none"  d="M219.83,-143.7C219.62,-136.41 219.37,-127.73 219.14,-119.54"/>
<polygon   points="222.64,-119.51 218.85,-109.62 215.64,-119.71 222.64,-119.51"/>
</g>
<!-- Bool2 -->
<g id="node9" class="node">
<title>Bool2</title>
<ellipse fill="none"  cx="296.32" cy="-90" rx="33.32" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="296.32" y="-85.33" font-family="Times,serif" font-size="14.00">Bool</text>
</g>
<!-- (\_, \_)&#45;&gt;Bool2 -->
<g id="edge8" class="edge">
<title>(\_, \_)&#45;&gt;Bool2</title>
<path fill="none"  d="M236.81,-145.81C246.97,-136.45 260.19,-124.28 271.58,-113.79"/>
<polygon   points="273.76,-116.53 278.75,-107.18 269.02,-111.39 273.76,-116.53"/>
</g>
<!-- Int2 -->
<g id="node8" class="node">
<title>Int2</title>
<ellipse fill="none"  cx="218.32" cy="-18" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="218.32" y="-13.32" font-family="Times,serif" font-size="14.00">Int</text>
</g>
<!-- a&#45;&gt;Int2 -->
<g id="edge7" class="edge">
<title>a&#45;&gt;Int2</title>
<path fill="none"  d="M218.32,-71.7C218.32,-64.41 218.32,-55.73 218.32,-47.54"/>
<polygon   points="221.82,-47.62 218.32,-37.62 214.82,-47.62 221.82,-47.62"/>
</g>
<!-- a2 -->
<g id="node10" class="node">
<title>a2</title>
<ellipse fill="none"  cx="296.32" cy="-18" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="296.32" y="-13.32" font-family="Times,serif" font-size="14.00">a</text>
</g>
<!-- Bool2&#45;&gt;a2 -->
<g id="edge9" class="edge">
<title>Bool2&#45;&gt;a2</title>
<path fill="none"  d="M296.32,-71.7C296.32,-64.41 296.32,-55.73 296.32,-47.54"/>
<polygon   points="299.82,-47.62 296.32,-37.62 292.82,-47.62 299.82,-47.62"/>
</g>
</g>
</svg></div></p>
<p>You might even think that we could resolve instances by simply
searching through the trie just like we did in our text prediction
example above, but it’s not quite that simple.</p>
<h2 id="universally-quantified-complications">Universally quantified
complications</h2>
<p>The issue is that some instances can contain universally quantified
type variables! In our case, we have two such instances:
<code>forall a. C(a, Int)</code> and
<code>forall a. C(Bool, a)</code>.</p>
<p>Trying to resolve, say <code>C(Bool, Int)</code>, needs to try both
instances and report an ambiguity error since both of them match.</p>
<p>More generally, at every inner node in our trie, there are either 0,
1, or 2 matching subtries that we need to check.</p>
<p>For example, looking up this instance in the trie above would
traverse all of the red nodes.</p>
<p><div class="dot-output"><?xml version="1.0" encoding="UTF-8" standalone="no"?>

<!-- Generated by graphviz version 14.0.5 (0)
 -->
<!-- Pages: 1 -->
<svg width="338pt" height="260pt"
 viewBox="0.00 0.00 338.00 260.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 256)">
<!-- C -->
<g id="node1" class="node">
<title>C</title>
<ellipse fill="none" stroke="red" cx="125.32" cy="-234" rx="30.69" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="125.32" y="-229.32" font-family="Times,serif" font-size="14.00">C(_)</text>
</g>
<!-- Int -->
<g id="node2" class="node">
<title>Int</title>
<ellipse fill="none"  cx="38.32" cy="-162" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="38.32" y="-157.32" font-family="Times,serif" font-size="14.00">Int</text>
</g>
<!-- C&#45;&gt;Int -->
<g id="edge1" class="edge">
<title>C&#45;&gt;Int</title>
<path fill="none"  d="M107.71,-218.83C95.09,-208.68 77.89,-194.83 63.77,-183.47"/>
<polygon   points="66.18,-180.92 56.19,-177.38 61.79,-186.38 66.18,-180.92"/>
</g>
<!-- List(_) -->
<g id="node3" class="node">
<title>List(_)</title>
<ellipse fill="none"  cx="125.32" cy="-162" rx="42.26" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="125.32" y="-157.32" font-family="Times,serif" font-size="14.00">List(_)</text>
</g>
<!-- C&#45;&gt;List(_) -->
<g id="edge2" class="edge">
<title>C&#45;&gt;List(_)</title>
<path fill="none"  d="M125.32,-215.7C125.32,-208.41 125.32,-199.73 125.32,-191.54"/>
<polygon   points="128.82,-191.62 125.32,-181.62 121.82,-191.62 128.82,-191.62"/>
</g>
<!-- (\_, \_) -->
<g id="node6" class="node">
<title>(\_, \_)</title>
<ellipse fill="none" stroke="red" cx="220.32" cy="-162" rx="34.37" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="220.32" y="-157.32" font-family="Times,serif" font-size="14.00">(_, _)</text>
</g>
<!-- C&#45;&gt;(\_, \_) -->
<g id="edge5" class="edge">
<title>C&#45;&gt;(\_, \_)</title>
<path fill="none" stroke="red" d="M143.64,-219.5C157.3,-209.44 176.22,-195.49 191.85,-183.98"/>
<polygon fill="red" stroke="red" points="193.89,-186.82 199.86,-178.07 189.74,-181.19 193.89,-186.82"/>
</g>
<!-- Bool -->
<g id="node4" class="node">
<title>Bool</title>
<ellipse fill="none"  cx="33.32" cy="-90" rx="33.32" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="33.32" y="-85.33" font-family="Times,serif" font-size="14.00">Bool</text>
</g>
<!-- List(_)&#45;&gt;Bool -->
<g id="edge3" class="edge">
<title>List(_)&#45;&gt;Bool</title>
<path fill="none"  d="M105.36,-145.81C92.35,-135.92 75.21,-122.87 60.91,-111.99"/>
<polygon   points="63.27,-109.39 53.19,-106.12 59.03,-114.96 63.27,-109.39"/>
</g>
<!-- String -->
<g id="node5" class="node">
<title>String</title>
<ellipse fill="none"  cx="127.32" cy="-90" rx="42.79" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="127.32" y="-85.33" font-family="Times,serif" font-size="14.00">String</text>
</g>
<!-- List(_)&#45;&gt;String -->
<g id="edge4" class="edge">
<title>List(_)&#45;&gt;String</title>
<path fill="none"  d="M125.81,-143.7C126.02,-136.41 126.27,-127.73 126.5,-119.54"/>
<polygon   points="130,-119.71 126.79,-109.62 123,-119.51 130,-119.71"/>
</g>
<!-- a -->
<g id="node7" class="node">
<title>a</title>
<ellipse fill="none" stroke="red" cx="218.32" cy="-90" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="218.32" y="-85.33" font-family="Times,serif" font-size="14.00">a</text>
</g>
<!-- (\_, \_)&#45;&gt;a -->
<g id="edge6" class="edge">
<title>(\_, \_)&#45;&gt;a</title>
<path fill="none" stroke="red" d="M219.83,-143.7C219.62,-136.41 219.37,-127.73 219.14,-119.54"/>
<polygon fill="red" stroke="red" points="222.64,-119.51 218.85,-109.62 215.64,-119.71 222.64,-119.51"/>
</g>
<!-- Bool2 -->
<g id="node9" class="node">
<title>Bool2</title>
<ellipse fill="none" stroke="red" cx="296.32" cy="-90" rx="33.32" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="296.32" y="-85.33" font-family="Times,serif" font-size="14.00">Bool</text>
</g>
<!-- (\_, \_)&#45;&gt;Bool2 -->
<g id="edge8" class="edge">
<title>(\_, \_)&#45;&gt;Bool2</title>
<path fill="none" stroke="red" d="M236.81,-145.81C246.97,-136.45 260.19,-124.28 271.58,-113.79"/>
<polygon fill="red" stroke="red" points="273.76,-116.53 278.75,-107.18 269.02,-111.39 273.76,-116.53"/>
</g>
<!-- Int2 -->
<g id="node8" class="node">
<title>Int2</title>
<ellipse fill="none" stroke="red" cx="218.32" cy="-18" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="218.32" y="-13.32" font-family="Times,serif" font-size="14.00">Int</text>
</g>
<!-- a&#45;&gt;Int2 -->
<g id="edge7" class="edge">
<title>a&#45;&gt;Int2</title>
<path fill="none" stroke="red" d="M218.32,-71.7C218.32,-64.41 218.32,-55.73 218.32,-47.54"/>
<polygon fill="red" stroke="red" points="221.82,-47.62 218.32,-37.62 214.82,-47.62 221.82,-47.62"/>
</g>
<!-- a2 -->
<g id="node10" class="node">
<title>a2</title>
<ellipse fill="none" stroke="red" cx="296.32" cy="-18" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="296.32" y="-13.32" font-family="Times,serif" font-size="14.00">a</text>
</g>
<!-- Bool2&#45;&gt;a2 -->
<g id="edge9" class="edge">
<title>Bool2&#45;&gt;a2</title>
<path fill="none" stroke="red" d="M296.32,-71.7C296.32,-64.41 296.32,-55.73 296.32,-47.54"/>
<polygon fill="red" stroke="red" points="299.82,-47.62 296.32,-37.62 292.82,-47.62 299.82,-47.62"/>
</g>
</g>
</svg></div></p>
<p>This might sound like it could lead to exponential blow-up, but it
actually doesn’t! In the absolute worst case, instance lookup needs to
traverse every path through our trie, but that is exactly equivalent to
what our naive linear search strategy did so it’s at least definitely
not slower than that.</p>
<p>Okay, so we traverse every possible path through our trie that
matches the types we are looking for. Is that it?</p>
<p>Not quite. Consider that variables might be used more than once in an
instance. For example, given an instance
<code>forall a. C((a, a))</code>, we need to check that the two
arguments to the tuple correspond to the same type.</p>
<p>To achieve this, we need to remember the first type we match a
variable against along a given path. If we come across this variable
again, we <em>patch</em> the trie by inserting the (unrolled) type where
the variable would be.</p>
<p>For example, say we have a trie with an instance for
<code>forall a. C((a, (a, Bool)))</code>. Now, matching this trie
against <code>C((List(Int), (List(Int), Bool)))</code> follows this
path. Once the traversal comes across the second occurrence of
<code>a</code>, it locally patches the trie by replacing <code>a</code>
with the blue path.</p>
<style>
.replaced {
    stroke: var(--gray);
    fill: var(--gray);
}
</style>
<p><div class="dot-output"><?xml version="1.0" encoding="UTF-8" standalone="no"?>

<!-- Generated by graphviz version 14.0.5 (0)
 -->
<!-- Pages: 1 -->
<svg width="565pt" height="476pt"
 viewBox="0.00 0.00 565.00 476.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 472)">
<!-- C((List(Int), (List(Int), Bool))) -->
<g id="node1" class="node">
<title>C((List(Int), (List(Int), Bool)))</title>
<ellipse fill="none" stroke="none" cx="156.43" cy="-450" rx="156.43" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="156.43" y="-445.32" font-family="Times,serif" font-size="14.00" fill="red">C((List(Int), (List(Int), Bool)))</text>
</g>
<!-- (List(Int), (List(Int), Bool)) -->
<g id="node2" class="node">
<title>(List(Int), (List(Int), Bool))</title>
<ellipse fill="none" stroke="none" cx="156.43" cy="-378" rx="141.7" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="156.43" y="-373.32" font-family="Times,serif" font-size="14.00" fill="red">(List(Int), (List(Int), Bool))</text>
</g>
<!-- C((List(Int), (List(Int), Bool)))&#45;&gt;(List(Int), (List(Int), Bool)) -->
<g id="edge1" class="edge">
<title>C((List(Int), (List(Int), Bool)))&#45;&gt;(List(Int), (List(Int), Bool))</title>
<path fill="none" stroke="none" d="M156.43,-431.7C156.43,-424.41 156.43,-415.73 156.43,-407.54"/>
<polygon fill="none" stroke="none" points="159.93,-407.62 156.43,-397.62 152.93,-407.62 159.93,-407.62"/>
</g>
<!-- List(Int) | (List(Int), Bool) -->
<g id="node3" class="node">
<title>List(Int) | (List(Int), Bool)</title>
<ellipse fill="none" stroke="none" cx="156.43" cy="-306" rx="137.49" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="156.43" y="-301.32" font-family="Times,serif" font-size="14.00" fill="red">List(Int) | (List(Int), Bool)</text>
</g>
<!-- (List(Int), (List(Int), Bool))&#45;&gt;List(Int) | (List(Int), Bool) -->
<g id="edge2" class="edge">
<title>(List(Int), (List(Int), Bool))&#45;&gt;List(Int) | (List(Int), Bool)</title>
<path fill="none" stroke="none" d="M156.43,-359.7C156.43,-352.41 156.43,-343.73 156.43,-335.54"/>
<polygon fill="none" stroke="none" points="159.93,-335.62 156.43,-325.62 152.93,-335.62 159.93,-335.62"/>
</g>
<!-- (List(Int), Bool) -->
<g id="node4" class="node">
<title>(List(Int), Bool)</title>
<ellipse fill="none" stroke="none" cx="156.43" cy="-234" rx="87.51" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="156.43" y="-229.32" font-family="Times,serif" font-size="14.00" fill="red">(List(Int), Bool)</text>
</g>
<!-- List(Int) | (List(Int), Bool)&#45;&gt;(List(Int), Bool) -->
<g id="edge3" class="edge">
<title>List(Int) | (List(Int), Bool)&#45;&gt;(List(Int), Bool)</title>
<path fill="none" stroke="none" d="M156.43,-287.7C156.43,-280.41 156.43,-271.73 156.43,-263.54"/>
<polygon fill="none" stroke="none" points="159.93,-263.62 156.43,-253.62 152.93,-263.62 159.93,-263.62"/>
</g>
<!-- List(Int) | Bool -->
<g id="node5" class="node">
<title>List(Int) | Bool</title>
<ellipse fill="none" stroke="none" cx="156.43" cy="-162" rx="83.3" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="156.43" y="-157.32" font-family="Times,serif" font-size="14.00" fill="red">List(Int) | Bool</text>
</g>
<!-- (List(Int), Bool)&#45;&gt;List(Int) | Bool -->
<g id="edge4" class="edge">
<title>(List(Int), Bool)&#45;&gt;List(Int) | Bool</title>
<path fill="none" stroke="none" d="M156.43,-215.7C156.43,-208.41 156.43,-199.73 156.43,-191.54"/>
<polygon fill="none" stroke="none" points="159.93,-191.62 156.43,-181.62 152.93,-191.62 159.93,-191.62"/>
</g>
<!-- Int | Bool -->
<g id="node6" class="node">
<title>Int | Bool</title>
<ellipse fill="none" stroke="none" cx="156.43" cy="-90" rx="57" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="156.43" y="-85.33" font-family="Times,serif" font-size="14.00" fill="red">Int | Bool</text>
</g>
<!-- List(Int) | Bool&#45;&gt;Int | Bool -->
<g id="edge5" class="edge">
<title>List(Int) | Bool&#45;&gt;Int | Bool</title>
<path fill="none" stroke="none" d="M156.43,-143.7C156.43,-136.41 156.43,-127.73 156.43,-119.54"/>
<polygon fill="none" stroke="none" points="159.93,-119.62 156.43,-109.62 152.93,-119.62 159.93,-119.62"/>
</g>
<!-- Bool2 -->
<g id="node7" class="node">
<title>Bool2</title>
<ellipse fill="none" stroke="none" cx="156.43" cy="-18" rx="33.32" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="156.43" y="-13.32" font-family="Times,serif" font-size="14.00" fill="red">Bool</text>
</g>
<!-- Int | Bool&#45;&gt;Bool2 -->
<g id="edge6" class="edge">
<title>Int | Bool&#45;&gt;Bool2</title>
<path fill="none" stroke="none" d="M156.43,-71.7C156.43,-64.41 156.43,-55.73 156.43,-47.54"/>
<polygon fill="none" stroke="none" points="159.93,-47.62 156.43,-37.62 152.93,-47.62 159.93,-47.62"/>
</g>
<!-- C(_) -->
<g id="node8" class="node">
<title>C(_)</title>
<ellipse fill="none"  cx="361.43" cy="-450" rx="30.69" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="361.43" y="-445.32" font-family="Times,serif" font-size="14.00">C(_)</text>
</g>
<!-- Pair -->
<g id="node9" class="node">
<title>Pair</title>
<ellipse fill="none"  cx="361.43" cy="-378" rx="34.37" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="361.43" y="-373.32" font-family="Times,serif" font-size="14.00">(_, _)</text>
</g>
<!-- C(_)&#45;&gt;Pair -->
<g id="edge7" class="edge">
<title>C(_)&#45;&gt;Pair</title>
<path fill="none"  d="M361.43,-431.7C361.43,-424.41 361.43,-415.73 361.43,-407.54"/>
<polygon   points="364.93,-407.62 361.43,-397.62 357.93,-407.62 364.93,-407.62"/>
</g>
<!-- a1 -->
<g id="node10" class="node">
<title>a1</title>
<ellipse fill="none"  cx="361.43" cy="-306" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="361.43" y="-301.32" font-family="Times,serif" font-size="14.00">a</text>
</g>
<!-- Pair&#45;&gt;a1 -->
<g id="edge8" class="edge">
<title>Pair&#45;&gt;a1</title>
<path fill="none"  d="M361.43,-359.7C361.43,-352.41 361.43,-343.73 361.43,-335.54"/>
<polygon   points="364.93,-335.62 361.43,-325.62 357.93,-335.62 364.93,-335.62"/>
</g>
<!-- Pair2 -->
<g id="node11" class="node">
<title>Pair2</title>
<ellipse fill="none"  cx="361.43" cy="-234" rx="34.37" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="361.43" y="-229.32" font-family="Times,serif" font-size="14.00">(_, _)</text>
</g>
<!-- a1&#45;&gt;Pair2 -->
<g id="edge9" class="edge">
<title>a1&#45;&gt;Pair2</title>
<path fill="none"  d="M361.43,-287.7C361.43,-280.41 361.43,-271.73 361.43,-263.54"/>
<polygon   points="364.93,-263.62 361.43,-253.62 357.93,-263.62 364.93,-263.62"/>
</g>
<!-- a2 -->
<g id="node12" class="node replaced">
<title>a2</title>
<ellipse fill="none"  cx="361.43" cy="-162" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="361.43" y="-157.32" font-family="Times,serif" font-size="14.00">a</text>
</g>
<!-- Pair2&#45;&gt;a2 -->
<g id="edge10" class="edge replaced">
<title>Pair2&#45;&gt;a2</title>
<path fill="none"  d="M361.43,-215.7C361.43,-208.41 361.43,-199.73 361.43,-191.54"/>
<polygon   points="364.93,-191.62 361.43,-181.62 357.93,-191.62 364.93,-191.62"/>
</g>
<!-- List -->
<g id="node14" class="node">
<title>List</title>
<ellipse fill="none" stroke="blue" cx="436.43" cy="-162" rx="30.16" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="436.43" y="-157.32" font-family="Times,serif" font-size="14.00">List</text>
</g>
<!-- Pair2&#45;&gt;List -->
<g id="edge12" class="edge">
<title>Pair2&#45;&gt;List</title>
<path fill="none" stroke="blue" d="M377.7,-217.81C387.87,-208.33 401.13,-195.95 412.48,-185.35"/>
<polygon fill="blue" stroke="blue" points="414.67,-188.09 419.6,-178.71 409.9,-182.98 414.67,-188.09"/>
</g>
<!-- Bool -->
<g id="node13" class="node">
<title>Bool</title>
<ellipse fill="none"  cx="361.43" cy="-18" rx="33.32" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="361.43" y="-13.32" font-family="Times,serif" font-size="14.00">Bool</text>
</g>
<!-- a2&#45;&gt;Bool -->
<g id="edge11" class="edge replaced">
<title>a2&#45;&gt;Bool</title>
<path fill="none"  d="M361.43,-143.59C361.43,-119.61 361.43,-76.14 361.43,-47.42"/>
<polygon   points="364.93,-47.62 361.43,-37.62 357.93,-47.62 364.93,-47.62"/>
</g>
<!-- Int -->
<g id="node15" class="node">
<title>Int</title>
<ellipse fill="none" stroke="blue" cx="436.43" cy="-90" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="436.43" y="-85.33" font-family="Times,serif" font-size="14.00">Int</text>
</g>
<!-- List&#45;&gt;Int -->
<g id="edge13" class="edge">
<title>List&#45;&gt;Int</title>
<path fill="none" stroke="blue" d="M436.43,-143.7C436.43,-136.41 436.43,-127.73 436.43,-119.54"/>
<polygon fill="blue" stroke="blue" points="439.93,-119.62 436.43,-109.62 432.93,-119.62 439.93,-119.62"/>
</g>
<!-- Int&#45;&gt;Bool -->
<g id="edge14" class="edge">
<title>Int&#45;&gt;Bool</title>
<path fill="none" stroke="blue" d="M421.25,-74.83C411.06,-65.32 397.4,-52.57 385.71,-41.66"/>
<polygon fill="blue" stroke="blue" points="388.43,-39.41 378.73,-35.15 383.65,-44.53 388.43,-39.41"/>
</g>
<!-- subst -->
<g id="node16" class="node">
<title>subst</title>
<ellipse fill="none" stroke="none" cx="481.43" cy="-306" rx="75.41" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="481.43" y="-301.32" font-family="Times,serif" font-size="14.00" fill="red">a := List(Int)</text>
</g>
</g>
</svg></div></p>
<p>And that’s it! This is enough to fully implement type class
resolution in languages like Haskell, Rust or PureScript.</p>
<h2 id="what-about-entailment">What about entailment?</h2>
<p>This can easily match simple instances, but what about instances like
<code>forall a. C(a) =&gt; C(List(a))</code>? Here,
<code>C(List(a))</code> <em>entails</em> <code>C(a)</code>, such that
<code>C(List(a))</code> only holds if <code>C(a)</code> holds. How do we
take that into account?</p>
<p>Well, following GHC’s footsteps, this is very easy: we don’t! Type
class resolution only matches the “instance head” (i.e. the part after
the <code>=&gt;</code>), so we only need to emit a <em>new</em>
constraint for <code>C(a)</code> when we land on that instance (using
our substitution to find the correct type for <code>a</code>).</p>
<p>This might seem a bit limiting and there are more elaborate systems
that can use entailment information, but in an open world setting like
type classes where any module might add new instances, these can have
some serious subtle downsides around modularity. Only matching on the
instance head is a very reasonable pragmatic choice that is enough to
cover most real world cases while keeping excellent performance.</p>
<h2 id="row-polymorphism">Row Polymorphism</h2>
<p>The system we covered so far works very well for classic ML-style
type systems that consist exclusively of (possibly parameterized) type
constructors, but not every type system is this simple.</p>
<p>A common type system extension is row polymorphism, which can be used
to model extensible records, polymorphic variants, and even algebraic
effects. How do we include this in our trie?</p>
<p>The fundamental issue with row polymorphism is that the order of
labels in a row does not matter. In other words,
<code>{ x : Int, y : Bool }</code> and
<code>{ y : Bool, x : Int }</code> are the same type (and hence,
depending on the instantiations of <code>a</code> and <code>b</code>,
even <code>{ x : Int | a }</code> and <code>{ y : Bool | b }</code>
might be equal). Depending on the exact flavor of your type system, rows
might be allowed to have duplicate labels. In that case, only the order
of <em>distinct</em> labels is irrelevant. For example,
<code>{ x : Int, y : Bool, x : String }</code> is equal to
<code>{ y : Bool, x : Int, x : String }</code>, but not
<code>{ x : String, x : Int, y : Bool }</code>.</p>
<p>How could we possibly represent type class instances for these types
in a trie?</p>
<p>The answer is actually surprisingly easy. We can treat the record
with only its labels as a head constructor, similar to what we did
before. Unlike before, we <em>canonicalize</em> rows by sorting their
fields. This is especially important if we want to use the trie to
detect two instances for exactly the same type (since we should probably
throw an error in that case).</p>
<p>A beautiful property of the duplicate label semantics outlined above
is that canonicalizing records with duplicate labels boils down to a
stable sort since it only needs to preserve the order of duplicate
labels.</p>
<p>For example, <code>{ y : Bool, x : Int }</code> will be canonicalized
to <code>{ x : Int, y : Bool }</code> and subsequently unrolled to</p>
<p><div class="dot-output"><?xml version="1.0" encoding="UTF-8" standalone="no"?>

<!-- Generated by graphviz version 14.0.5 (0)
 -->
<!-- Pages: 1 -->
<svg width="161pt" height="188pt"
 viewBox="0.00 0.00 161.00 188.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 184)">
<!-- { x : \_, y : \_ } -->
<g id="node1" class="node">
<title>{ x : \_, y : \_ }</title>
<ellipse fill="none"  cx="76.46" cy="-162" rx="76.46" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="76.46" y="-157.32" font-family="Times,serif" font-size="14.00">{ x : _, y : _ }</text>
</g>
<!-- Int -->
<g id="node2" class="node">
<title>Int</title>
<ellipse fill="none"  cx="76.46" cy="-90" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="76.46" y="-85.33" font-family="Times,serif" font-size="14.00">Int</text>
</g>
<!-- { x : \_, y : \_ }&#45;&gt;Int -->
<g id="edge1" class="edge">
<title>{ x : \_, y : \_ }&#45;&gt;Int</title>
<path fill="none"  d="M76.46,-143.7C76.46,-136.41 76.46,-127.73 76.46,-119.54"/>
<polygon   points="79.96,-119.62 76.46,-109.62 72.96,-119.62 79.96,-119.62"/>
</g>
<!-- Bool -->
<g id="node3" class="node">
<title>Bool</title>
<ellipse fill="none"  cx="76.46" cy="-18" rx="33.32" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="76.46" y="-13.32" font-family="Times,serif" font-size="14.00">Bool</text>
</g>
<!-- Int&#45;&gt;Bool -->
<g id="edge2" class="edge">
<title>Int&#45;&gt;Bool</title>
<path fill="none"  d="M76.46,-71.7C76.46,-64.41 76.46,-55.73 76.46,-47.54"/>
<polygon   points="79.96,-47.62 76.46,-37.62 72.96,-47.62 79.96,-47.62"/>
</g>
</g>
</svg></div></p>
<p>and <code>{ x : Int, y : Bool, x : String | a }</code> becomes</p>
<p><div class="dot-output"><?xml version="1.0" encoding="UTF-8" standalone="no"?>

<!-- Generated by graphviz version 14.0.5 (0)
 -->
<!-- Pages: 1 -->
<svg width="242pt" height="332pt"
 viewBox="0.00 0.00 242.00 332.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 328)">
<!-- { x : \_, x : \_, y : \_ | \_ } -->
<g id="node1" class="node">
<title>{ x : \_, x : \_, y : \_ | \_ }</title>
<ellipse fill="none"  cx="116.97" cy="-306" rx="116.97" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="116.97" y="-301.32" font-family="Times,serif" font-size="14.00">{ x : _, x : _, y : _ | _ }</text>
</g>
<!-- Int -->
<g id="node2" class="node">
<title>Int</title>
<ellipse fill="none"  cx="116.97" cy="-234" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="116.97" y="-229.32" font-family="Times,serif" font-size="14.00">Int</text>
</g>
<!-- { x : \_, x : \_, y : \_ | \_ }&#45;&gt;Int -->
<g id="edge1" class="edge">
<title>{ x : \_, x : \_, y : \_ | \_ }&#45;&gt;Int</title>
<path fill="none"  d="M116.97,-287.7C116.97,-280.41 116.97,-271.73 116.97,-263.54"/>
<polygon   points="120.47,-263.62 116.97,-253.62 113.47,-263.62 120.47,-263.62"/>
</g>
<!-- String -->
<g id="node3" class="node">
<title>String</title>
<ellipse fill="none"  cx="116.97" cy="-162" rx="42.79" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="116.97" y="-157.32" font-family="Times,serif" font-size="14.00">String</text>
</g>
<!-- Int&#45;&gt;String -->
<g id="edge2" class="edge">
<title>Int&#45;&gt;String</title>
<path fill="none"  d="M116.97,-215.7C116.97,-208.41 116.97,-199.73 116.97,-191.54"/>
<polygon   points="120.47,-191.62 116.97,-181.62 113.47,-191.62 120.47,-191.62"/>
</g>
<!-- Bool -->
<g id="node4" class="node">
<title>Bool</title>
<ellipse fill="none"  cx="116.97" cy="-90" rx="33.32" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="116.97" y="-85.33" font-family="Times,serif" font-size="14.00">Bool</text>
</g>
<!-- String&#45;&gt;Bool -->
<g id="edge3" class="edge">
<title>String&#45;&gt;Bool</title>
<path fill="none"  d="M116.97,-143.7C116.97,-136.41 116.97,-127.73 116.97,-119.54"/>
<polygon   points="120.47,-119.62 116.97,-109.62 113.47,-119.62 120.47,-119.62"/>
</g>
<!-- a -->
<g id="node5" class="node">
<title>a</title>
<ellipse fill="none"  cx="116.97" cy="-18" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="116.97" y="-13.32" font-family="Times,serif" font-size="14.00">a</text>
</g>
<!-- Bool&#45;&gt;a -->
<g id="edge4" class="edge">
<title>Bool&#45;&gt;a</title>
<path fill="none"  d="M116.97,-71.7C116.97,-64.41 116.97,-55.73 116.97,-47.54"/>
<polygon   points="120.47,-47.62 116.97,-37.62 113.47,-47.62 120.47,-47.62"/>
</g>
</g>
</svg></div></p>
<p>Now, when matching a type against a row head constructor like this,
we move the types from the head constructor labels to the front in
canonical order. This ensures that they are matched against the correct
trie fields and keeps the remaining row to be matched against the
extension variable if applicable.</p>
<p>For example, this is how one possible match could behave</p>
<p><div class="dot-output"><?xml version="1.0" encoding="UTF-8" standalone="no"?>

<!-- Generated by graphviz version 14.0.5 (0)
 -->
<!-- Pages: 1 -->
<svg width="586pt" height="260pt"
 viewBox="0.00 0.00 586.00 260.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 256)">
<!-- record -->
<g id="node1" class="node">
<title>record</title>
<text xml:space="preserve" text-anchor="middle" x="132.23" y="-229.32" font-family="Times,serif" font-size="14.00" fill="red">{ z : String, y : Bool, x : Int }</text>
</g>
<!-- Int | String | { y : Bool } -->
<g id="node2" class="node">
<title>Int | String | { y : Bool }</title>
<ellipse fill="none" stroke="none" cx="132.23" cy="-162" rx="132.23" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="132.23" y="-157.32" font-family="Times,serif" font-size="14.00" fill="red">Int | String | { y : Bool }</text>
</g>
<!-- record&#45;&gt;Int | String | { y : Bool } -->
<g id="edge1" class="edge">
<title>record&#45;&gt;Int | String | { y : Bool }</title>
<path fill="none" stroke="none" d="M132.23,-216.05C132.23,-208.68 132.23,-199.84 132.23,-191.51"/>
<polygon fill="none" stroke="none" points="135.73,-191.79 132.23,-181.79 128.73,-191.79 135.73,-191.79"/>
</g>
<!-- String | { y : Bool } -->
<g id="node3" class="node">
<title>String | { y : Bool }</title>
<ellipse fill="none" stroke="none" cx="132.23" cy="-90" rx="108.55" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="132.23" y="-85.33" font-family="Times,serif" font-size="14.00" fill="red">String | { y : Bool }</text>
</g>
<!-- Int | String | { y : Bool }&#45;&gt;String | { y : Bool } -->
<g id="edge2" class="edge">
<title>Int | String | { y : Bool }&#45;&gt;String | { y : Bool }</title>
<path fill="none" stroke="none" d="M132.23,-143.7C132.23,-136.41 132.23,-127.73 132.23,-119.54"/>
<polygon fill="none" stroke="none" points="135.73,-119.62 132.23,-109.62 128.73,-119.62 135.73,-119.62"/>
</g>
<!-- { y : Bool } -->
<g id="node4" class="node">
<title>{ y : Bool }</title>
<ellipse fill="none" stroke="none" cx="132.23" cy="-18" rx="67.52" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="132.23" y="-13.32" font-family="Times,serif" font-size="14.00" fill="red">{ y : Bool }</text>
</g>
<!-- String | { y : Bool }&#45;&gt;{ y : Bool } -->
<g id="edge3" class="edge">
<title>String | { y : Bool }&#45;&gt;{ y : Bool }</title>
<path fill="none" stroke="none" d="M132.23,-71.7C132.23,-64.41 132.23,-55.73 132.23,-47.54"/>
<polygon fill="none" stroke="none" points="135.73,-47.62 132.23,-37.62 128.73,-47.62 135.73,-47.62"/>
</g>
<!-- rowhead -->
<g id="node5" class="node">
<title>rowhead</title>
<ellipse fill="none"  cx="351.23" cy="-234" rx="90.14" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="351.23" y="-229.32" font-family="Times,serif" font-size="14.00">{ x : _, z : _ | _ }</text>
</g>
<!-- Int -->
<g id="node6" class="node">
<title>Int</title>
<ellipse fill="none"  cx="351.23" cy="-162" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="351.23" y="-157.32" font-family="Times,serif" font-size="14.00">Int</text>
</g>
<!-- rowhead&#45;&gt;Int -->
<g id="edge4" class="edge">
<title>rowhead&#45;&gt;Int</title>
<path fill="none"  d="M351.23,-215.7C351.23,-208.41 351.23,-199.73 351.23,-191.54"/>
<polygon   points="354.73,-191.62 351.23,-181.62 347.73,-191.62 354.73,-191.62"/>
</g>
<!-- String -->
<g id="node7" class="node">
<title>String</title>
<ellipse fill="none"  cx="351.23" cy="-90" rx="42.79" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="351.23" y="-85.33" font-family="Times,serif" font-size="14.00">String</text>
</g>
<!-- Int&#45;&gt;String -->
<g id="edge5" class="edge">
<title>Int&#45;&gt;String</title>
<path fill="none"  d="M351.23,-143.7C351.23,-136.41 351.23,-127.73 351.23,-119.54"/>
<polygon   points="354.73,-119.62 351.23,-109.62 347.73,-119.62 354.73,-119.62"/>
</g>
<!-- a -->
<g id="node8" class="node">
<title>a</title>
<ellipse fill="none"  cx="351.23" cy="-18" rx="27" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="351.23" y="-13.32" font-family="Times,serif" font-size="14.00">a</text>
</g>
<!-- String&#45;&gt;a -->
<g id="edge6" class="edge">
<title>String&#45;&gt;a</title>
<path fill="none"  d="M351.23,-71.7C351.23,-64.41 351.23,-55.73 351.23,-47.54"/>
<polygon   points="354.73,-47.62 351.23,-37.62 347.73,-47.62 354.73,-47.62"/>
</g>
<!-- a := { y : Bool } -->
<g id="node9" class="node">
<title>a := { y : Bool }</title>
<ellipse fill="none" stroke="none" cx="487.23" cy="-18" rx="91.19" ry="18"/>
<text xml:space="preserve" text-anchor="middle" x="487.23" y="-13.32" font-family="Times,serif" font-size="14.00" fill="red">a := { y : Bool }</text>
</g>
</g>
</svg></div></p>
<h2 id="overlapping-instances">Overlapping instances</h2>
<p>Usually, requiring type class resolution to come up with a single
unambiguous instance is the right choice, but sometimes it makes sense
to disambiguate explicitly and let the compiler choose one instance over
another. Can we do this with our trie?</p>
<p>Yes! In fact, since we report every matching candidate, we can
perform this disambiguation entirely on the result of type class
resolution without ever touching our trie. The exact rules for how to do
this can be a bit subtle, but one reasonable approach is the one taken
by GHC, which is documented <a
href="https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/instances.html#overlapping-instances">in
the fantastic GHC User’s Guide</a><a href="#fn3" class="footnote-ref"
id="fnref3" role="doc-noteref"><sup>3</sup></a>.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Even if you don’t plan on implementing a programming language with
type classes any time soon (why not?), there are a few things I would
like you to take away from this.</p>
<ul>
<li>Tries are awesome!</li>
<li>Picking the right data structures is incredibly important, even in
domains like type checkers where they typically don’t receive that much
love.</li>
<li>There is a lot to be gained by applying knowledge from one area of
computer science (e.g. text processing) to another (e.g. type
checking)</li>
</ul>
<p>If nothing else, this gave me a great opportunity to try out GraphViz
support on my blog.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>To my knowledge at the time of writing anyway. They
might have moved to something more efficient by now.<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>sorry.<a href="#fnref2" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>Seriously, this is an incredibly underrated resource for
nearly everything related to Haskell and GHC.<a href="#fnref3"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
    <pubDate>Mon, 19 Feb 2024 00:00:00 +0100</pubDate>
</item><item>
    <title>Fast Map Union and Local Instances Through Instance Types</title>
    <link>https://welltypedwit.ch/posts/insttypes.html</link>
    <guid isPermaLink="true">https://welltypedwit.ch/posts/insttypes.html</guid>
    <description><![CDATA[<p></p>
<p>In part 3<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a> of my <a
href="/posts/unsafeCoerceDict.html">crusade against</a> <a
href="/posts/coherentIP.html">GHC’s coherence guarantees</a>, I have
actually done it! This time we will end up with a way to generate local
type class instances without any asterisks about code breaking with
optimizations. On the way, we are going to end up solving the dreaded
Fast Map Union Problem, combining two of my favorite Haskell tricks, and
discovering a bug in a previous version of GHC.</p>
<p>But before we get to that, let’s start at the beginning</p>
<h2 id="what-even-is-this-fast-map-union-problem">What even is this
‘fast Map union problem’?</h2>
<p>Let’s pretend that Haskell <em>did</em> have consistent locally
overridable type class instances. In that case, the interface for
<code>Map</code> would be completely broken.</p>
<p>Look at the type of <code>Data.Map.insert</code></p>
<div class="sourceCode" id="cb1"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ot">insert ::</span> <span class="dt">Ord</span> k <span class="ot">=&gt;</span> k <span class="ot">-&gt;</span> v <span class="ot">-&gt;</span> <span class="dt">Map</span> k v <span class="ot">-&gt;</span> <span class="dt">Map</span> k v</span></code></pre></div>
<p>See the issue? <code>Map</code> is some kind of ordered tree
internally, so it depends on the <code>Ord</code> instance being
consistent across different operations, but with local instances, we
don’t have any guarantees like that.</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- This uses the regular instance for Ord Int</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> <span class="fu">map</span> <span class="ot">=</span> insert (<span class="dv">1</span><span class="ot"> ::</span> <span class="dt">Int</span>) <span class="dv">1</span> <span class="fu">mempty</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="co">-- This uses a different, incompatible instance on the same map!</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>withLocalOrd reverseOrdInt <span class="op">$</span> insert (<span class="dv">2</span><span class="ot"> ::</span> <span class="dt">Int</span>) <span class="dv">2</span> <span class="fu">map</span> </span></code></pre></div>
<p>If you think about this for a bit, you may come up with a solution:
You can store the instance in the map. This is how most map
implementations in other languages work after all.</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Map</span> k v <span class="ot">=</span> <span class="dt">MkMap</span> (<span class="dt">Dict</span> (<span class="dt">Ord</span> k)) (<span class="dt">ActualMapImplementation</span> k v)</span></code></pre></div>
<p>And now the type of insert doesn’t mention <code>Ord</code> at all
anymore so everything is sunshine and roses</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="ot">insert ::</span> k <span class="ot">-&gt;</span> v <span class="ot">-&gt;</span> <span class="dt">Map</span> k v <span class="ot">-&gt;</span> <span class="dt">Map</span> k v</span></code></pre></div>
<p>…until it isn’t! Consider the type of <code>union</code> now</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="ot">union ::</span> <span class="dt">Map</span> k v <span class="ot">-&gt;</span> <span class="dt">Map</span> k v <span class="ot">-&gt;</span> <span class="dt">Map</span> k v</span></code></pre></div>
<p>What happens if both maps use different <code>Ord k</code> instances?
We have no way to statically ensure that they don’t. The way to solve
this in practice would be to just reinsert every value from one map in
the other, but that means that union is now drastically slower than it
would be if we could assume that both maps use the same instance (It’s
now at least linear in the size of one map vs. logarithmic in that of
the smaller one).</p>
<h2 id="instance-types">Instance Types</h2>
<p>Now, what we really need here is a way to statically ensure that both
maps use the same <code>Ord</code> implementation. In a dependently
typed language, one could just carry the instance dictionary in the
type</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Map</span> k v (<span class="ot">inst ::</span> <span class="dt">Ord</span> k) <span class="ot">=</span> <span class="op">...</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="ot">union ::</span> <span class="dt">Map</span> k v inst <span class="ot">-&gt;</span> <span class="dt">Map</span> k v inst <span class="ot">-&gt;</span> <span class="dt">Map</span> k v inst</span></code></pre></div>
<p>But we cannot do that in Haskell (yet?), so we need a few more
tricks. What we absolutely <em>need</em> to do is to somehow move the
used instance to the type level, so let’s start there. While we cannot
directly depend on the instance value, we can define a dummy type as a
stand-in.</p>
<p>With this new type, we can write a version of <code>Ord</code> that
carries its concrete instance in the type. Every function with an
<code>Ord</code> constraint should now be polymorphic over this instance
parameter.</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">OrdI</span> inst a <span class="op">|</span> inst <span class="ot">-&gt;</span> a <span class="kw">where</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="ot">    compareI ::</span> a <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">Ordering</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">RegularOrdInt</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">OrdI</span> <span class="dt">RegularOrdInt</span> <span class="dt">Int</span> <span class="kw">where</span></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>    compareI <span class="ot">=</span> <span class="fu">compare</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">ReverseOrdInt</span></span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">OrdI</span> <span class="dt">ReverseOrdInt</span> <span class="dt">Int</span> <span class="kw">where</span></span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a>    compareI x y <span class="ot">=</span> <span class="kw">case</span> <span class="fu">compare</span> x y <span class="kw">of</span></span>
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a>        <span class="dt">LT</span> <span class="ot">-&gt;</span> <span class="dt">GT</span></span>
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true" tabindex="-1"></a>        <span class="dt">EQ</span> <span class="ot">-&gt;</span> <span class="dt">EQ</span></span>
<span id="cb7-13"><a href="#cb7-13" aria-hidden="true" tabindex="-1"></a>        <span class="dt">GT</span> <span class="ot">-&gt;</span> <span class="dt">LT</span></span></code></pre></div>
<p>And now we can finally parameterize Map over the used
<code>Ord</code> instance!</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">IMap</span> inst k v <span class="ot">=</span> <span class="op">...</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="ot">insert ::</span> <span class="dt">OrdI</span> inst k <span class="ot">=&gt;</span> k <span class="ot">-&gt;</span> v <span class="ot">-&gt;</span> <span class="dt">IMap</span> inst k v <span class="ot">-&gt;</span> <span class="dt">IMap</span> inst k v</span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="ot">union ::</span> <span class="dt">OrdI</span> inst k <span class="ot">=&gt;</span> <span class="dt">IMap</span> inst k v <span class="ot">-&gt;</span> <span class="dt">IMap</span> inst k v <span class="ot">-&gt;</span> <span class="dt">IMap</span> inst k v</span></code></pre></div>
<p><code>union</code> statically ensures that both maps agree on their
instances.</p>
<p>The only ‘issue’ here is that we lose some inference. This is more or
less unavoidable if we want multiple instances to coexist (well, more on
that later). We need to tell Haskell what instance to use at some point,
but it’s not that bad, since at least for <code>IMap</code>s, which
carry the instance in their type, we only need to do this once.</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> map1 <span class="ot">=</span> insert <span class="dv">1</span> <span class="dv">1</span> <span class="op">$</span> insert <span class="dv">2</span> <span class="dv">2</span> <span class="op">$</span> empty <span class="op">@</span><span class="dt">RegularOrdInt</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> map2 <span class="ot">=</span> insert <span class="op">@</span><span class="dt">ReverseOrdInt</span> <span class="dv">3</span> <span class="dv">3</span> <span class="op">$</span> insert <span class="dv">4</span> <span class="dv">4</span> <span class="op">$</span> empty</span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>union map1 map2 <span class="co">-- Type error: Couldn&#39;t match type &#39;RegularOrdInt&#39; with `ReverseOrdInt`</span></span></code></pre></div>
<h2 id="how-do-local-instances-fit-into-this">How do local instances fit
into this?</h2>
<p>Quite well as it turns out! We can combine two of my favorite Haskell
tricks to implement them in current Haskell (You can stop pretending
that they exist. We are going to implement them for real now)</p>
<p>Local instances might differ between different executions of the same
code, so we need to make sure that the instance types can only be used
locally and cannot escape. If this sounds familiar that is because there
is a decent chance that you have used something similar before: <a
href="https://hackage.haskell.org/package/base-4.17.0.0/docs/Control-Monad-ST.html#v:runST"><code>runST</code></a>.</p>
<p><code>ST</code> is a monad that is used for local mutability inside
pure code. You can use it to create <code>STRef</code>s and mutate them,
just like you would in your favorite imperative language<a href="#fn2"
class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a>,
except that Haskell, by virtue of being a pure language, needs to make
absolutely sure that you never ever return an <code>STRef</code> from
<code>runST</code>. Doing so would allow effects in one usage of the
supposedly pure <code>runST</code> to affect the result of another
one.</p>
<p>How does <code>ST</code> do this? It uses higher-rank types!</p>
<div class="sourceCode" id="cb10"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="ot">newSTRef ::</span> a <span class="ot">-&gt;</span> <span class="dt">ST</span> s (<span class="dt">STRef</span> s a)</span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="ot">runST ::</span> (<span class="kw">forall</span> s<span class="op">.</span> <span class="dt">ST</span> s a) <span class="ot">-&gt;</span> a</span></code></pre></div>
<p>If you have never seen this before, you’re probably quite confused
right now. The type <code>forall s. ST s a</code> specifies that the
argument to <code>runST</code> needs to be an <code>ST</code> value that
works for any possible instantiation of <code>s</code>. Crucially for
this case, this means that the <code>s</code> variable is, unlike
<code>a</code>, <em>not</em> a type parameter of <code>runST</code>
itself, but actually one of <em>the arguments to runST</em>. This is
much clearer if we write <code>runST</code> with an explicit outer
<code>forall</code>.</p>
<div class="sourceCode" id="cb11"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="ot">runST ::</span> <span class="kw">forall</span> a<span class="op">.</span> (<span class="kw">forall</span> s<span class="op">.</span> <span class="dt">ST</span> s a) <span class="ot">-&gt;</span> a</span></code></pre></div>
<p>Now, the reason this ensures that no STRefs escape is that the
<code>s</code> parameter of the <code>STRef</code> is the same as that
of the containing <code>ST</code> monad. If you <em>were</em> able to
return an <code>STRef</code> from the argument to <code>runST</code>,
e.g. by passing something of type
<code>forall s. ST s (STRef s Int)</code>, what type would the result
have? Blindly substituting would yield <code>STRef s Int</code>, but
what is <code>s</code> now? Previously, <code>s</code> was bound by the
<code>forall</code> in the type of the argument to <code>runST</code>,
but that <code>forall</code> does not exist anymore! This is why GHC
will not accept this code and complain about an ‘escaping skolem’.</p>
<p>We can use exactly the same trick for local type class instances to
invent an instance type that only exists locally! If we can implement a
function of the following type, then this will ensure that instance
types cannot possibly escape.</p>
<div class="sourceCode" id="cb12"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="ot">withOrdI ::</span> <span class="kw">forall</span> a b<span class="op">.</span> (a <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">Ordering</span>) <span class="ot">-&gt;</span> (<span class="kw">forall</span> inst<span class="op">.</span> <span class="dt">OrdI</span> inst a <span class="ot">=&gt;</span> b) <span class="ot">-&gt;</span> b</span></code></pre></div>
<p>Now, how do we implement this function? If you read <a
href="/posts/unsafeCoerceDict.html">the first post in this series</a>,
you will probably know the answer already.</p>
<p>At runtime, GHC represents type classes via a technique called
dictionary passing. This means that a function with an <code>Ord</code>
constraint like <code>Ord a =&gt; a -&gt; a -&gt; Ordering</code> will
be turned into a function that <em>takes an implementation of that type
class as an argument</em> (<code>Ord a -&gt; a -&gt; a</code>). This
implementation, called a dictionary, is just a regular record-like data
type that contains an implementation for every method.</p>
<p>Using <code>GADT</code>s, we can capture this dictionary in a
value.</p>
<div class="sourceCode" id="cb13"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">OrdIDict</span> a <span class="kw">where</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>    <span class="dt">OrdIDict</span><span class="ot"> ::</span> <span class="dt">Ord</span> a <span class="ot">=&gt;</span> <span class="dt">OrdIDict</span> a</span></code></pre></div>
<p>If we are now able to replicate the structure of this
<code>OrdIDict</code> exactly, but with a custom record of methods, we
can use <code>unsafeCoerce</code> to convert it to a functional
<code>OrdIDict a</code>. By pattern matching on the result, we can
release the dictionary back into a regular instance, which now contains
our handwritten type class instance!</p>
<p>Instinctively, your definition of <code>OrdIDict</code> would
probably look like this</p>
<div class="sourceCode" id="cb14"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">OrdIDict</span> inst a <span class="kw">where</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a>    <span class="dt">OrdIDict</span><span class="ot"> ::</span> <span class="dt">OrdI</span> inst a <span class="ot">=&gt;</span> <span class="dt">OrdIDict</span> inst a</span></code></pre></div>
<p>This is not going to work though. We need to invent a new type for
<code>inst</code>, so <code>OrdIDict</code> cannot take it as a
parameter. Thanks to Haskell’s support for existential types, this is
not actually an issue, since we can just leave it off<a href="#fn3"
class="footnote-ref" id="fnref3"
role="doc-noteref"><sup>3</sup></a>.</p>
<div class="sourceCode" id="cb15"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">OrdIDict</span> a <span class="kw">where</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>    <span class="dt">OrdIDict</span><span class="ot"> ::</span> <span class="dt">OrdI</span> inst a <span class="ot">=&gt;</span> <span class="dt">OrdIDict</span> a</span></code></pre></div>
<p><code>OrdI</code> only has a single method, so it will be represented
by the equivalent of a newtype record at runtime. This is erased
entirely, so we do not need to build a record around our
<code>a -&gt; a -&gt; Ordering</code> function.</p>
<p>The <code>OrdIDict</code> wrapper adds some indirection though, so we
need to replicate that.</p>
<div class="sourceCode" id="cb16"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">FakeDict</span> a <span class="ot">=</span> <span class="dt">FakeDict</span> a</span></code></pre></div>
<p>All preparations are complete. We are ready for the magic<a
href="#fn4" class="footnote-ref" id="fnref4"
role="doc-noteref"><sup>4</sup></a>!</p>
<div class="sourceCode" id="cb17"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="ot">withOrdI ::</span> <span class="kw">forall</span> a b<span class="op">.</span> (a <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">Ordering</span>) <span class="ot">-&gt;</span> (<span class="kw">forall</span> inst<span class="op">.</span> <span class="dt">OrdI</span> inst a <span class="ot">=&gt;</span> b) <span class="ot">-&gt;</span> b</span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a>withOrdI dict body <span class="ot">=</span> </span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">case</span> unsafeCoerce (<span class="dt">FakeDict</span> dict)<span class="ot"> ::</span> <span class="dt">OrdIDict</span> a <span class="kw">of</span></span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a>        (<span class="dt">OrdIDict</span> <span class="op">@</span>inst) <span class="ot">-&gt;</span> body <span class="op">@</span>inst</span></code></pre></div>
<p>And that’s… it!</p>
<p>Well, not quite. If you paid very close attention, you may notice
that we have no way to bind the <code>inst</code> type variable in the
<code>(forall inst. OrdI inst a =&gt; b)</code> argument. This means if
we put a lambda there, we cannot actually mention <code>inst</code>
anywhere. This is easy enough to solve by introducing a <a
href="https://hackage.haskell.org/package/base-4.17.0.0/docs/Data-Proxy.html#t:Proxy"><code>Proxy</code></a>
value.</p>
<div class="sourceCode" id="cb18"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="ot">withOrdIProxy ::</span> <span class="kw">forall</span> a b<span class="op">.</span> (a <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">Ordering</span>) <span class="ot">-&gt;</span> (<span class="kw">forall</span> inst<span class="op">.</span> <span class="dt">OrdI</span> inst a <span class="ot">=&gt;</span> <span class="dt">Proxy</span> inst <span class="ot">-&gt;</span> b) <span class="ot">-&gt;</span> b</span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a>withOrdIProxy dict body <span class="ot">=</span> </span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">case</span> unsafeCoerce (<span class="dt">FakeDict</span> dict)<span class="ot"> ::</span> <span class="dt">OrdIDict</span> a <span class="kw">of</span></span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a>        (<span class="dt">OrdIDict</span> <span class="op">@</span>inst) <span class="ot">-&gt;</span> body <span class="op">@</span>inst (<span class="dt">Proxy</span> <span class="op">@</span>inst)</span></code></pre></div>
<h2 id="lets-try-it-out">Let’s try it out!</h2>
<p>We can start with some concrete instances</p>
<div class="sourceCode" id="cb19"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a>map1 <span class="ot">=</span> insert <span class="dv">1</span> <span class="dv">1</span> (empty <span class="op">@</span><span class="dt">Int</span>)</span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a>map2 <span class="ot">=</span> insert <span class="dv">2</span> <span class="dv">2</span> (empty <span class="op">@</span><span class="dt">Int</span>)</span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a>map3 <span class="ot">=</span> insert <span class="dv">3</span> <span class="dv">3</span> (empty <span class="op">@</span><span class="dt">ReverseIntOrd</span>)</span>
<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a>map4 <span class="ot">=</span> insert <span class="dv">4</span> <span class="dv">4</span> (empty <span class="op">@</span><span class="dt">ReverseIntOrd</span>)</span>
<span id="cb19-6"><a href="#cb19-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-7"><a href="#cb19-7" aria-hidden="true" tabindex="-1"></a>fine1 <span class="ot">=</span> union map1 map2</span>
<span id="cb19-8"><a href="#cb19-8" aria-hidden="true" tabindex="-1"></a>fine2 <span class="ot">=</span> union map3 map4</span>
<span id="cb19-9"><a href="#cb19-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-10"><a href="#cb19-10" aria-hidden="true" tabindex="-1"></a>notFine <span class="ot">=</span> union map1 map3 <span class="co">-- fails!</span></span></code></pre></div>
<p>Looking good. Now let’s try local instances</p>
<div class="sourceCode" id="cb20"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a>local <span class="ot">=</span> withOrdIProxy <span class="fu">compare</span> \(<span class="dt">Proxy</span> <span class="op">@</span>inst) <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span><span class="ot"> localMap1 ::</span> <span class="dt">IMap</span> inst <span class="dt">Int</span> <span class="dt">Int</span> <span class="ot">=</span> insert <span class="op">@</span>inst <span class="dv">1</span> <span class="dv">1</span> (empty <span class="op">@</span>inst)</span>
<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a>    ()</span></code></pre></div>
<div class="sourceCode" id="cb21"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> ghc-9.2 insttypes.hs</span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a><span class="ex">insttypes.hs:80:42:</span> error:</span>
<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a>    <span class="ex">•</span> Could not deduce <span class="er">(</span><span class="ex">OrdI</span> <span class="er">(</span><span class="ex">*</span><span class="kw">)</span> <span class="ex">Int</span><span class="kw">)</span> <span class="ex">arising</span> from a use of ‘insert’</span>
<span id="cb21-4"><a href="#cb21-4" aria-hidden="true" tabindex="-1"></a>      <span class="ex">from</span> the context: OrdI inst a0</span>
<span id="cb21-5"><a href="#cb21-5" aria-hidden="true" tabindex="-1"></a>    <span class="ex">...</span></span></code></pre></div>
<p>Huh. That is… strange. It looks like for some strange reason, GHC
defaults the <code>inst</code> parameter to… <code>(*)</code><a
href="#fn5" class="footnote-ref" id="fnref5"
role="doc-noteref"><sup>5</sup></a>? Even if we add as many type
annotations as physically possible?</p>
<p>If this smells like a bug in GHC, that is <strong>because it
is!</strong> Or well, <em>was</em>.</p>
<p>If you run the same example with GHC 9.4, it will compile without
complaining.</p>
<p>Now, let’s try that again</p>
<div class="sourceCode" id="cb22"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a>local <span class="ot">=</span> withOrdIProxy <span class="fu">compare</span> \(<span class="dt">Proxy</span> <span class="op">@</span>inst) <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> localMap1 <span class="ot">=</span> insert <span class="dv">1</span> <span class="dv">1</span> (empty <span class="op">@</span>inst)</span>
<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> localMap2 <span class="ot">=</span> insert <span class="dv">2</span> <span class="dv">2</span> (empty <span class="op">@</span>inst)</span>
<span id="cb22-4"><a href="#cb22-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb22-5"><a href="#cb22-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> perfectlyFine <span class="ot">=</span> union localMap1 localMap2</span>
<span id="cb22-6"><a href="#cb22-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb22-7"><a href="#cb22-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span><span class="ot"> notFine ::</span> <span class="dt">IMap</span> <span class="dt">RegularIntOrd</span> <span class="dt">Int</span> <span class="dt">Int</span> <span class="ot">=</span> insert <span class="op">@</span>inst <span class="dv">2</span> <span class="dv">2</span> (empty <span class="op">@</span>inst) <span class="co">-- fails!</span></span>
<span id="cb22-8"><a href="#cb22-8" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> notFine2 <span class="ot">=</span> union localMap1 map1 <span class="co">-- also fails!</span></span>
<span id="cb22-9"><a href="#cb22-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb22-10"><a href="#cb22-10" aria-hidden="true" tabindex="-1"></a>    localMap1 <span class="co">-- fails!</span></span></code></pre></div>
<p>Perfect!</p>
<h3 id="do-we-have-to-annotate-the-instance-every-time">Do we have to
annotate the instance every time?</h3>
<p>In this specific example with <code>IMap</code>, the number of type
annotations required was quite manageable, but in code that uses
<code>OrdI</code> like regular <code>Ord</code>, this is much less
pleasant</p>
<div class="sourceCode" id="cb23"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true" tabindex="-1"></a><span class="ot">min3 ::</span> <span class="dt">IOrd</span> inst a <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> a</span>
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a>min3 x y z <span class="ot">=</span> <span class="kw">case</span> <span class="fu">compare</span> <span class="op">@</span>inst x y <span class="kw">of</span> <span class="co">-- needs a type application!</span></span>
<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a>    <span class="dt">GT</span> <span class="ot">-&gt;</span> <span class="kw">case</span> <span class="fu">compare</span> <span class="op">@</span>inst y z <span class="kw">of</span> <span class="co">-- this one as well</span></span>
<span id="cb23-4"><a href="#cb23-4" aria-hidden="true" tabindex="-1"></a>        <span class="dt">GT</span> <span class="ot">-&gt;</span> z</span>
<span id="cb23-5"><a href="#cb23-5" aria-hidden="true" tabindex="-1"></a>        _ <span class="ot">-&gt;</span> y</span>
<span id="cb23-6"><a href="#cb23-6" aria-hidden="true" tabindex="-1"></a>    _ <span class="ot">-&gt;</span> <span class="kw">case</span> <span class="fu">compare</span> <span class="op">@</span>inst x z <span class="kw">of</span> <span class="co">-- same here</span></span>
<span id="cb23-7"><a href="#cb23-7" aria-hidden="true" tabindex="-1"></a>        <span class="dt">GT</span> <span class="ot">-&gt;</span> <span class="kw">case</span> <span class="fu">compare</span> <span class="op">@</span>inst y z <span class="kw">of</span> <span class="co">-- also here</span></span>
<span id="cb23-8"><a href="#cb23-8" aria-hidden="true" tabindex="-1"></a>            <span class="dt">GT</span> <span class="ot">-&gt;</span> z</span>
<span id="cb23-9"><a href="#cb23-9" aria-hidden="true" tabindex="-1"></a>            _ <span class="ot">-&gt;</span> y</span>
<span id="cb23-10"><a href="#cb23-10" aria-hidden="true" tabindex="-1"></a>        _ <span class="ot">-&gt;</span> x</span></code></pre></div>
<p>Used directly like this, this technique is really just <a
href="https://www.haskellforall.com/2012/05/scrap-your-type-classes.html">Scrap
your type classes</a> with extra steps.</p>
<p>This is frustrating because we are just running up against GHC’s
stubbornness here. There is only a single possible instance for
<code>IOrd inst a</code> in scope, but GHC doesn’t want to choose it.
Usually, this behavior might make sense, but it’s really not helpful for
us.</p>
<p>Fortunately for us though, we are not the first to run into this
issue! <a
href="https://hackage.haskell.org/package/polysemy">Polysemy</a>, the
popular effect system library, had the exact same problem. Polysemy
makes it possible to define effects of the form
<code>Member Effect r</code> over a set of effects <code>r</code>. The
issue here is that, unlike <a
href="https://hackage.haskell.org/package/mtl">mtl</a>, Polysemy allows
duplicate effects, so GHC again doesn’t trust that you really wanted to
use the constraint from the signature and not another, currently
unwritten one.</p>
<p>How did Polysemy solve that? They wrote <a
href="https://hackage.haskell.org/package/polysemy-plugin">a type
checker plugin</a> that disambiguates Polysemy constraints whenever
there is exactly one relevant instance in scope.</p>
<p>This is exactly what we want, so we could probably copy most of
it.</p>
<p>But that is a topic for a future blog post.</p>
<h2 id="conclusion">Conclusion</h2>
<p>We covered quite a bit of ground there.</p>
<ul>
<li>We parameterized type classes over a type representing the
instance</li>
<li>This made it possible to statically ensure that maps can safely be
merged in logarithmic time, even in the presence of local instances</li>
<li>We managed to implement local type class instances that are actually
safe, even in the presence of optimizations</li>
<li>We discovered a bug in GHC 9.2</li>
<li>There is probably a way to avoid unnecessary type applications with
a GHC plugin</li>
</ul>
<p>This is the first time in this series that I can write a conclusion
without begging you to ‘please never ever use this anywhere near
production’. This technique still relies on GHC’s internal type class
representation (and you should always be careful around
<code>unsafeCoerce</code>) but so does the popular <a
href="https://hackage.haskell.org/package/reflection">reflection</a>
package, so you should be fine.</p>
<p>If you want to try this for yourself, you can get the code <a
href="https://gist.github.com/Innf107/53f1b6e2fdbb1ca0a49d1f75375c036c">in
a gist</a>. Just make sure to use GHC 9.4 or above.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>You don’t need to have read any of the previous posts to
understand this, don’t worry. On the other hand, if you like this one,
you will probably enjoy the others as well ;)<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>If your favorite imperative language is OCaml or
Standard ML that is.<a href="#fnref2" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>In fact, pattern matching on a value containing an
existentially quantified type variable will turn that variable into a
‘skolem’, just like the higher rank type in the <code>runST</code>
example, so we are truly conjuring a new type from thin air with this.<a
href="#fnref3" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn4"><p>This is an OCaml joke. Don’t worry about it.<a
href="#fnref4" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn5"><p><code>(*)</code> is another way of writing <a
href="https://hackage.haskell.org/package/base-4.17.0.0/docs/Data-Kind.html#t:Type"><code>Type</code></a>,
the type of types. The only reason this is even valid is that modern GHC
Haskell has dependent kinds and <code>Type : Type</code>.<a
href="#fnref5" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
    <pubDate>Sun, 26 Feb 2023 00:00:00 +0100</pubDate>
</item><item>
    <title>Coherent Local Instances with Dynamic Types and <code>ImplicitParams</code></title>
    <link>https://welltypedwit.ch/posts/coherentIP.html</link>
    <guid isPermaLink="true">https://welltypedwit.ch/posts/coherentIP.html</guid>
    <description><![CDATA[<p> If you read my <a
href="/posts/unsafeCoerceDict.html">previous post</a><a href="#fn1"
class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>
about local instances, you might have noticed something. Remember how I
said that <code>ImplicitParams</code> are really just <a
href="/posts/unsafeCoerceDict.html#implicitparams">syntactic sugar for
instances of the type class <code>GHC.Classes.IP</code></a>? Well,
unlike <code>withFakeDict</code>, <code>ImplicitParams</code> can safely
be overridden, without causing incoherence issues. Couldn’t we somehow
use <code>ImplicitParams</code> to provide local type class instances
that can safely be overridden?</p>
<p>Most type classes are a bit more complex than they look, so let’s
invent a new one to use as a running example.</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Pretty</span> a <span class="kw">where</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="ot">    pretty ::</span> a <span class="ot">-&gt;</span> <span class="dt">String</span></span></code></pre></div>
<p><code>Pretty</code> is just like <code>Show</code>, but with fewer
methods and no preexisting instances that might get in our way.</p>
<p>We also need to define a dictionary type for <code>Pretty</code>. We
could use the Template Haskell machinery from last time for this, but
<code>Pretty</code> is simple enough to do it manually for now.</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- The newtype is important since `Pretty` only has a single method</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">PrettyDict</span> a <span class="ot">=</span> <span class="dt">PrettyDict</span> {</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="ot">    _pretty ::</span> a <span class="ot">-&gt;</span> <span class="dt">String</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>}</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="ot">boringPretty ::</span> <span class="dt">PrettyDict</span> <span class="dt">Int</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>boringPretty <span class="ot">=</span> <span class="dt">PrettyDict</span> {</span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>    _pretty <span class="ot">=</span> <span class="fu">show</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>}</span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a><span class="ot">nicePretty ::</span> <span class="dt">PrettyDict</span> <span class="dt">Int</span></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a>nicePretty <span class="ot">=</span> <span class="dt">PrettyDict</span> {</span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a>    _pretty <span class="ot">=</span> \x <span class="ot">-&gt;</span> <span class="st">&quot;✨&quot;</span> <span class="op">&lt;&gt;</span> <span class="fu">show</span> x <span class="op">&lt;&gt;</span> <span class="st">&quot;✨&quot;</span></span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p>With this, we could already write a few functions that use our ‘type
class’, just by accepting a corresponding dictionary as an implicit
parameter. This way we actually get something closely resembling local
instances already!</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="ot">pretty ::</span> (<span class="op">?</span><span class="ot">prettyInst ::</span> <span class="dt">PrettyDict</span> a) <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">String</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>pretty <span class="ot">=</span> _pretty <span class="op">?</span>prettyInst</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="ot">f ::</span> (<span class="op">?</span><span class="ot">prettyInst ::</span> <span class="dt">PrettyDict</span> a) <span class="ot">=&gt;</span> [a] <span class="ot">-&gt;</span> <span class="dt">String</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>f xs <span class="ot">=</span> intercalate <span class="st">&quot;, &quot;</span> (<span class="fu">map</span> pretty xs)</span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a><span class="ot">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> <span class="op">?</span>prettyInst <span class="ot">=</span> boringPretty</span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a>    <span class="fu">putStrLn</span> <span class="op">$</span> f [<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span><span class="ot"> ::</span> <span class="dt">Int</span>]</span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> <span class="op">?</span>prettyInst <span class="ot">=</span> nicePretty <span class="kw">in</span> <span class="fu">putStrLn</span> <span class="op">$</span> f [<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span><span class="ot"> ::</span> <span class="dt">Int</span>]</span></code></pre></div>
<p>Let’s also enable optimizations, just to make sure this is actually
coherent. :)</p>
<div class="sourceCode" id="cb4"><pre
class="sourceCode txt"><code class="sourceCode default"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>$ ghc -O2 Main.hs &amp;&amp; ./Main</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>[1 of 1] Compiling Main             ( Main.hs, Main.o )</span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>Linking Main ...</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>5</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>✨5✨</span></code></pre></div>
<p>Perfect!</p>
<p>There is just one issue. While <code>ImplicitParams</code> make it
almost trivial to work with <em>local</em> instances, we lose the
ability to define regular <em>global</em> instances.</p>
<p>Whenever we want to use a function with a <code>?prettyInst</code>
constraint, we always have to define the instance we want to use
somewhere locally in its lexical scope.</p>
<p>If we wanted an actual replacement for type classes with local
<em>and</em> global instances, we would need some kind of…</p>
<h2 id="global-implicitparams">Global <code>ImplicitParams</code>?</h2>
<p>Remember how <code>IP</code> is just a regular type class? Couldn’t
we just… you know… define a regular, global instance for
<code>IP</code>?</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">IP</span> <span class="st">&quot;x&quot;</span> <span class="dt">Int</span> <span class="kw">where</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>    ip <span class="ot">=</span> <span class="dv">5</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> <span class="op">?</span>x</span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="dv">5</span></span></code></pre></div>
<p>So… uh… I honestly did not expect this to work, considering GHC
forbids manual <code>Typeable</code> or <code>Generic</code>
instances.</p>
<p>Anyway, if we want to model our class with this, we can simply write
global instances as instances for <code>IP</code> and override local
instances with <code>let ?x = ...</code> just as we did before.</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">IP</span> <span class="st">&quot;prettyInst&quot;</span> (<span class="dt">PrettyDict</span> <span class="dt">Int</span>) <span class="kw">where</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>    pretty <span class="ot">=</span> boringPretty</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="ot">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>    <span class="fu">putStrLn</span> (pretty (<span class="dv">5</span><span class="ot"> ::</span> <span class="dt">Int</span>))</span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a>    <span class="fu">putStrLn</span> (<span class="kw">let</span> <span class="op">?</span>prettyInst <span class="ot">=</span> nicePretty <span class="kw">in</span> pretty (<span class="dv">5</span><span class="ot"> ::</span> <span class="dt">Int</span>))</span></code></pre></div>
<div class="sourceCode" id="cb7"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> ghc <span class="at">-O2</span> Main.hs <span class="kw">&amp;&amp;</span> <span class="ex">./Main</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="ex">[1</span> of 1] Compiling Main             <span class="er">(</span> <span class="ex">Main.hs,</span> Main.o <span class="kw">)</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="ex">Linking</span> Main ...</span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="ex">5</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a><span class="ex">✨5✨</span></span></code></pre></div>
<p>Awesome! Unlike our unsafeCoerce trick last time, optimizations don’t
break <code>ImplicitParams</code>, so this is entirely safe!</p>
<p>We just came up with a type class replacement that completely
subsumes local, as well as global instances in a few lines of code.</p>
<p>It’s that simple!</p>
<h2 id="its-not-that-simple">It’s not that simple</h2>
<p>If you look at the definition of <code>IP</code>, you will likely
notice the deadly flaw in our current approach</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">IP</span> x a <span class="op">|</span> x <span class="ot">-&gt;</span> a <span class="kw">where</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="ot">    ip ::</span> a</span></code></pre></div>
<p><strong>There is a functional dependency between the parameter name
and its type.</strong><a href="#fn2" class="footnote-ref" id="fnref2"
role="doc-noteref"><sup>2</sup></a> This means that every parameter name
can only ever be used with <em>the same type argument</em> and so our
type class replacement can only ever have a single instance per class.
The entire purpose of type classes is to overload operations for
different types, so this completely defeats the point of using type
classes in the first place. :/</p>
<p>If we try to write an instance for two separate types anyway, the
compiler is going to complain as expected, since we violated the
functional dependency.</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">IP</span> <span class="st">&quot;prettyInst&quot;</span> (<span class="dt">PrettyDict</span> <span class="dt">Int</span>) <span class="kw">where</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>    pretty <span class="ot">=</span> boringPretty</span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a><span class="co">-- Error: Functional dependency conflict</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">IP</span> <span class="st">&quot;prettyInst&quot;</span> (<span class="dt">PrettyDict</span> <span class="dt">String</span>) <span class="kw">where</span></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a>    pretty <span class="ot">=</span> <span class="dt">PrettyDict</span> <span class="fu">id</span></span></code></pre></div>
<h2
id="when-life-gives-you-lemons"><a href="https://www.youtube.com/watch?v=g8ufRnf2Exc" target="_blank">When
life gives you lemons</a></h2>
<p>Unfortunately, since we can only have a single global <code>IP</code>
instance, we cannot use Haskell’s regular type class dispatching
mechanism to select the instance that we want.</p>
<p>But…</p>
<p>we could try and build our own, <em>based on runtime type
information</em>. This solution will not work for all types, but it
might work for all that implement <code>Typeable</code>.</p>
<p>With <code>Typeable</code>, we can extract a <code>TypeRep</code><a
href="#fn3" class="footnote-ref" id="fnref3"
role="doc-noteref"><sup>3</sup></a> from a <code>Proxy</code> for a
given type and, thanks to <code>typeRepFingerprint</code>, we are able
to turn this <code>TypeRep</code> into a <code>Fingerprint</code> that
is unique for every type. This <code>Fingerprint</code> implements
<code>Ord</code>, so we can use it as a key in a <code>Map</code>.</p>
<p>With this, we can build some machinery that selects an instance from
a <code>Map</code> based on the runtime <code>TypeRep</code> of a type.
The values of the <code>Map</code> then represent the instances for the
given types.</p>
<p>Conveniently, we already have a way of reifying instances, so we can
just store the concrete dictionaries (<code>PrettyDict</code>s in this
case).</p>
<p>We have to store dictionaries of different types
(e.g. <code>PrettyDict Int</code>, <code>PrettyDict Bool</code>, …), so
we could try some tricks with existentials, but since we are relying on
runtime type information anyway, it is easier to store them as <a
href="https://hackage.haskell.org/package/base-4.16.1.0/docs/GHC-Exts.html#t:Any"><code>Any</code></a>
and use <code>unsafeCoerce</code>.</p>
<div class="sourceCode" id="cb10"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">InstMap</span> <span class="ot">=</span> <span class="dt">MkInstMap</span> {<span class="ot">unInstMap ::</span> <span class="dt">Map</span> <span class="dt">Fingerprint</span> <span class="dt">Any</span>}</span></code></pre></div>
<p>To actually use this custom dispatching mechanism, we need to
reimplement our <code>pretty</code> ‘method’, which now takes an
<code>InstMap</code> as an implicit parameter and extracts the
dictionary for the type used, based on its <code>TypeRep</code>.</p>
<div class="sourceCode" id="cb11"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="ot">pretty ::</span> <span class="kw">forall</span> a<span class="op">.</span> (<span class="dt">Typeable</span> a, <span class="op">?</span><span class="ot">prettyInst ::</span> <span class="dt">InstMap</span>) <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">String</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>pretty <span class="ot">=</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> key <span class="ot">=</span> typeRepFingerprint (typeRep (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> a)) <span class="kw">in</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">case</span> M.lookup key (unInstMap <span class="op">?</span>prettyInst) <span class="kw">of</span></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Nothing</span> <span class="ot">-&gt;</span> <span class="fu">error</span> <span class="st">&quot;pretty: No instance found at runtime&quot;</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Just</span> dict <span class="ot">-&gt;</span> _pretty <span class="op">$</span> unsafeCoerce dict</span></code></pre></div>
<p>To add a local instance to the instance map, all we have to do is to
update the implicit <code>?prettyInst</code> parameter.</p>
<div class="sourceCode" id="cb12"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="ot">withPretty ::</span> <span class="kw">forall</span> a b<span class="op">.</span> <span class="dt">Typeable</span> a <span class="ot">=&gt;</span> <span class="dt">PrettyDict</span> a <span class="ot">-&gt;</span> ((<span class="op">?</span><span class="ot">prettyInst ::</span> <span class="dt">InstMap</span>) <span class="ot">=&gt;</span> b) <span class="ot">-&gt;</span> b</span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>withPretty dict x <span class="ot">=</span></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> key <span class="ot">=</span> typeRepFingerprint (typeRep (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> a)) <span class="kw">in</span></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> <span class="dt">MkInstMap</span> prevInst <span class="ot">=</span> <span class="op">?</span>prettyInst <span class="kw">in</span></span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> <span class="op">?</span>prettyInst <span class="ot">=</span> <span class="dt">MkInstMap</span> (M.insert key (unsafeCoerce dict) prevInst) <span class="kw">in</span> </span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a>    x</span></code></pre></div>
<p>Okay, so we gave up type safety, but in return, we gained the ability
to override instances locally… which we could already do with just
<code>ImplicitParams</code> without any runtime type dispatch machinery.
Sounds like we are back to square one?</p>
<h2 id="recovering-type-safety">Recovering type safety</h2>
<p>We have a way of locally overriding instances, but we should really
make sure that instances are actually available.</p>
<p>How could we check this? Well, type classes are perfect for
invariants like this!</p>
<p>If using type classes to implement a type class replacement sounds
pointless, keep in mind that we don’t care about the type class methods.
In fact, we don’t even need any! This way, incoherence is not an issue,
since the concrete instance chosen is irrelevant.</p>
<div class="sourceCode" id="cb13"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">HasPretty</span> a</span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a><span class="ot">pretty ::</span> <span class="kw">forall</span> a<span class="op">.</span> (<span class="dt">Typeable</span> a, <span class="dt">HasPretty</span> a, <span class="op">?</span><span class="ot">prettyInst ::</span> <span class="dt">InstMap</span>) <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">String</span></span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>pretty <span class="ot">=</span> <span class="co">-- same implementation</span></span></code></pre></div>
<p>Note that we didn’t change anything on the term level. The
<code>HasPretty</code> constraint in the type purely exists to make sure
that we call <code>withPretty</code> at some point before calling
<code>pretty</code>.</p>
<p>To satisfy the <code>HasPretty</code> constraint in the continuation
passed to <code>withPretty</code>, we can just use the
<code>unsafeCoerce</code> trick from the previous post.</p>
<div class="sourceCode" id="cb14"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">LocalPrettyInst</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">HasPretty</span> <span class="dt">LocalPrettyInst</span></span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a><span class="ot">withPretty ::</span> <span class="kw">forall</span> a b<span class="op">.</span> <span class="dt">Typeable</span> a </span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a>           <span class="ot">=&gt;</span> <span class="dt">PrettyDict</span> a </span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a>           <span class="ot">-&gt;</span> ((<span class="dt">HasPretty</span> a, <span class="op">?</span><span class="ot">prettyInst ::</span> <span class="dt">InstMap</span>) <span class="ot">=&gt;</span> b) </span>
<span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a>           <span class="ot">-&gt;</span> b</span>
<span id="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a>withPretty dict x <span class="ot">=</span></span>
<span id="cb14-10"><a href="#cb14-10" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> key <span class="ot">=</span> typeRepFingerprint (typeRep (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> a)) <span class="kw">in</span></span>
<span id="cb14-11"><a href="#cb14-11" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> <span class="dt">MkInstMap</span> previousInst <span class="ot">=</span> <span class="op">?</span>prettyInst <span class="kw">in</span></span>
<span id="cb14-12"><a href="#cb14-12" aria-hidden="true" tabindex="-1"></a>    <span class="kw">case</span> unsafeCoerce (<span class="dt">Dict</span><span class="ot"> ::</span> <span class="dt">Dict</span> (<span class="dt">HasPretty</span> <span class="dt">LocalPrettyInst</span>))<span class="ot"> ::</span> <span class="dt">Dict</span> (<span class="dt">HasPretty</span> a) <span class="kw">of</span></span>
<span id="cb14-13"><a href="#cb14-13" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Dict</span> <span class="ot">-&gt;</span> </span>
<span id="cb14-14"><a href="#cb14-14" aria-hidden="true" tabindex="-1"></a>            <span class="kw">let</span> <span class="op">?</span>prettyInst <span class="ot">=</span> <span class="dt">MkInstMap</span> (M.insert key (unsafeCoerce dict) previousInst) <span class="kw">in</span> </span>
<span id="cb14-15"><a href="#cb14-15" aria-hidden="true" tabindex="-1"></a>            x</span></code></pre></div>
<p>So, a function that would have a <code>Pretty a</code> constraint
with regular classes or a <code>(?prettyInst :: PrettyDict a)</code>
constraint with <code>ImplicitParams</code>, now needs a
<code>(Typeable a, HasPretty a, ?prettyInst :: InstMap)</code>
constraint.</p>
<h2 id="going-global">Going global</h2>
<p>We recovered type safety, but our approach still doesn’t offer any
advantage over pure <code>ImplicitParams</code>, since we still don’t
have a way to write global instances.</p>
<p>Your first thought might be to write a global instance for
<code>IP "prettyInst" InstMap</code> and somehow populate that when
defining new global instances.</p>
<p>Unfortunately, this doesn’t work. We could try to use a global
<code>IORef</code> and extend it at runtime, but how would we run the
code to extend that IORef? Haskell doesn’t provide a way to run IO code
at module load time, so we couldn’t make sure that the map contains all
relevant instances without having to populate it in
<code>main</code>.</p>
<p>Instead, let’s start with an empty map.</p>
<div class="sourceCode" id="cb15"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">IP</span> <span class="st">&quot;prettyInst&quot;</span> <span class="dt">InstMap</span> <span class="kw">where</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>    ip <span class="ot">=</span> <span class="dt">MkInstMap</span> <span class="fu">mempty</span></span></code></pre></div>
<p>The typechecker prevents us from using this instance without further
local instances since we don’t have any <code>HasPretty</code> instances
yet.</p>
<p>Fortunately, telling the type checker about global instances is quite
easy: We just have to implement <code>HasPretty</code> for the type we
are writing an instance for.</p>
<p>Since we don’t have an actual instance yet, this would still crash at
runtime; our instance map doesn’t have any implementations by
default.</p>
<p>Consider this: In case the instance map does not contain an entry for
the type <code>pretty</code> is called at, but it <em>is called</em>
(meaning the <code>HasPretty</code> constraint was satisfied), we know
that there <em>has to be a global instance</em> and that <em>no local
instances are in scope</em>. Thus, crucially, <strong>there is only a
single instance for <code>HasPretty</code>, which is a regular global
instance</strong>. If there is only a single instance, we don’t need to
deal with incoherence and we are able to use actual methods from
<code>HasPretty</code> with confidence that they are coming from the
global instance with or without optimizations.</p>
<p>What would possible methods on <code>HasPretty</code> look like? We
still need to specify the implementation of our global instance
somewhere, so this would be a perfect place to put that.</p>
<p>Now, whenever <code>pretty</code> is called and detects a runtime
instance in its instance map, we know that the instance has been
overridden and <code>HasPretty</code> is potentially contaminated, so we
use the instance from the instance map directly and ignore any methods
from <code>HasPretty</code>.</p>
<p>If there is no runtime instance, we know that the instance it is
called at has to be a global, coherent instance and we can safely use
the implementation from <code>HasPretty</code> to maintain
coherence.</p>
<div class="sourceCode" id="cb16"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">HasPretty</span> a <span class="kw">where</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a><span class="ot">    globalInst ::</span> <span class="dt">PrettyDict</span> a</span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">LocalPrettyInst</span></span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">HasPretty</span> <span class="dt">LocalPrettyInst</span> <span class="kw">where</span></span>
<span id="cb16-7"><a href="#cb16-7" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- This will never be called unless someone seriously messes with things, </span></span>
<span id="cb16-8"><a href="#cb16-8" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- since `withPretty` always adds an instance to the ?prettyInst InstMap </span></span>
<span id="cb16-9"><a href="#cb16-9" aria-hidden="true" tabindex="-1"></a>    globalInst <span class="ot">=</span> <span class="fu">error</span> <span class="st">&quot;pretty: No instance found at runtime&quot;</span></span>
<span id="cb16-10"><a href="#cb16-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-11"><a href="#cb16-11" aria-hidden="true" tabindex="-1"></a><span class="ot">pretty ::</span> <span class="kw">forall</span> a<span class="op">.</span> (<span class="dt">Typeable</span> a, <span class="dt">HasPretty</span> a, <span class="op">?</span><span class="ot">prettyInst ::</span> <span class="dt">InstMap</span>) <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">String</span></span>
<span id="cb16-12"><a href="#cb16-12" aria-hidden="true" tabindex="-1"></a>pretty <span class="ot">=</span></span>
<span id="cb16-13"><a href="#cb16-13" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> key <span class="ot">=</span> typeRepFingerprint (typeRep (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> a)) <span class="kw">in</span></span>
<span id="cb16-14"><a href="#cb16-14" aria-hidden="true" tabindex="-1"></a>    <span class="kw">case</span> M.lookup key (unInstMap <span class="op">?</span>prettyInst) <span class="kw">of</span></span>
<span id="cb16-15"><a href="#cb16-15" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Nothing</span> <span class="ot">-&gt;</span> </span>
<span id="cb16-16"><a href="#cb16-16" aria-hidden="true" tabindex="-1"></a>            _pretty globalInst</span>
<span id="cb16-17"><a href="#cb16-17" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Just</span> dict <span class="ot">-&gt;</span></span>
<span id="cb16-18"><a href="#cb16-18" aria-hidden="true" tabindex="-1"></a>            _pretty <span class="op">$</span> unsafeCoerce dict</span></code></pre></div>
<p>This works!</p>
<p>If we try the example from before…</p>
<div class="sourceCode" id="cb17"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">HasPretty</span> <span class="dt">Int</span> <span class="kw">where</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a>    globalInst <span class="ot">=</span> boringPretty</span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a><span class="ot">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a>    <span class="fu">putStrLn</span> (pretty (<span class="dv">5</span><span class="ot"> ::</span> <span class="dt">Int</span>))</span>
<span id="cb17-7"><a href="#cb17-7" aria-hidden="true" tabindex="-1"></a>    <span class="fu">putStrLn</span> (withPretty nicePretty (pretty (<span class="dv">5</span><span class="ot"> ::</span> <span class="dt">Int</span>)))</span></code></pre></div>
<div class="sourceCode" id="cb18"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> ghc <span class="at">-O2</span> Main.hs <span class="kw">&amp;&amp;</span> <span class="ex">./Main</span></span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a><span class="ex">[1</span> of 1] Compiling Main             <span class="er">(</span> <span class="ex">Main.hs,</span> Main.o <span class="kw">)</span></span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a><span class="ex">Linking</span> Main ...</span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a><span class="ex">5</span></span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a><span class="ex">✨5✨</span></span></code></pre></div>
<p>… everything works as expected, even with optimizations!</p>
<p>There is actually not much boilerplate involved in this technique,
compared to regular type classes and instances.</p>
<p>The main limitation is that types used in instances all have to
implement <code>Typeable</code>, so we can only use this for relatively
simple instances.</p>
<p>Defining a class is quite a bit more verbose since we have to define
a dictionary type, a <code>HasX</code> class to carry the global
instance, a global instance for the associated implicit parameter as
well as functions to apply and override the active instance.</p>
<p>To use our running example, the class definition</p>
<div class="sourceCode" id="cb19"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Pretty</span> a <span class="kw">where</span></span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a><span class="ot">    pretty ::</span> a <span class="ot">-&gt;</span> <span class="dt">String</span></span></code></pre></div>
<p>becomes</p>
<div class="sourceCode" id="cb20"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">PrettyDict</span> a <span class="ot">=</span> <span class="dt">PrettyDict</span> {</span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a><span class="ot">    _pretty ::</span> a <span class="ot">-&gt;</span> <span class="dt">String</span></span>
<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a>}</span>
<span id="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-5"><a href="#cb20-5" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">HasPretty</span> a <span class="kw">where</span></span>
<span id="cb20-6"><a href="#cb20-6" aria-hidden="true" tabindex="-1"></a><span class="ot">    globalInst ::</span> <span class="dt">PrettyDict</span> a <span class="ot">=&gt;</span> a</span>
<span id="cb20-7"><a href="#cb20-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-8"><a href="#cb20-8" aria-hidden="true" tabindex="-1"></a><span class="ot">pretty ::</span> <span class="kw">forall</span> a<span class="op">.</span> (<span class="dt">Typeable</span> a, <span class="dt">HasPretty</span> a, <span class="op">?</span><span class="ot">prettyInst ::</span> <span class="dt">InstMap</span>) <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">String</span></span>
<span id="cb20-9"><a href="#cb20-9" aria-hidden="true" tabindex="-1"></a>pretty <span class="ot">=</span></span>
<span id="cb20-10"><a href="#cb20-10" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> key <span class="ot">=</span> typeRepFingerprint (typeRep (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> a)) <span class="kw">in</span></span>
<span id="cb20-11"><a href="#cb20-11" aria-hidden="true" tabindex="-1"></a>    <span class="kw">case</span> M.lookup key (unInstMap <span class="op">?</span>prettyInst) <span class="kw">of</span></span>
<span id="cb20-12"><a href="#cb20-12" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Nothing</span> <span class="ot">-&gt;</span> </span>
<span id="cb20-13"><a href="#cb20-13" aria-hidden="true" tabindex="-1"></a>            _pretty globalInst</span>
<span id="cb20-14"><a href="#cb20-14" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Just</span> dict <span class="ot">-&gt;</span></span>
<span id="cb20-15"><a href="#cb20-15" aria-hidden="true" tabindex="-1"></a>            _pretty <span class="op">$</span> unsafeCoerce dict</span>
<span id="cb20-16"><a href="#cb20-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-17"><a href="#cb20-17" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">LocalPrettyInst</span></span>
<span id="cb20-18"><a href="#cb20-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-19"><a href="#cb20-19" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">HasPretty</span> <span class="dt">LocalPrettyInst</span> <span class="kw">where</span></span>
<span id="cb20-20"><a href="#cb20-20" aria-hidden="true" tabindex="-1"></a>    globalInst <span class="ot">=</span> <span class="fu">error</span> <span class="st">&quot;pretty: No instance found at runtime&quot;</span></span>
<span id="cb20-21"><a href="#cb20-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-22"><a href="#cb20-22" aria-hidden="true" tabindex="-1"></a><span class="ot">withPretty ::</span> <span class="kw">forall</span> a b<span class="op">.</span> <span class="dt">Typeable</span> a <span class="ot">=&gt;</span> <span class="dt">PrettyDict</span> a <span class="ot">-&gt;</span> ((<span class="dt">HasPretty</span> a, <span class="op">?</span><span class="ot">prettyInst ::</span> <span class="dt">InstMap</span>) <span class="ot">=&gt;</span> b) <span class="ot">-&gt;</span> b</span>
<span id="cb20-23"><a href="#cb20-23" aria-hidden="true" tabindex="-1"></a>withPretty dict x <span class="ot">=</span></span>
<span id="cb20-24"><a href="#cb20-24" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> key <span class="ot">=</span> typeRepFingerprint (typeRep (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> a)) <span class="kw">in</span></span>
<span id="cb20-25"><a href="#cb20-25" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> <span class="dt">MkInstMap</span> prevInst <span class="ot">=</span> <span class="op">?</span>prettyInst <span class="kw">in</span></span>
<span id="cb20-26"><a href="#cb20-26" aria-hidden="true" tabindex="-1"></a>    <span class="kw">case</span> unsafeCoerce (<span class="dt">Dict</span><span class="ot"> ::</span> <span class="dt">Dict</span> (<span class="dt">HasPretty</span> <span class="dt">LocalPrettyInst</span>))<span class="ot"> ::</span> <span class="dt">Dict</span> (<span class="dt">HasPretty</span> a) <span class="kw">of</span></span>
<span id="cb20-27"><a href="#cb20-27" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Dict</span> <span class="ot">-&gt;</span> </span>
<span id="cb20-28"><a href="#cb20-28" aria-hidden="true" tabindex="-1"></a>            <span class="kw">let</span> <span class="op">?</span>prettyInst <span class="ot">=</span> <span class="dt">MkInstMap</span> (M.insert key (unsafeCoerce dict) prevInst) <span class="kw">in</span> </span>
<span id="cb20-29"><a href="#cb20-29" aria-hidden="true" tabindex="-1"></a>            x</span></code></pre></div>
<p>Crucially, though, the boilerplate involved in <em>using</em> these
overridable instances is pretty minimal and most of the boilerplate when
defining these ‘classes’ could be automated with TemplateHaskell.</p>
<p>New global instances only have to implement <code>HasPretty</code>,
which is a tiny bit less ergonomic than <code>Pretty</code>, since we
have to implement the dictionary, not the methods and there are no
default implementations.</p>
<div class="sourceCode" id="cb21"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">HasPretty</span> <span class="dt">Int</span> <span class="kw">where</span></span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a>    globalInst <span class="ot">=</span> <span class="dt">PrettyDict</span> {</span>
<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a>        _pretty <span class="ot">=</span> <span class="fu">show</span></span>
<span id="cb21-4"><a href="#cb21-4" aria-hidden="true" tabindex="-1"></a>    }</span></code></pre></div>
<p>The only difference between a function that uses our overridable
<code>pretty</code> and one that uses the regular <code>Pretty</code>
type class is in the constraint, which changes from
<code>Pretty a</code> to
<code>(Typeable a, HasPretty a, ?prettyInst :: InstMap)</code>.</p>
<p>We could try to factor this out to a type synonym.</p>
<div class="sourceCode" id="cb22"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">Pretty</span> a <span class="ot">=</span> (<span class="dt">Typeable</span> a, <span class="dt">HasPretty</span> a, <span class="op">?</span><span class="ot">prettyInst ::</span> <span class="dt">InstMap</span>)</span></code></pre></div>
<p>Thereby completely eliminating any additonal boilerplate when using
<code>pretty</code>!</p>
<p>Let’s rewrite <code>pretty</code> with a <code>Pretty a</code>
constraint instead of the more complicated
<code>(Typeable a, HasPretty a, ?prettyInst :: InstMap)</code>. After
all, <code>Pretty</code> is just a type synonym, so this should mean
exactly the same thing, right? …<em>right?</em></p>
<h2 id="it-all-comes-tumbling-down">It all comes tumbling down</h2>
<div class="sourceCode" id="cb23"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true" tabindex="-1"></a><span class="ot">pretty ::</span> <span class="dt">Pretty</span> a <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">String</span></span>
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a>pretty <span class="ot">=</span> <span class="op">...</span></span>
<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb23-4"><a href="#cb23-4" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> <span class="op">:</span>t pretty</span>
<span id="cb23-5"><a href="#cb23-5" aria-hidden="true" tabindex="-1"></a><span class="ot">pretty ::</span> (<span class="dt">HasPretty</span> a, <span class="dt">Typeable</span> a) <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">String</span></span></code></pre></div>
<p>Uh oh. The <code>?prettyInst :: InstMap</code> constraint just…
disappeared?</p>
<p>What happened here, is that when resolving<a href="#fn4"
class="footnote-ref" id="fnref4" role="doc-noteref"><sup>4</sup></a> the
type synonym, GHC tried to simplify the constraint and removed the
monomorphic <code>?prettyInst :: InstMap</code> constraint, since an
instance was found in the global context.</p>
<p>This obviously sounds like a bug, but I am not certain that it
actually is. In fact, the real bug is probably that we were able to
define a global instance for <code>IP</code> in the first place.</p>
<p>Okay, we are unable to factor out the
<code>(Typeable a, HasPretty a, ?prettyInst :: InstMap)</code>
constraint with a type synonym. Since we have a custom
<code>HasPretty</code> class anyway, we could try to include these as
superclasses in the style of <a
href="https://blog.csongor.co.uk/opaque-constraint-synonyms">Opaque
constraint synonyms</a> instead.</p>
<div class="sourceCode" id="cb24"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> (<span class="dt">Typeable</span> a, <span class="dt">IP</span> <span class="st">&quot;prettyInst&quot;</span> <span class="dt">InstMap</span>) <span class="ot">=&gt;</span> <span class="dt">HasPretty</span> a</span></code></pre></div>
<p>…except this doesn’t work. GHC does not allow implicit parameters in
superclasses, even if we explicitly write them as <code>IP</code> class
constraints.</p>
<p>This is a reasonable restriction because the time at which
dictionaries with super classes are constructed can be quite
unpredictable, so an implicit parameter superclass constraint will
probably not contain the intended value, but it <em>is</em> annoying
since we have to keep the <code>?prettyInst :: InstMap</code> constraint
around.</p>
<p>We could at least try to factor out <code>Typeable</code> though.</p>
<div class="sourceCode" id="cb25"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Typeable</span> a <span class="ot">=&gt;</span> <span class="dt">HasPretty</span> a <span class="kw">where</span></span>
<span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a>    <span class="op">...</span></span></code></pre></div>
<p>This compiles and even runs correctly!</p>
<p>…as long as we compile <em>with</em> optimizations.<a href="#fn5"
class="footnote-ref" id="fnref5" role="doc-noteref"><sup>5</sup></a></p>
<p>So, factoring out the
<code>(Typeable a, HasPretty a, ?prettyInst :: InstMap)</code>
constraint is not an option. Is there anything else we cannot do?</p>
<div class="sourceCode" id="cb26"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a><span class="ot">f ::</span> (<span class="dt">Typeable</span> a, <span class="dt">HasPretty</span> a, <span class="op">?</span><span class="ot">prettyInst ::</span> <span class="dt">InstMap</span>) <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">String</span></span>
<span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a>f <span class="ot">=</span> pretty</span>
<span id="cb26-3"><a href="#cb26-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-4"><a href="#cb26-4" aria-hidden="true" tabindex="-1"></a>g x <span class="ot">=</span> f x</span>
<span id="cb26-5"><a href="#cb26-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-6"><a href="#cb26-6" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> <span class="op">:</span>t g</span>
<span id="cb26-7"><a href="#cb26-7" aria-hidden="true" tabindex="-1"></a><span class="ot">g ::</span> (<span class="dt">Typeable</span> a, <span class="dt">HasPretty</span> a) <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">String</span></span>
<span id="cb26-8"><a href="#cb26-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-9"><a href="#cb26-9" aria-hidden="true" tabindex="-1"></a><span class="ot">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb26-10"><a href="#cb26-10" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb26-11"><a href="#cb26-11" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- I am using instances for `Bool` here since we haven&#39;t defined a </span></span>
<span id="cb26-12"><a href="#cb26-12" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- global instance for `HasPretty Bool` yet.</span></span>
<span id="cb26-13"><a href="#cb26-13" aria-hidden="true" tabindex="-1"></a>    <span class="fu">putStrLn</span> (withPretty (<span class="dt">PrettyDict</span> <span class="op">@</span><span class="dt">Bool</span> <span class="fu">show</span>) (f <span class="dt">True</span>))</span>
<span id="cb26-14"><a href="#cb26-14" aria-hidden="true" tabindex="-1"></a>    <span class="fu">putStrLn</span> (withPretty (<span class="dt">PrettyDict</span> <span class="op">@</span><span class="dt">Bool</span> <span class="fu">show</span>) (g <span class="dt">True</span>))</span></code></pre></div>
<div class="sourceCode" id="cb27"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> ghc Main.hs <span class="kw">&amp;&amp;</span> <span class="ex">./Main</span></span>
<span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a><span class="ex">[1</span> of 1] Compiling Main             <span class="er">(</span> <span class="ex">Main.hs,</span> Main.o <span class="kw">)</span></span>
<span id="cb27-3"><a href="#cb27-3" aria-hidden="true" tabindex="-1"></a><span class="ex">Linking</span> Main ...</span>
<span id="cb27-4"><a href="#cb27-4" aria-hidden="true" tabindex="-1"></a><span class="ex">True</span></span>
<span id="cb27-5"><a href="#cb27-5" aria-hidden="true" tabindex="-1"></a><span class="ex">Main:</span> pretty: No instance found at runtime</span>
<span id="cb27-6"><a href="#cb27-6" aria-hidden="true" tabindex="-1"></a><span class="ex">CallStack</span> <span class="er">(</span><span class="ex">from</span> HasCallStack<span class="kw">)</span><span class="bu">:</span></span>
<span id="cb27-7"><a href="#cb27-7" aria-hidden="true" tabindex="-1"></a>  <span class="ex">error,</span> called at Main.hs:55:18 in main:Main</span></code></pre></div>
<p>Oh, come on!</p>
<p>As it turns out, when inferring the type for <code>g</code>, GHC
omits the implicit parameter constraint and instead hard wires the empty
instance map from the global instance.</p>
<p><code>withPretty</code> still inserts a <code>HasPretty</code>
instance, so the compiler cannot stop us from calling <code>g</code> and
crashing at runtime.</p>
<h2 id="conclusion">Conclusion</h2>
<ul>
<li>We are able to replace type classes with overridable
<code>ImplicitParams</code> and runtime type information based
dispatch.</li>
<li>We can recover type safety, by using fake constraints for an empty
class so that incoherence is not an issue.</li>
<li>To get proper global instances, we can extend the previously empty
class with a base implementation. We only ever use this implementation
if we are absolutely sure no local instance exists, so this is also
safe.</li>
<li>Unfortunately, the global <code>ImplicitParams</code> instance makes
<code>?prettyInst</code> constraints extremely brittle and mistakes like
forgetting a type signature can remove the parameter and lead to runtime
crashes.</li>
</ul>
<p>To safely use this, we <em>always</em> have to make sure to</p>
<ul>
<li>type out the entire
<code>(Typeable a, HasPretty a, ?prettyInst :: InstMap)</code>
constraint</li>
<li>write a type signature whenever it might include
<code>?prettyInst</code></li>
</ul>
<p>Now, should you ever use any of this in anything that you might
possibly not want to break?</p>
<p>Of course not. Global implicit parameters seem to be mostly uncharted
territory and I’m pretty sure their mere existence constitutes a
bug.</p>
<p>Still, screwing around with broken features and pushing the limits of
Haskell is fun. I had a blast writing this and I hope it was enjoyable
to read as well! Maybe you even learned something today?</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>If you have not already, you should probably read <a
href="/posts/unsafeCoerceDict.html">that post</a> first to understand
the context of this and what ‘incoherence’ even means.<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>As far as I can tell, the reason for this is to aid type
inference. Without this dependency, GHC would be unable to figure out
the type of <code>?x</code> even when a <code>(?x :: Int)</code>
constraint is in scope. This is a little frustrating though, since the
functional dependency is a bit of a lie. The type of <code>x</code> is
not <em>really</em> only determined by its name. It is determined by its
name and the instance in the surrounding context, but GHC cannot express
that so it cheats and invents a functional dependency.<a href="#fnref2"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>The terminology is a bit confusing here.
<code>TypeRep</code> in <code>Data.Typeable</code> is just a
representation of regular compile-time types, that is carried in
<code>Typeable</code> constraints at runtime, not about the runtime
representation of values as in <code>type role representational</code>.
Concretely this means, that newtypes like <code>Int</code> and
<code>Sum Int</code> will have the same runtime representation, but
their <code>TypeRep</code>s will be different.<a href="#fnref3"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn4"><p>The issue might have already happened when
<em>defining</em> the type synonym. I’m not sure but the end result is
the same either way.<a href="#fnref4" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn5"><p>Yeah…<a href="#fnref5" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
    <pubDate>Mon, 29 Aug 2022 00:00:00 +0200</pubDate>
</item><item>
    <title>Faking Local Instances with <code>unsafeCoerce Dict</code></title>
    <link>https://welltypedwit.ch/posts/unsafeCoerceDict.html</link>
    <guid isPermaLink="true">https://welltypedwit.ch/posts/unsafeCoerceDict.html</guid>
    <description><![CDATA[<p> When you first learned about Haskell’s <code>Monoid</code>
typeclass, you were probably quite surprised to find out that there is
no instance for <code>Monoid Int</code> in <code>base</code>.</p>
<p>After all, <code>(+)</code> is an associative binary operation, and
<code>0</code> acts as a unit element.</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Semigroup</span> <span class="dt">Int</span> <span class="kw">where</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>    (<span class="op">&lt;&gt;</span>) <span class="ot">=</span> (<span class="op">+</span>)</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Monoid</span> <span class="dt">Int</span> <span class="kw">where</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>    <span class="fu">mempty</span> <span class="ot">=</span> <span class="dv">0</span></span></code></pre></div>
<p>The reason, as you will have learned is that this is not the
<em>only</em> possible instance for <code>Monoid Int</code>.</p>
<p>The following instance is, in fact, just as valid.</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Semigroup</span> <span class="dt">Int</span> <span class="kw">where</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>    (<span class="op">&lt;&gt;</span>) <span class="ot">=</span> (<span class="op">*</span>)</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Monoid</span> <span class="dt">Int</span> <span class="kw">where</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>    <span class="fu">mempty</span> <span class="ot">=</span> <span class="dv">1</span></span></code></pre></div>
<p>You might also be aware, that the way to work around this is to
declare newtype wrappers and to wrap and unwrap all <code>Int</code>s
every time the Monoid instance is needed.</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">Sum</span> a <span class="ot">=</span> <span class="dt">Sum</span> {<span class="ot">getSum ::</span> a}</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">Product</span> a <span class="ot">=</span> <span class="dt">Product</span> {<span class="ot">getProduct ::</span> a}</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> (<span class="dt">Num</span> a) <span class="ot">=&gt;</span> <span class="dt">Semigroup</span> (<span class="dt">Sum</span> a) <span class="kw">where</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>    (<span class="dt">Sum</span> x) <span class="op">&lt;&gt;</span> (<span class="dt">Sum</span> y) <span class="ot">=</span> <span class="dt">Sum</span> (x <span class="op">+</span> y)</span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> (<span class="dt">Num</span> a) <span class="ot">=&gt;</span> <span class="dt">Monoid</span> (<span class="dt">Sum</span> a) <span class="kw">where</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>    <span class="fu">mempty</span> <span class="ot">=</span> <span class="dt">Sum</span> <span class="dv">0</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> (<span class="dt">Num</span> a) <span class="ot">=&gt;</span> <span class="dt">Semigroup</span> (<span class="dt">Product</span> a) <span class="kw">where</span></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a>    (<span class="dt">Product</span> x) <span class="op">&lt;&gt;</span> (<span class="dt">Product</span> y) <span class="ot">=</span> <span class="dt">Product</span> (x <span class="op">*</span> y)</span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> (<span class="dt">Num</span> a) <span class="ot">=&gt;</span> <span class="dt">Monoid</span> (<span class="dt">Product</span> a) <span class="kw">where</span></span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a>    <span class="fu">mempty</span> <span class="ot">=</span> <span class="dt">Product</span> <span class="dv">1</span></span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> getSum <span class="op">$</span> <span class="fu">foldMap</span> <span class="dt">Sum</span> [<span class="dv">1</span><span class="op">..</span><span class="dv">10</span>] <span class="op">&lt;&gt;</span> <span class="dt">Sum</span> <span class="dv">5</span></span>
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true" tabindex="-1"></a><span class="dv">60</span></span></code></pre></div>
<p>There is a bit of boilerplate involved in defining the newtypes and
corresponding instances, but what is hard to swallow is that quite a bit
of boilerplate has to be included at <em>every single use site</em>.<a
href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a></p>
<p>If Haskell had local instances, this would not be an issue since we
would not be forced to commit to a single instance and could just tell
the compiler the instance we want without having to constantly wrap and
unwrap everything.<a href="#fn2" class="footnote-ref" id="fnref2"
role="doc-noteref"><sup>2</sup></a></p>
<h2 id="introducing-dict">Introducing <code>Dict</code></h2>
<p>GHC uses a technique called <em>dictionary passing</em> to compile
typeclass dictionaries. This means that in Core (GHC’s intermediate
language), <code>=&gt;</code> is turned into <code>-&gt;</code>. In
other words, <em>constraints become arguments</em>, called
<em>dictionaries</em>.</p>
<p>Why is that useful to know? Well, while there is no way to directly
access or construct these dictionaries, we <em>can</em> reify them with
<code>Dict</code>.</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Dict</span> (<span class="ot">c ::</span> <span class="dt">Constraint</span>) <span class="kw">where</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Dict</span><span class="ot"> ::</span> c <span class="ot">=&gt;</span> <span class="dt">Dict</span> c</span></code></pre></div>
<p>Because the constraint <code>c</code> appears in the type signature
of the <code>Dict</code> constructor, the constructor stores the
corresponding dictionary, and whenever it is scrutinized in a pattern
match, the constraint is made available.</p>
<p>Unfortunately, even with <code>Dict</code>, there is no way to
construct a dictionary without defining an instance first.</p>
<p>The only way to construct a ‘local’ instance then is to define an
instance for a newtype wrapper, but if we create a Dict from that
instance, we cannot use the newtype <code>Dict</code> for our original
type, because <code>Dict (Monoid Int)</code> and
<code>Dict (Monoid (Sum Int))</code> are entirely separate types to the
typechecker.</p>
<p>We hit quite the wall there. We know we could use the Dict for our
newtype, and we know it would be safe<a href="#fn3" class="footnote-ref"
id="fnref3" role="doc-noteref"><sup>3</sup></a> because newtypes are
erased at runtime, but the typechecker doesn’t allow us to use a newtype
Dict to get an instance for the original type.</p>
<p>If there was just some way to bypass the typechecker…</p>
<h2 id="i-solemnly-swear-i-am-up-to-no-good">I solemnly swear I am up to
no good</h2>
<p>Luckily for us: there is!</p>
<p><code>unsafeCoerce :: forall a b. a -&gt; b</code> lets us bypass the
typechecker by treating a value of <em>any</em> (lifted) type as a value
of <em>any other</em> (lifted) type.</p>
<p>This is probably one of the most dangerous, if not <em>the</em> most
dangerous function in GHC’s arsenal. If you’re not careful, you can
easily end up with segmentation faults.</p>
<p>We know what we’re doing though, so let’s try it out!</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="ot">monoidSumDict ::</span> <span class="dt">Dict</span> (<span class="dt">Monoid</span> (<span class="dt">Sum</span> <span class="dt">Int</span>))</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>monoidSumDict <span class="ot">=</span> <span class="dt">Dict</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="ot">monoidIntDict ::</span> <span class="dt">Dict</span> (<span class="dt">Monoid</span> <span class="dt">Int</span>)</span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>monoidIntDict <span class="ot">=</span> unsafeCoerce monoidSumDict</span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a><span class="co">-- If we didn&#39;t include the type signature, GHC would be confused about the type of number we&#39;re using</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> <span class="kw">case</span> monoidIntDict <span class="kw">of</span> <span class="dt">Dict</span> <span class="ot">-&gt;</span> fold [<span class="dv">1</span><span class="op">..</span><span class="dv">10</span>] <span class="op">&lt;&gt;</span> (<span class="dv">5</span><span class="ot"> ::</span> <span class="dt">Int</span>)</span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a><span class="dv">60</span></span></code></pre></div>
<p>Perfect! We just created an instance of <code>Monoid Int</code>, that
only exists if we pattern match on <code>monoidIntDict</code>. This
sounds a lot like local instances to me.</p>
<h2 id="lets-simplify-this">Let’s simplify this</h2>
<p>What we have so far is already pretty cool, but having to write out a
pattern match every time is a bit inconvenient.</p>
<p>Fortunately, we can easily factor out the pattern match by turning it
into a function.</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="ot">withDict ::</span> <span class="dt">Dict</span> c <span class="ot">-&gt;</span> (c <span class="ot">=&gt;</span> a) <span class="ot">-&gt;</span> a</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>withDict d x <span class="ot">=</span> <span class="kw">case</span> d <span class="kw">of</span> <span class="dt">Dict</span> <span class="ot">-&gt;</span> x</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> withDict monoidIntDict <span class="op">$</span> fold [<span class="dv">1</span><span class="op">..</span><span class="dv">10</span>] <span class="op">&lt;&gt;</span> (<span class="dv">5</span><span class="ot"> ::</span> <span class="dt">Int</span>)</span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a><span class="dv">60</span></span></code></pre></div>
<p>That <code>(c =&gt; a)</code> argument might look a bit strange, but
this is exactly what we’re trying to do: Take a value or function with a
constraint and remove that constraint by inserting the instance stored
in our <code>Dict</code>.</p>
<p>We can do even better. The only way to construct one of our ‘local’
Dicts is to create a <code>Dict</code> for a newtype and cast that to a
<code>Dict</code> for the original type using <code>unsafeCoerce</code>,
but users of our library really shouldn’t have to write their own
<code>Dict</code> definition, let alone use
<code>unsafeCoerce</code>.</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="ot">withLocal ::</span> <span class="kw">forall</span> c1 c2 d<span class="op">.</span> c1 <span class="ot">=&gt;</span> (c2 <span class="ot">=&gt;</span> d) <span class="ot">-&gt;</span> d</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>withLocal x <span class="ot">=</span> <span class="kw">case</span> c2Dict <span class="kw">of</span> <span class="dt">Dict</span> <span class="ot">-&gt;</span> x</span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">where</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="ot">        c1Dict ::</span> <span class="dt">Dict</span> c1</span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>        c1Dict <span class="ot">=</span> <span class="dt">Dict</span></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a><span class="ot">        c2Dict ::</span> <span class="dt">Dict</span> c2</span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a>        c2Dict <span class="ot">=</span> unsafeCoerce c1Dict </span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> withLocal <span class="op">@</span>(<span class="dt">Monoid</span> (<span class="dt">Sum</span> <span class="dt">Int</span>)) <span class="op">@</span>(<span class="dt">Monoid</span> <span class="dt">Int</span>) <span class="op">$</span> fold [<span class="dv">1</span><span class="op">..</span><span class="dv">10</span>] <span class="op">&lt;&gt;</span> (<span class="dv">5</span><span class="ot"> ::</span> <span class="dt">Int</span>)</span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a><span class="dv">60</span></span></code></pre></div>
<p>Now, all that users have to do is supply the right type applications
and <code>withLocal</code> is going to do everything else for them.
Nice!</p>
<h2 id="hey-google-whats-a-segfault">Hey Google, what’s a segfault?</h2>
<div class="sourceCode" id="cb8"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> withLocal <span class="op">@</span>(<span class="dt">Eq</span> <span class="dt">Bool</span>) <span class="op">@</span>(<span class="dt">Num</span> <span class="dt">Int</span>) <span class="op">$</span> (<span class="op">-</span><span class="dv">1</span><span class="ot"> ::</span> <span class="dt">Int</span>) <span class="op">+</span> <span class="dv">2</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>fish<span class="op">:</span> <span class="dt">Job</span> <span class="dv">1</span>, &#39;ghci unsafeCoerceDict<span class="op">.</span>hs&#39; terminated by signal <span class="dt">SIGSEGV</span> (<span class="dt">Address</span> boundary <span class="fu">error</span>)</span></code></pre></div>
<p>Oh no<a href="#fn4" class="footnote-ref" id="fnref4"
role="doc-noteref"><sup>4</sup></a>…</p>
<p>We just used <code>unsafeCoerce</code> to cast a
<code>Dict (Eq Bool)</code> to a <code>Dict (Num Int)</code>. We really
shouldn’t be able to do this.</p>
<p>The issue here is that <code>withLocal</code> places no constraints
on the — well — <em>constraints</em> (<code>c1</code> and
<code>c2</code>). In reality, we need both constraints to contain the
same typeclass and to only differ in the <em>argument</em> to that
class.</p>
<p>Let’s do that.</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode hs"><code class="sourceCode haskell"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="ot">withLocal ::</span> <span class="kw">forall</span> c a b d<span class="op">.</span> (c a) <span class="ot">=&gt;</span> (c b <span class="ot">=&gt;</span> d) <span class="ot">-&gt;</span> d</span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>withLocal x <span class="ot">=</span> <span class="kw">case</span> cbDict <span class="kw">of</span> <span class="dt">Dict</span> <span class="ot">-&gt;</span> x</span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">where</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a><span class="ot">        caDict ::</span> <span class="dt">Dict</span> (c a)</span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>        caDict <span class="ot">=</span> <span class="dt">Dict</span></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a><span class="ot">        cbDict ::</span> <span class="dt">Dict</span> (c b)</span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a>        cbDict <span class="ot">=</span> unsafeCoerce caDict </span></code></pre></div>
<p>Note that we did not change anything about the implementation. We
just constrained its type signature.</p>
<p>Unfortunately, <code>withLocal</code> can still segfault because
there are still no constraints on <code>a</code> and <code>b</code>. We
could, for instance, still try to convert a <code>Monoid String</code>
to a <code>Monoid Int</code>.</p>
<h2 id="why-did-this-even-work-before">Why did this even work
before?</h2>
<p>The reason why this function is safe on <code>Sum Int</code> and
<code>Int</code> is that <code>Sum Int</code> is just a newtype wrapper
over <code>Int</code>, and newtypes are completely erased at runtime. So
a function of type <code>Sum Int -&gt; b</code> really becomes a
function of type <code>Int -&gt; b</code> at runtime.</p>
<p>Thus we can safely<a href="#fn5" class="footnote-ref" id="fnref5"
role="doc-noteref"><sup>5</sup></a> cast it to <code>Int -&gt; b</code>
using <code>unsafeCoerce</code>.</p>
<p><code>String</code> and <code>Int</code> don’t have the same runtime
representation, so we cannot safely cast
<code>Dict (Monoid String)</code> to <code>Dict (Monoid Int)</code>.</p>
<p>Fortunately for us, Haskell does actually provide a way to constrain
a function to types with the same runtime representation:
<code>Coercible</code>!</p>
<p>If we adjust our function to include a <code>Coercible a b</code>
constraint, we finally end up with a safe implementation that doesn’t
segfault!</p>
<div class="sourceCode" id="cb10"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="ot">withLocal ::</span> <span class="kw">forall</span> c a b d<span class="op">.</span> (c a, <span class="dt">Coercible</span> a b) <span class="ot">=&gt;</span> (c b <span class="ot">=&gt;</span> d) <span class="ot">-&gt;</span> d</span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>withLocal x <span class="ot">=</span> <span class="kw">case</span> cbDict <span class="kw">of</span> <span class="dt">Dict</span> <span class="ot">-&gt;</span> x</span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">where</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a><span class="ot">        caDict ::</span> <span class="dt">Dict</span> (c a)</span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>        caDict <span class="ot">=</span> <span class="dt">Dict</span></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a><span class="ot">        cbDict ::</span> <span class="dt">Dict</span> (c b)</span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a>        cbDict <span class="ot">=</span> unsafeCoerce caDict </span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a>λ<span class="op">&gt;</span> withLocal <span class="op">@</span><span class="dt">Monoid</span> <span class="op">@</span>(<span class="dt">Sum</span> <span class="dt">Int</span>) <span class="op">@</span><span class="dt">Int</span> <span class="op">$</span> fold [<span class="dv">1</span><span class="op">..</span><span class="dv">10</span>] <span class="op">&lt;&gt;</span> (<span class="dv">5</span><span class="ot"> ::</span> <span class="dt">Int</span>)</span>
<span id="cb10-10"><a href="#cb10-10" aria-hidden="true" tabindex="-1"></a><span class="dv">60</span></span></code></pre></div>
<p>Note that we still had to use <code>unsafeCoerce</code> instead of
<code>coerce</code>. Just because <code>a</code> can be coerced to
<code>b</code>, doesn’t mean GHC will allow you to cast
<code>Dict (c a)</code> to <code>Dict (c b)</code>.</p>
<h2 id="expanding">Expanding</h2>
<p>What we have so far is already pretty cool, but we can do even
better.</p>
<p>So far, all our local instances were limited by us having to write an
instance for a newtype wrapper and so our instances could not include
entirely arbitrary functions.</p>
<p>We couldn’t, for example, declare a local function depending on a
local variable and use that in an instance, because instances have to be
written at the top level and therefore can’t include local
variables.</p>
<p>Fortunately, by selling a bit more of our soul to the type checker,
we can work around this limitation!</p>
<p>At runtime, dictionaries (not <code>Dict</code>s) are really just
regular data types, so there is no reason, why we shouldn’t be able to
fake them with <code>unsafeCoerce</code>.</p>
<p>Note, that <code>Dict</code> actually stores the runtime dictionary
as a lifted field, so if we want to coerce to <code>Dict</code>, we need
to add a layer of indirection.</p>
<div class="sourceCode" id="cb11"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">FakeDict</span> a <span class="ot">=</span> <span class="dt">FakeDict</span> a</span></code></pre></div>
<p>Now for the runtime dictionary, let’s look at the definition of the
<code>Eq</code> typeclass.</p>
<div class="sourceCode" id="cb12"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Eq</span> a <span class="kw">where</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a><span class="ot">  (==) ::</span> a <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">Bool</span></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a><span class="ot">  (/=) ::</span> a <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">Bool</span></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>  <span class="ot">{-# MINIMAL (==) | (/=) #-}</span></span></code></pre></div>
<p><code>Eq</code> has two methods <code>(==)</code> and
<code>(/=)</code>, so our datatype also has to have two fields with
matching types.</p>
<div class="sourceCode" id="cb13"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">EqDict</span> a <span class="ot">=</span> <span class="dt">EqDict</span> {</span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="ot">        _eq  ::</span> a <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">Bool</span></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a>    ,<span class="ot">   _neq ::</span> a <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">Bool</span></span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>    }</span></code></pre></div>
<p>Now we need a function to make <code>unsafeCoere</code> a little less
unsafe.</p>
<div class="sourceCode" id="cb14"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="ot">withFakeDictUnsafe ::</span> <span class="kw">forall</span> c d a<span class="op">.</span> d <span class="ot">-&gt;</span> (c <span class="ot">=&gt;</span> a) <span class="ot">-&gt;</span> a</span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a>withFakeDictUnsafe d x <span class="ot">=</span> <span class="kw">case</span> unsafeCoerce (<span class="dt">FakeDict</span> d)<span class="ot"> ::</span> <span class="dt">Dict</span> c <span class="kw">of</span></span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Dict</span> <span class="ot">-&gt;</span> x</span></code></pre></div>
<p>This already works for simple classes like <code>Eq</code>, but right
now we can’t handle classes with superclasses like <code>Monoid</code>,
because we have no way of storing the superclass dictionary in our fake
dictionary.</p>
<p>In order to include the dictionary, we have to expand our
<code>MonoidDict</code> to a GADT.</p>
<div class="sourceCode" id="cb15"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">MonoidDict</span> a <span class="kw">where</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>    <span class="dt">MonoidDict</span><span class="ot"> ::</span> <span class="dt">Semigroup</span> a <span class="ot">=&gt;</span> {</span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a><span class="ot">        _mempty  ::</span> a</span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a>    ,<span class="ot">   _mappend ::</span> a <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> a</span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a>    ,<span class="ot">   _mconcat ::</span> [a] <span class="ot">-&gt;</span> a </span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a>    } <span class="ot">-&gt;</span> <span class="dt">MonoidDict</span> a</span></code></pre></div>
<p>And… that’s it!</p>
<p>We can now actually write useful functions that we couldn’t just
emulate by wrapping everything in a newtype.</p>
<p>As an example, let’s consider a function that (locally) implements a
<code>Monoid</code> instance for a type, which only implements
<code>Semigroup</code>, based on a provided default argument for
<code>mempty</code>.</p>
<div class="sourceCode" id="cb16"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="ot">withSemigroupAsMonoid ::</span> <span class="kw">forall</span> a b<span class="op">.</span> <span class="dt">Semigroup</span> a <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> (<span class="dt">Monoid</span> a <span class="ot">=&gt;</span> b) <span class="ot">-&gt;</span> b</span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a>withSemigroupAsMonoid d <span class="ot">=</span> withFakeDictUnsafe <span class="op">@</span>(<span class="dt">Monoid</span> a) (<span class="dt">MonoidDict</span> {</span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a>        _mempty  <span class="ot">=</span> d</span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a>    ,   _mappend <span class="ot">=</span> (<span class="op">&lt;&gt;</span>)</span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a>    ,   _mconcat <span class="ot">=</span> <span class="fu">foldr</span> (<span class="op">&lt;&gt;</span>) d</span>
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a>    })</span></code></pre></div>
<p>We couldn’t use a newtype instance, since
<code>withSemigroupAsMonoid</code> uses the function parameter
<code>d</code> in its instance definition.</p>
<h2 id="template-haskell">Template Haskell</h2>
<p>Writing all these Dict types by hand is not just annoying, but also
quite dangerous because they are not automatically kept in sync with the
corresponding type classes, so if one of those changes and we forget to
update the Dict, the types are not actually compatible anymore.</p>
<p>We can use some TemplateHaskell to automate the process and
(hopefully) avoid further segfaults.</p>
<p>My experience with TemplateHaskell is pretty limited, so I’m not
going to pretend like this is a great implementation.<a href="#fn6"
class="footnote-ref" id="fnref6" role="doc-noteref"><sup>6</sup></a></p>
<div class="sourceCode" id="cb17"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="ot">makeDict ::</span> <span class="dt">Name</span> <span class="ot">-&gt;</span> <span class="dt">Q</span> [<span class="dt">Dec</span>]</span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a>makeDict cname <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a>    reify cname <span class="op">&gt;&gt;=</span> \<span class="kw">case</span> <span class="co">-- (1)</span></span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a>        <span class="dt">ClassI</span> cdec is <span class="ot">-&gt;</span> <span class="kw">case</span> cdec <span class="kw">of</span></span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a>            <span class="dt">ClassD</span> cxt cname tvs _ meths <span class="ot">-&gt;</span> <span class="fu">pure</span> [</span>
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a>                        dataCon [] dname tvs <span class="dt">Nothing</span> [<span class="dt">ForallC</span> (<span class="fu">map</span> (addSpecificity <span class="dt">SpecifiedSpec</span>) tvs) cxt </span>
<span id="cb17-7"><a href="#cb17-7" aria-hidden="true" tabindex="-1"></a>                            <span class="op">$</span> <span class="dt">RecGadtC</span> [dname] (<span class="fu">map</span> methodToVarBangType meths) appliedFakeType] [] <span class="co">-- (2)</span></span>
<span id="cb17-8"><a href="#cb17-8" aria-hidden="true" tabindex="-1"></a>                    ]</span>
<span id="cb17-9"><a href="#cb17-9" aria-hidden="true" tabindex="-1"></a>                <span class="kw">where</span></span>
<span id="cb17-10"><a href="#cb17-10" aria-hidden="true" tabindex="-1"></a>                    dataCon <span class="ot">=</span> <span class="kw">case</span> (meths, cxt) <span class="kw">of</span></span>
<span id="cb17-11"><a href="#cb17-11" aria-hidden="true" tabindex="-1"></a>                        ([_], []) <span class="ot">-&gt;</span> \cxt name tvs k [cs] ds <span class="ot">-&gt;</span> <span class="dt">NewtypeD</span> cxt name tvs k cs ds <span class="co">-- (4)</span></span>
<span id="cb17-12"><a href="#cb17-12" aria-hidden="true" tabindex="-1"></a>                        _ <span class="ot">-&gt;</span> <span class="dt">DataD</span></span>
<span id="cb17-13"><a href="#cb17-13" aria-hidden="true" tabindex="-1"></a>                    dname <span class="ot">=</span> mkName <span class="op">$</span> nameBase cname <span class="op">&lt;&gt;</span> <span class="st">&quot;Dict&quot;</span> <span class="co">-- (3)</span></span>
<span id="cb17-14"><a href="#cb17-14" aria-hidden="true" tabindex="-1"></a>                    </span>
<span id="cb17-15"><a href="#cb17-15" aria-hidden="true" tabindex="-1"></a>                    methodToVarBangType (<span class="dt">SigD</span> n t) <span class="ot">=</span> (mkName (<span class="st">&quot;_&quot;</span> <span class="op">&lt;&gt;</span> nameBase n), <span class="dt">Bang</span> <span class="dt">SourceNoUnpack</span> <span class="dt">NoSourceStrictness</span>, t)</span>
<span id="cb17-16"><a href="#cb17-16" aria-hidden="true" tabindex="-1"></a>                    </span>
<span id="cb17-17"><a href="#cb17-17" aria-hidden="true" tabindex="-1"></a>                    appliedFakeType  <span class="ot">=</span> <span class="fu">foldl</span> <span class="dt">AppT</span> (<span class="dt">ConT</span> dname) (<span class="fu">map</span> (<span class="dt">VarT</span> <span class="op">.</span> tyVarName) tvs)</span>
<span id="cb17-18"><a href="#cb17-18" aria-hidden="true" tabindex="-1"></a>                    appliedClassType <span class="ot">=</span> <span class="fu">foldl</span> <span class="dt">AppT</span> (<span class="dt">ConT</span> cname) (<span class="fu">map</span> (<span class="dt">VarT</span> <span class="op">.</span> tyVarName) tvs)</span>
<span id="cb17-19"><a href="#cb17-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-20"><a href="#cb17-20" aria-hidden="true" tabindex="-1"></a>                    addSpecificity s (<span class="dt">PlainTV</span> n _) <span class="ot">=</span> <span class="dt">PlainTV</span> n s</span>
<span id="cb17-21"><a href="#cb17-21" aria-hidden="true" tabindex="-1"></a>                    addSpecificity s (<span class="dt">KindedTV</span> n _ k) <span class="ot">=</span> <span class="dt">KindedTV</span> n s k</span>
<span id="cb17-22"><a href="#cb17-22" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-23"><a href="#cb17-23" aria-hidden="true" tabindex="-1"></a>                    tyVarName (<span class="dt">PlainTV</span> n _) <span class="ot">=</span> n</span>
<span id="cb17-24"><a href="#cb17-24" aria-hidden="true" tabindex="-1"></a>                    tyVarName (<span class="dt">KindedTV</span> n _ _) <span class="ot">=</span> n</span>
<span id="cb17-25"><a href="#cb17-25" aria-hidden="true" tabindex="-1"></a>            _ <span class="ot">-&gt;</span> <span class="fu">fail</span> <span class="op">$</span> <span class="st">&quot;Not a class: &quot;</span> <span class="op">&lt;&gt;</span> <span class="fu">show</span> cname</span>
<span id="cb17-26"><a href="#cb17-26" aria-hidden="true" tabindex="-1"></a>        _ <span class="ot">-&gt;</span> <span class="fu">fail</span> <span class="op">$</span> <span class="st">&quot;Not a class: &quot;</span> <span class="op">&lt;&gt;</span> <span class="fu">show</span> cname</span></code></pre></div>
<p>The important steps are these:</p>
<ol type="1">
<li>We get the class definition using <code>reify</code></li>
<li>We can use that definition to construct a record GADT
(<code>RecGadtC</code>) with one field for every class method.</li>
<li>The new GADT is called <code>&lt;ClassName&gt;Dict</code>.</li>
<li>If there is only a single method and no superclass, we construct a
newtype instead. Note that this step is not just an optimization, but
absolutely crucial, since a <code>data</code> constructor has one more
level of indirection than a newtype, and confusing the two would lead to
a segfault.</li>
</ol>
<p>We actually get another benefit from generating our instance. Since
we know, that using <code>withFakeDictUnsafe</code> with our generated
<code>MonoidDict</code> is safe, we can use a (non-exported) type class
and a function <code>withFakeDict</code> to constrain arguments to
<em>safe</em> (i.e. generated) dictionaries.</p>
<div class="sourceCode" id="cb18"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">FakeDictFor</span> (<span class="ot">c ::</span> <span class="dt">Constraint</span>) (<span class="ot">d ::</span> <span class="dt">Type</span>) <span class="op">|</span> d <span class="ot">-&gt;</span> c</span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a><span class="ot">withFakeDict ::</span> <span class="kw">forall</span> d c a<span class="op">.</span> <span class="dt">FakeDictFor</span> c d <span class="ot">=&gt;</span> d <span class="ot">-&gt;</span> (c <span class="ot">=&gt;</span> a) <span class="ot">-&gt;</span> a</span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a>withFakeDict <span class="ot">=</span> withFakeDictUnsafe</span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a><span class="ot">makeDict ::</span> <span class="dt">Name</span> <span class="ot">-&gt;</span> <span class="dt">Q</span> [<span class="dt">Dec</span>]</span>
<span id="cb18-7"><a href="#cb18-7" aria-hidden="true" tabindex="-1"></a>makeDict cname <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb18-8"><a href="#cb18-8" aria-hidden="true" tabindex="-1"></a>    <span class="co">{- ... -}</span></span>
<span id="cb18-9"><a href="#cb18-9" aria-hidden="true" tabindex="-1"></a>    [d|instance FakeDictFor $(pure appliedClassType) $(pure appliedFakeType)|]</span>
<span id="cb18-10"><a href="#cb18-10" aria-hidden="true" tabindex="-1"></a>    <span class="co">{- ... -}</span></span></code></pre></div>
<h2 id="incoherence">Incoherence</h2>
<p>Unfortunately, both <code>withLocal</code> and
<code>withFakeDictUnsafe</code> have a pretty serious flaw. Usually,
whenever we use a typeclass method in Haskell, there are essentially two
possibilities: either <em>no</em> instance exists or there is
<em>exactly one</em> and the compiler picks that one. This is called
<em>Coherence</em> and is also the reason why all in-scope typeclass
instances are always exported from a module.</p>
<p>The issue with our functions is that in case there is already an
instance for the typeclass, they introduce a second instance and break
the compiler’s Coherence assumption.</p>
<p>As an example, let’s say we want to introduce a local instance for
<code>Show Int</code>. If we do this, using <code>withLocal</code><a
href="#fn7" class="footnote-ref" id="fnref7"
role="doc-noteref"><sup>7</sup></a>, which instance is the compiler
going to pick? Let’s find out!</p>
<div class="sourceCode" id="cb19"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">FancyShow</span> a <span class="ot">=</span> <span class="dt">FancyShow</span> a</span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Show</span> a <span class="ot">=&gt;</span> <span class="dt">Show</span> (<span class="dt">FancyShow</span> a) <span class="kw">where</span> </span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a>    <span class="fu">show</span> (<span class="dt">FancyShow</span> x) <span class="ot">=</span> <span class="st">&quot;⭐&quot;</span> <span class="op">&lt;&gt;</span> <span class="fu">show</span> x <span class="op">&lt;&gt;</span> <span class="st">&quot;⭐&quot;</span></span>
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> withLocal <span class="op">@</span><span class="dt">Show</span> <span class="op">@</span>(<span class="dt">FancyShow</span> <span class="dt">Int</span>) <span class="op">@</span><span class="dt">Int</span> <span class="op">$</span> <span class="fu">print</span> (<span class="dv">5</span><span class="ot"> ::</span> <span class="dt">Int</span>)</span></code></pre></div>
<div class="sourceCode" id="cb20"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> ghc unsafeCoerceDict.hs <span class="kw">&amp;&amp;</span> <span class="ex">./unsafeCoerceDict</span></span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a><span class="ex">[1</span> of 1] Compiling Main             <span class="er">(</span> <span class="ex">unsafeCoerceDict.hs,</span> unsafeCoerceDict.o <span class="kw">)</span></span>
<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a><span class="ex">Linking</span> unsafeCoerceDict ...</span>
<span id="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a><span class="ex">⭐5⭐</span></span></code></pre></div>
<p>Nice! It seems like we can override instances using
<code>withLocal</code>. Let’s try that with optimizations</p>
<div class="sourceCode" id="cb21"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> ghc <span class="at">-O</span> unsafeCoerceDict.hs <span class="kw">&amp;&amp;</span> <span class="ex">./unsafeCoerceDict</span></span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a><span class="ex">[1</span> of 1] Compiling Main             <span class="er">(</span> <span class="ex">unsafeCoerceDict.hs,</span> unsafeCoerceDict.o <span class="kw">)</span></span>
<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a><span class="ex">Linking</span> unsafeCoerceDict ...</span>
<span id="cb21-4"><a href="#cb21-4" aria-hidden="true" tabindex="-1"></a><span class="ex">5</span></span></code></pre></div>
<p>Oh no… optimizations can change the semantics of our program by
picking the original instance, that we tried to override. We really
don’t want that.</p>
<p>To make matters worse, there is no way to prevent incoherent usage
without having to include Template Haskell at call sites, since there is
no way to write a type like
<code>Not (Eq a) =&gt; (Eq a =&gt; b) -&gt; b</code>.</p>
<p>It’s not that bad though. As long as we make sure to never try to
override existing instances, we are safe.</p>
<h2 id="implicitparams">ImplicitParams</h2>
<p><code>withFakeDict</code> might remind you of a different Haskell
feature, namely <code>ImplicitParams</code>. And indeed, we can directly
interoperate with <code>ImplicitParams</code> using
<code>withFakeDict</code>.</p>
<p>An implicit parameter constraint like</p>
<div class="sourceCode" id="cb22"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a><span class="ot">f ::</span> (<span class="op">?</span><span class="ot">x ::</span> <span class="dt">Int</span>) <span class="ot">=&gt;</span> <span class="dt">Int</span></span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a>f <span class="ot">=</span> <span class="op">?</span>x <span class="op">+</span> <span class="dv">1</span></span></code></pre></div>
<p>is really just syntactic sugar for</p>
<div class="sourceCode" id="cb23"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true" tabindex="-1"></a><span class="ot">f ::</span> (<span class="dt">IP</span> <span class="st">&quot;x&quot;</span> <span class="dt">Int</span>) <span class="ot">=&gt;</span> <span class="dt">Int</span></span>
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a>f <span class="ot">=</span> ip <span class="op">@</span><span class="st">&quot;x&quot;</span> <span class="op">+</span> <span class="dv">1</span></span></code></pre></div>
<p>where IP is a regular type class defined in
<code>GHC.Classes</code>.</p>
<p>What’s really cool about this is that we can actually define an
<code>IP</code> constraint using <code>withFakeDict</code>.</p>
<p>So instead of</p>
<div class="sourceCode" id="cb24"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> <span class="op">?</span>x <span class="ot">=</span> <span class="dv">5</span> <span class="kw">in</span> f</span></code></pre></div>
<p>we can write</p>
<div class="sourceCode" id="cb25"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a>withFakeDict <span class="op">@</span>(<span class="dt">IPDict</span> <span class="st">&quot;x&quot;</span> <span class="dt">Int</span>) (<span class="dt">IPDict</span> {_ip <span class="ot">=</span> <span class="dv">5</span>}) f</span></code></pre></div>
<p>and get the exact same behavior!</p>
<p>This means that <code>withFakeDict</code> is strictly more powerful
than ImplicitParams, but it also shares ImplicitParams’ <a
href="https://chrisdone.com/posts/whats-wrong-with-implicitparams/">somewhat
famous</a> <a
href="https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/implicit_parameters.html#implicit-parameters-and-polymorphic-recursion">issues</a>.</p>
<h2 id="configurable-trace">Configurable trace</h2>
<p><code>Debug.Trace.trace</code> can be a very useful function for
quick debugging. Want to know what this intermediate expression
evaluates to? Just write it to stderr using <code>trace</code>. Want to
know what values this function is called with? You can use trace for
that.</p>
<div class="sourceCode" id="cb26"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a><span class="ot">f ::</span> <span class="dt">A</span> <span class="ot">-&gt;</span> <span class="dt">B</span></span>
<span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a>f x <span class="op">|</span> trace (<span class="st">&quot;x = &quot;</span> <span class="op">&lt;&gt;</span> <span class="fu">show</span> x) <span class="dt">False</span> <span class="ot">=</span> <span class="fu">error</span> <span class="st">&quot;unreachable&quot;</span></span>
<span id="cb26-3"><a href="#cb26-3" aria-hidden="true" tabindex="-1"></a>f x <span class="ot">=</span> <span class="op">...</span></span></code></pre></div>
<p>Unfortunately, <code>trace</code> is not really suited for slightly
more permanent tracing, since there is no way to turn it off or to
change the target it writes to.</p>
<p>If we wanted to improve trace, we would have to somehow pass a
configuration without <em>actually</em> passing it manually to every
single function. Sounds a lot like type classes to me!</p>
<p>Let’s try that. We should also probably use <code>Text</code> instead
of <code>String</code>, while we’re at it.</p>
<div class="sourceCode" id="cb27"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Trace</span> <span class="kw">where</span></span>
<span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a><span class="ot">    trace ::</span> <span class="dt">Text</span> <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> a</span></code></pre></div>
<p>To make filtering easier, we should probably also accept some kind of
trace level. We could just accept an integer, but parameterizing our
class over the type of the trace level is more general.</p>
<div class="sourceCode" id="cb28"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb28-1"><a href="#cb28-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Trace</span> lvl <span class="kw">where</span></span>
<span id="cb28-2"><a href="#cb28-2" aria-hidden="true" tabindex="-1"></a><span class="ot">    trace ::</span> lvl <span class="ot">-&gt;</span> <span class="dt">Text</span> <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> a</span></code></pre></div>
<p>Cool. Functions that want to perform logging now need an additional
<code>Trace lvl</code> constraint, that supplies the actual
implementation.</p>
<p>How do we pick the implementation though? If you’ve paid attention so
far, the answer should be obvious: We construct a fake dictionary using
<code>withFakeDict</code>.</p>
<div class="sourceCode" id="cb29"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb29-1"><a href="#cb29-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Trace</span> lvl <span class="kw">where</span></span>
<span id="cb29-2"><a href="#cb29-2" aria-hidden="true" tabindex="-1"></a><span class="ot">    trace ::</span> lvl <span class="ot">-&gt;</span> <span class="dt">Text</span> <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> a</span>
<span id="cb29-3"><a href="#cb29-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb29-4"><a href="#cb29-4" aria-hidden="true" tabindex="-1"></a>makeDict &#39;<span class="dt">&#39;Trace</span></span>
<span id="cb29-5"><a href="#cb29-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb29-6"><a href="#cb29-6" aria-hidden="true" tabindex="-1"></a><span class="ot">runTraceStderr ::</span> (<span class="dt">Trace</span> lvl <span class="ot">=&gt;</span> a) <span class="ot">-&gt;</span> a</span>
<span id="cb29-7"><a href="#cb29-7" aria-hidden="true" tabindex="-1"></a>runTraceStderr <span class="ot">=</span> withFakeDict (<span class="dt">TraceDict</span> {</span>
<span id="cb29-8"><a href="#cb29-8" aria-hidden="true" tabindex="-1"></a>        _trace _ <span class="ot">=</span> Debug.Trace.trace</span>
<span id="cb29-9"><a href="#cb29-9" aria-hidden="true" tabindex="-1"></a>    })</span>
<span id="cb29-10"><a href="#cb29-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb29-11"><a href="#cb29-11" aria-hidden="true" tabindex="-1"></a><span class="ot">ignoreTrace ::</span> (<span class="dt">Trace</span> lvl <span class="ot">=&gt;</span> a) <span class="ot">-&gt;</span> a</span>
<span id="cb29-12"><a href="#cb29-12" aria-hidden="true" tabindex="-1"></a>ignoreTrace <span class="ot">=</span> withFakeDict (<span class="dt">TraceDict</span> {</span>
<span id="cb29-13"><a href="#cb29-13" aria-hidden="true" tabindex="-1"></a>    _trace _ _ x <span class="ot">=</span> x</span>
<span id="cb29-14"><a href="#cb29-14" aria-hidden="true" tabindex="-1"></a>})</span></code></pre></div>
<p>One issue that might still come up is that someone could
theoretically define a top-level instance of <code>Trace lvl</code>,
which would introduce incoherence and completely break our system. To
prevent that, we can hide the actual implementation in a class
<code>_Trace</code>, that we don’t actually export. We can then define a
type synonym <code>Trace</code> that we <em>do</em> export. This way,
users of our library can still reference Trace through our type synonym,
but cannot define top-level instances since instances cannot be defined
for type synonyms of type classes.</p>
<div class="sourceCode" id="cb30"><pre
class="sourceCode hs"><code class="sourceCode haskell"><span id="cb30-1"><a href="#cb30-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> _Trace lvl <span class="kw">where</span></span>
<span id="cb30-2"><a href="#cb30-2" aria-hidden="true" tabindex="-1"></a><span class="ot">    trace ::</span> lvl <span class="ot">-&gt;</span> <span class="dt">Text</span> <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> a</span>
<span id="cb30-3"><a href="#cb30-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb30-4"><a href="#cb30-4" aria-hidden="true" tabindex="-1"></a>makeDict &#39;&#39;_Trace</span>
<span id="cb30-5"><a href="#cb30-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb30-6"><a href="#cb30-6" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">Trace</span> <span class="ot">=</span> _Trace</span>
<span id="cb30-7"><a href="#cb30-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb30-8"><a href="#cb30-8" aria-hidden="true" tabindex="-1"></a><span class="ot">runTraceStderr ::</span> (<span class="dt">Trace</span> lvl <span class="ot">=&gt;</span> a) <span class="ot">-&gt;</span> a</span>
<span id="cb30-9"><a href="#cb30-9" aria-hidden="true" tabindex="-1"></a>runTraceStderr <span class="ot">=</span> withFakeDict (<span class="dt">Trace_Dict</span> {</span>
<span id="cb30-10"><a href="#cb30-10" aria-hidden="true" tabindex="-1"></a>        _trace _ <span class="ot">=</span> Debug.Trace.trace</span>
<span id="cb30-11"><a href="#cb30-11" aria-hidden="true" tabindex="-1"></a>    })</span>
<span id="cb30-12"><a href="#cb30-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb30-13"><a href="#cb30-13" aria-hidden="true" tabindex="-1"></a><span class="ot">ignoreTrace ::</span> (<span class="dt">Trace</span> lvl <span class="ot">=&gt;</span> a) <span class="ot">-&gt;</span> a</span>
<span id="cb30-14"><a href="#cb30-14" aria-hidden="true" tabindex="-1"></a>ignoreTrace <span class="ot">=</span> withFakeDict (<span class="dt">Trace_Dict</span> {</span>
<span id="cb30-15"><a href="#cb30-15" aria-hidden="true" tabindex="-1"></a>    _trace _ _ x <span class="ot">=</span> x</span>
<span id="cb30-16"><a href="#cb30-16" aria-hidden="true" tabindex="-1"></a>})</span></code></pre></div>
<p>Nice! We just defined a fairly extensible little tracing library in
less than 20 lines of code.</p>
<p>Here is why this is a good application of fake local instances</p>
<ul>
<li>There is no reason to manually implement the <code>Trace</code> type
class, so we were able to hide it completely and fully prevent
incoherence.</li>
<li>In case we made a mistake or this whole approach is fundamentally
flawed and GHC decides to pick the wrong instance, nothing major breaks.
(You can never be entirely sure with <code>unsafeCoerce</code> tricks
like this)</li>
<li>This is really easy to implement, and much less limited than most
alternative approaches (Logging monads/effects, global
<code>IORef</code>s, …)</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<p>Now, what did we learn from all of this?</p>
<ul>
<li>It is possible to transfer instances between newtypes.</li>
<li>This approach can be expanded to allow the inclusion of arbitrary
functions as instance methods.</li>
<li>All segfaults stemming from non-unsafe functions can be avoided and
it is possible to generate most boilerplate.</li>
<li>Incoherence, stemming from multiple instances being available at
once, is an issue.</li>
<li>ImplicitParams can be emulated with local instances.</li>
<li>A tiny extensible tracing library is a pretty cool application of
local instances.</li>
</ul>
<p>Does this mean, you should throw all your newtypes out of the window?
No.</p>
<p>Does this mean, you should use the code from this article in
production? Probably not. You should really know what you’re doing if
you want to use anything in production that is based on
<code>unsafeCoerce</code>. That said, if you want to try this out for
yourself, the code is available in a <a
href="https://github.com/Innf107/fakedict">small library on github</a>,
including <code>trace</code>.</p>
<p>Ultimately, I hope that you learned a nice little trick today. You
never know when it might come in handy.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>In this particular example, most boilerplate could be
eliminated by using <code>Sum</code>’s <code>Num</code> instance, but in
most real scenarios it’s unfortunately not that simple.<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>There are very good reasons why Haskell doesn’t have
local instances, but we’ll get to that.<a href="#fnref2"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>Well… we’ll see about that.<a href="#fnref3"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn4"><p>I told you, unsafeCoerce was dangerous…<a href="#fnref4"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn5"><p><em>safe</em> here just means that it doesn’t segfault.
We’ll get to other meanings of safe, don’t worry!<a href="#fnref5"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn6"><p>Feel free to <a
href="https://github.com/Innf107/fakedict/tree/main/src/Fakedict/TH.hs">submit
a pull request</a> if you would like to write a better implementation<a
href="#fnref6" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn7"><p>I did not use <code>withFakeDict</code> here, since
<code>Show</code> has a few additional methods that we would have had to
implement manually<a href="#fnref7" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
    <pubDate>Fri, 18 Mar 2022 00:00:00 +0100</pubDate>
</item>
    </channel>
</rss>