<?xml version='1.0' encoding='UTF-8'?>
<feed xmlns='http://www.w3.org/2005/Atom' xmlns:g='http://base.google.com/ns/1.0'>
  <title>Reasonably Polymorphic</title>
  <updated>2026-01-02T14:27:00Z</updated>
  <author><name>Sandy Maguire</name></author>
  <id>http://reasonablypolymorphic.com</id>
  <link rel='self' href='https://reasonablypolymorphic.com'/>

    <entry>
      <title>An Algebraic Theory of Music</title>
      <id>blog/more-algebraic-music/index.html</id>
      <link href='blog/more-algebraic-music/index.html'/>
      <published>2026-01-02T14:27:00Z</published>
      <updated>2026-01-02T14:27:00Z</updated>

      <content type="html" xml:base="https://reasonablypolymorphic.com">
        <![CDATA[
        <p>In my last post, I was <a href="/blog/algebraic-music/">struggling towards an algebraic theory of music.</a> This idea has been burning in my mind ever since, and I wanted to give some updates with where I’ve landed.</p>
<h2 id="differentiating-voices-from-music">Differentiating Voices from Music</h2>
<p>We begin by modeling a <a href="https://en.wikipedia.org/wiki/Part_(music)#Polyphony_and_part-writing">musical voice</a>, which is, roughly speaking, the abstract version of a human voice. The voice can be doing one thing at a time, or can choose to not be doing anything.</p>
<p>Voices are modeled by <a href="https://hackage.haskell.org/package/step-function">step functions</a>, which are divisions of the real line into discrete chunks. We interpret each discrete chunk as a note being played by the voice for the duration of the chunk.</p>
<p>This gives rise to a nice applicative structure that I alluded to in my previous post:</p>
<pre><code>liftA2 f
  |---- a ----|-- b --|
  |-- x --|---- y ----|
=
  |- fax -|fay|- fby -|</code></pre>
<p>where we take the union of the note boundaries in order to form the applicative. If either voice is resting, so too is the applicative. There is also an <code>Alternative</code> instance here, which chooses the first non-rest.</p>
<p>There is a similar monoidal structure here, where multiplication is given by “play these two things simultaneously,” relying on an underlying <code>Semigroup</code> instance for the meaning of “play these two things:”</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode haskell"><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> a <span class="ot">=&gt;</span> <span class="dt">Semigroup</span> (<span class="dt">Voice</span> a)</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Semigroup</span> a <span class="ot">=&gt;</span> <span class="dt">Monoid</span> (<span class="dt">Voice</span> a)</span></code></pre></div>
<p>If either voice is resting, we treat its value as <code>mempty</code>, and can happily combine the two parts in parallel.</p>
<p>All of this gives rise to the following rich structure:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell"><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">Voice</span> a <span class="ot">=</span> <span class="dt">Voice</span> {<span class="ot"> unVoice ::</span> <span class="dt">SF</span> <span class="dt">Time</span> (<span class="dt">Maybe</span> a) }</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> stock</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>    (<span class="dt">Eq</span>, <span class="dt">Ord</span>, <span class="dt">Show</span>, <span class="dt">Functor</span>, <span class="dt">Foldable</span>, <span class="dt">Traversable</span>, <span class="dt">Generic</span>, <span class="dt">Generic1</span>)</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> <span class="kw">newtype</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>    (<span class="dt">Semigroup</span>, <span class="dt">Monoid</span>)</span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Applicative</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>    via <span class="dt">Compose</span> (<span class="dt">SF</span> <span class="dt">Time</span>) <span class="dt">Maybe</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Filterable</span> <span class="dt">Voice</span></span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Witherable</span> <span class="dt">Voice</span></span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Alternative</span> <span class="dt">Voice</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="co">-- | Delay a voice by some amount of time.</span></span>
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true" tabindex="-1"></a><span class="ot">delayV ::</span> <span class="dt">Time</span> <span class="ot">-&gt;</span> <span class="dt">Voice</span> a <span class="ot">-&gt;</span> <span class="dt">Voice</span> a</span></code></pre></div>
<h2 id="from-voices-to-music">From Voices to Music</h2>
<p>Voices, therefore, give us our primitive notion of monophony. But real music usually has many voices doing many things, independently. This was a point in which I got stuck in my previous post.</p>
<p>The solution here, is surprisingly easy. Assign a <code>Voice</code> to each voice name:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">Music</span> v a <span class="ot">=</span> <span class="dt">Music</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>  {<span class="ot"> getVoices ::</span> v <span class="ot">-&gt;</span> <span class="dt">Voice</span> a</span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>  }</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> stock</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>    (<span class="dt">Functor</span>, <span class="dt">Generic</span>, <span class="dt">Functor</span>)</span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> <span class="kw">newtype</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>    (<span class="dt">Semigroup</span>, <span class="dt">Monoid</span>)</span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Applicative</span>, <span class="dt">Alternative</span>)</span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>    via <span class="dt">Compose</span> ((<span class="ot">-&gt;</span>) v) <span class="dt">Voice</span></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Profunctor</span> <span class="dt">Music</span></span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Finite</span> v <span class="ot">=&gt;</span> <span class="dt">Foldable</span> (<span class="dt">Music</span> v)</span>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Finite</span> v <span class="ot">=&gt;</span> <span class="dt">Traversable</span> (<span class="dt">Music</span> v)</span>
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Filterable</span> (<span class="dt">Music</span> v)</span>
<span id="cb4-16"><a href="#cb4-16" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Finite</span> v <span class="ot">=&gt;</span> <span class="dt">Witherable</span> (<span class="dt">Music</span> v)</span></code></pre></div>
<p>We get an extremely rich structure here completely for free. Our monoid combines all voices in parallel; our applicative combines voices pointwise; etc. However, we also have a new <code>Profunctor Music</code> instance, whose characteristic <code>lmap :: (b -&gt; c) -&gt; Music c a -&gt; Music b a</code> method allows us to trade lines between voices.</p>
<p>In addition to the <em>in-parallel</em> monoid instance, we can also define a <a href="https://dl.acm.org/doi/10.1145/2633638.2633649">tile product</a> operator over <code>Music v a</code>, which composes things sequentially<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="ot">duration ::</span> <span class="dt">Music</span> v a <span class="ot">-&gt;</span> <span class="dt">Time</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="ot">(##) ::</span> <span class="dt">Semigroup</span> a <span class="ot">=&gt;</span> <span class="dt">Music</span> v a <span class="ot">-&gt;</span> <span class="dt">Music</span> v a <span class="ot">-&gt;</span> <span class="dt">Music</span> v a</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>m<span class="op">@</span>(<span class="dt">Music</span> m1) <span class="op">##</span> <span class="dt">Music</span> m2 <span class="ot">=</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Music</span> <span class="op">$</span> liftA2 (<span class="op">&lt;&gt;</span>) m1 <span class="op">$</span> <span class="fu">fmap</span> (delayV <span class="op">$</span> duration m) m2</span></code></pre></div>
<p>The <code>Semigroup a</code> constraint on <code>(##)</code> arises from the fact that the pieces of music might extend off to infinity in either direction (which <code>pure @Voice</code> must do), and we need to deal with that.</p>
<p>There are a few other combinators we care about. First, we can lift anonymous voices (colloquially “tunes”) into multi-part <code>Music</code>:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="ot">voice ::</span> <span class="dt">Eq</span> v <span class="ot">=&gt;</span> v <span class="ot">-&gt;</span> <span class="dt">Music</span> () a <span class="ot">-&gt;</span> <span class="dt">Music</span> v a</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>voice v (<span class="dt">Music</span> sf) <span class="ot">=</span> <span class="dt">Music</span> <span class="op">$</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>  \<span class="kw">case</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>    ((<span class="op">==</span> v) <span class="ot">-&gt;</span> <span class="dt">True</span>) <span class="ot">-&gt;</span> sf ()</span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>    _ <span class="ot">-&gt;</span> <span class="fu">mempty</span></span></code></pre></div>
<p>and we can assign the same line to everyone:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="ot">everyone ::</span> <span class="dt">Music</span> () a <span class="ot">-&gt;</span> <span class="dt">Music</span> v a</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>everyone (<span class="dt">Music</span> m) <span class="ot">=</span> <span class="dt">Music</span> <span class="op">$</span> <span class="fu">const</span> <span class="op">$</span> m ()</span></code></pre></div>
<h2 id="writing-lines">Writing Lines</h2>
<p>The primitives for building little tunes are</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="ot">note ::</span> <span class="dt">Time</span> <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">Music</span> () a</span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="ot">rest ::</span> <span class="dt">Time</span> <span class="ot">-&gt;</span> <span class="dt">Music</span> () a</span></code></pre></div>
<p>which you can then compose sequentially via <code>(##)</code>, and assign to voices via <code>voice</code>.</p>
<h2 id="harmonic-constraints">Harmonic Constraints</h2>
<p>One of the better responses to my last blog post was a link to <a href="https://dmitri.mycpanel.princeton.edu/index.html">Dmitri Tymoczko</a>’s <a href="https://www.youtube.com/watch?v=yp5Eys2L_04">FARM 2024 talk</a>.</p>
<p>There’s much more in this video than I can possibly due justice to here, but my big takeaway was that this guy is thinking about the same sorts of things that I am. So I dove into his work, and that lead to his <a href="https://www.madmusicalscience.com/quadruple.mp4">quadruple hierarchy</a>:</p>
<blockquote>
<p>Voices move within chords, which move within scales, which move within macro-harmonies.</p>
</blockquote>
<p>Tymoczko presents a <code>T</code> algebra which is a geometric space for reasoning about voice leadings. He’s got a lot of fun websites for exploring the ideas, but I couldn’t find an actual implementation of the idea anywhere, so I <a href="https://github.com/isovector/denomusic/blob/6a313a546cc376bb22f37cec55d76518bff40acd/src/DenoMusic/Harmony.hs">cooked one up</a> myself.</p>
<p>The idea here is that we have some <code>T :: [Nat] -&gt; Type</code> which describes a hierarchy of abstract scales moving with respect to one another. For example, the Western traditional of having triads move within the diatonic scale, which moves within the chromatic scale, would be represented as <code>T '[3, 7, 12]</code>. <code>T</code> forms a monoid, and has some simple generators that give rise to smooth voice leadings (chord changes.)</p>
<p>Having a model for smooth harmonic transformations means we can use it constructively. I am still working out the exact details here, but the rough shape of the idea is to build an underlying field of key changes (represented as smooth voice leadings in <code>T '[7, 12]</code>):</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="ot">keyChanges ::</span> <span class="dt">Music</span> () (<span class="dt">T</span> &#39;[<span class="dv">7</span>, <span class="dv">12</span>])</span></code></pre></div>
<p>We can then make an underlying field of functional harmonic changes (chord changes), modeled as smooth voice leadings in <code>T '[3, 7]</code>:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="ot">chordChanges ::</span> <span class="dt">Music</span> () (<span class="dt">T</span> &#39;[<span class="dv">3</span>, <span class="dv">7</span>])</span></code></pre></div>
<p>Our voices responsible for harmony can now be written as values of type</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="ot">harmonicVoices ::</span> <span class="dt">Music</span> h (<span class="dt">Set</span> (<span class="dt">T</span> &#39;[<span class="dv">3</span>]))</span></code></pre></div>
<p>and we can use the applicative musical structure to combine the elements together:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE ApplicativeDo #-}</span></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">extend ::</span> <span class="dt">T</span> ns <span class="ot">-&gt;</span> <span class="dt">T</span> (ns <span class="op">++</span> ms)</span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a><span class="ot">sink   ::</span> <span class="dt">T</span> ns <span class="ot">-&gt;</span> <span class="dt">T</span> (n &#39;<span class="op">:</span> ns)</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="ot">harmony ::</span> <span class="dt">Music</span> h (<span class="dt">Set</span> (<span class="dt">T</span> &#39;[<span class="dv">3</span>, <span class="dv">7</span>, <span class="dv">12</span>]))</span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a>harmony <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a>  k <span class="ot">&lt;-</span> everyone keyChanges</span>
<span id="cb12-9"><a href="#cb12-9" aria-hidden="true" tabindex="-1"></a>  c <span class="ot">&lt;-</span> everyone chordChanges</span>
<span id="cb12-10"><a href="#cb12-10" aria-hidden="true" tabindex="-1"></a>  m <span class="ot">&lt;-</span> harmonicVoices</span>
<span id="cb12-11"><a href="#cb12-11" aria-hidden="true" tabindex="-1"></a>  <span class="fu">pure</span> <span class="op">$</span> extend m <span class="op">&lt;&gt;</span> extend c <span class="op">&lt;&gt;</span> sink k</span></code></pre></div>
<p>which we can later <code>fmap</code> out into concrete pitches. The result is that we can completely isolate the following pieces:</p>
<ul>
<li>key changes</li>
<li>chord changes</li>
<li>how voices express the current harmony</li>
<li>the rhythms of all of the above</li>
</ul>
<p>and the result is guaranteed to compose in a way that the ear can interpret as music. Not necessarily <em>good music,</em> but undeniably as <em>music.</em></p>
<p>The type indices on <code>T</code> are purely for my book-keeping, and nothing requires them to be there. Which means we could also use the applicative structure to modulate over different sorts of harmony (eg, move from triads to seventh chords.)</p>
<h2 id="melody-still-an-open-question">Melody: Still an Open Question</h2>
<p>I haven’t quite gotten a feel for melody yet; I think it’s probably in <code>T '[7, 12]</code>, but it would be nice to be able to target chord tones as well. Please let me know in the comments if you have any insight here.</p>
<p>However, I have been thinking about contouring, which is the overall “shape” of a musical line. Does it go up, and peak in the middle, and then come down again? Or maybe it smoothly descends down.</p>
<p>We can use the discrete intervals intrinsic inside of <code>Voice</code>s to find “reasonable” times to sample them. In essence this assigns a <code>Time</code> to each segment:</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="ot">timed ::</span> <span class="dt">Music</span> v a <span class="ot">-&gt;</span> <span class="dt">Music</span> v (<span class="dt">Time</span>, a)</span></code></pre></div>
<p>and we can then use these times to then sample a function <code>Time -&gt; b</code>. This then allows us to apply contours (given as regular <code>Real -&gt; Real</code> functions) to arbitrary rhythms. I currently have this typed as</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="ot">contour ::</span> <span class="dt">Group</span> a <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> (<span class="dt">Real</span> <span class="ot">-&gt;</span> <span class="dt">Real</span>) <span class="ot">-&gt;</span> <span class="dt">Music</span> v () <span class="ot">-&gt;</span> <span class="dt">Music</span> v a</span></code></pre></div>
<p>where <code>a ~ T something</code>, and the outputted <code>Real</code>s get rounded to their nearest integer values. I’m not deeply in love with this type, but the rough idea is great—turn arbitrary real-valued functions into musical lines. This generalizes contouring, as well as scale runs.</p>
<h2 id="next-steps">Next Steps?</h2>
<p>I’m writing all of this up because I go back to work on Monday and life is going to get very busy soon. I’m afraid I won’t be able to finish all of this!</p>
<p>The types above I’m pretty certain are relatively close to perfect. They seem to capture everything I could possibly want, and nothing I don’t want. Assuming I’m right about that, they must make up the basis of musical composition.</p>
<p>The next step therefore is to build musical combinators on top. One particular combinator I’ve got my eye on is some sort of general <code>~&gt;</code> “get from here to there” operator:</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="ot">(~&gt;) ::</span> (<span class="dt">Semigroup</span> a, <span class="op">???</span>) <span class="ot">=&gt;</span> <span class="dt">Music</span> v a <span class="ot">-&gt;</span> <span class="dt">Music</span> v a <span class="ot">-&gt;</span> <span class="dt">Music</span> v a</span></code></pre></div>
<p>which I imagine would bridge a gap between the end of one piece of music with beginning of another. I think this would be roughly as easy as moving each voice linearly in <code>T</code> space from where it was to where it needs to be. This might need to be a ternary operation in order to also associate a rhythmic pattern to use for the bridge.</p>
<p>But I imagine <code>(~&gt;)</code> would be great for lots of dumb little musical things. Like when applied over the chord dimension, it would generate arpeggios. Over the scale dimension, it would generate runs. And it would make chromatic moves in the chroma dimension.</p>
<p>Choosing exactly what moves to make for <code>T</code>s consisting of components in multiple axes might just be some bespoke order, or could do something more intelligent. I think the right approach would be to steal <code>diagrams</code>’ idea of an <code>Envelope</code>, and attach some relevant metadata to each <code>Music</code>. We could then write <code>(~&gt;)</code> as a function of those envelopes, but I must admit I don’t quite know what this would look like.</p>
<p>As usual, I’d love any insight you have! Please leave it in the comments. Although I must admit I appreciate comments of the form “have you tried $X” much more than of the form “music is sublime and you’re an idiot for even trying this.”</p>
<p>Happy new year!</p>
<section class="footnotes" role="doc-endnotes">
<hr />
<ol>
<li id="fn1" role="doc-endnote"><p>Strictly speaking, the tile product can also do parallel composition, as well as sychronizing composition, but that’s not super important right now.<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
        ]]>
      </content>
    </entry>
    <entry>
      <title>Struggling Towards an Algebraic Theory of Music</title>
      <id>blog/algebraic-music/index.html</id>
      <link href='blog/algebraic-music/index.html'/>
      <published>2025-12-04T20:15:00Z</published>
      <updated>2025-12-04T20:15:00Z</updated>

      <content type="html" xml:base="https://reasonablypolymorphic.com">
        <![CDATA[
        <p>For the last few months, I’ve been trying to come up with a nice, denotational basis for what music <em>is.</em> But I’m running out of steam on the project, so I thought I’d write what I’ve figured out, and what I’ve tried but doesn’t work. Hopefully this will inspire someone to come tell me what I’m being stupid about and help get the whole process unstuck.</p>
<h2 id="what-music-is-not">What Music Is Not</h2>
<p>It’s tempting to gesticulate wildly, saying that music is merely a function from time to wave amplitudes, eg something of the form:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a>μ <span class="dt">Music</span> <span class="ot">=</span> <span class="dt">Time</span> <span class="ot">-&gt;</span> <span class="dt">Amplitude</span></span></code></pre></div>
<p>While I think it’s fair to say that this is indeed the underlying denotation of <em>sound,</em> this is clearly not the denotation of <em>music.</em> For example, we can transpose a song up a semitone without changing the speed—something that’s very challenging without a great deal of in the waveform representation. And we can play a musical phrase backwards, which is probably impossible in a waveform for any timbral envelope.</p>
<p>Since we have now two examples of “reasonable to want to do” with musical objects, which cannot be expressed in terms of a function <code>Time -&gt; Amplitude</code>, we must conceed that waveforms-over-time cannot be the denotation of music.</p>
<h2 id="what-music-might-be">What Music Might Be</h2>
<p>Music is obviously temporal, so keeping the “function from time” part seems relevant. But a function from time to what? As a first attempt:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Note</span> <span class="ot">=</span> <span class="dt">Note</span> <span class="dt">Pitch</span> <span class="dt">Timbre</span> <span class="dt">Volume</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>μ <span class="dt">Music</span> <span class="ot">=</span> <span class="dt">Time</span> <span class="ot">-&gt;</span> <span class="dt">Set</span> (<span class="dt">Duration</span>, <span class="dt">Note</span>)</span></code></pre></div>
<p>which, for a given time, returns a set of notes starting at that time, and how long they ought to be played for. An immediate improvement would be to parameterize the above over notes:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a>μ (<span class="dt">Music</span> a) <span class="ot">=</span> <span class="dt">Time</span> <span class="ot">-&gt;</span> <span class="dt">Set</span> (<span class="dt">Duration</span>, a)</span></code></pre></div>
<p>It’s tempting to try to eliminate more of the structure here with our parametricity, but I was unable to do so. In contrapuntal music, we will want to be able to express two notes starting at the same moment, but ending at different times.</p>
<p>One alluring path here could to write monophonic voices, and combine them together for polyphony:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>μ (<span class="dt">Voice</span> a) <span class="ot">=</span> <span class="co">{- something like -}</span> <span class="dt">Time</span> <span class="ot">-&gt;</span> (<span class="dt">Duration</span>, a)</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>μ (<span class="dt">Music</span> a) <span class="ot">=</span> <span class="dt">Time</span> <span class="ot">-&gt;</span> <span class="dt">Set</span> (<span class="dt">Voice</span> a)</span></code></pre></div>
<p>Such an encoding has many unfavorable traits. First, it just feels yucky. Why are there two layers of <code>Time</code>? Second, now I-as-a-composer need to make a choice of which voice I put each note in, despite the fact that this is merely an encoding quirk. So no, I don’t think this is a viable path forward.</p>
<p>So let’s return to our best contender:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>μ (<span class="dt">Music</span> a) <span class="ot">=</span> <span class="dt">Time</span> <span class="ot">-&gt;</span> <span class="dt">Set</span> (<span class="dt">Duration</span>, a)</span></code></pre></div>
<p>This definition is trivially a monoid, pointwise over the time structure:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a>μ (<span class="dt">Music</span> a <span class="op">&lt;&gt;</span> <span class="dt">Music</span> b) <span class="ot">=</span> <span class="dt">Music</span> (μ a <span class="op">&lt;&gt;</span> μ b)</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>μ <span class="fu">mempty</span> <span class="ot">=</span> <span class="dt">Music</span> <span class="fu">mempty</span></span></code></pre></div>
<p>If we think about abstract sets here, rather than <code>Data.Set.Set</code>, such an object is clearly a functor. There are many possible applicatives here, but the pointwise zipper seems most compelling to me. Pictorally:</p>
<pre><code>pure a
=
  |----- a ----forever...


liftA2 f
  |---- a ----|-- b --|
  |-- x --|---- y ----|
=
  |- fax -|fay|- fby -|</code></pre>
<p>Such an applicative structure is quite nice! It would allow us to “stamp” a rhythm on top of a pure representation of a melody.</p>
<p>However, the desirability of this instance is a point <em>against</em> <code>μ (Music a) = Time -&gt; Set (Duration, a)</code>, since by <a href="http://conal.net/papers/type-class-morphisms/">Conal Elliott’s typeclass morphism rule</a>, the meaning of the applicative here ought to be the applicative of the meaning. Nevertheless, any other applicative structure would be effecitvely useless, since it would require the notes on one side to begin at the same time as the notes on the other. To sketch:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- bad instance!</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>liftA2 f (<span class="dt">Music</span> a) (<span class="dt">Music</span> b) <span class="ot">=</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Music</span> (liftA2 (\(d1, m) (d2, n) <span class="ot">-&gt;</span> (d1 <span class="op">&lt;&gt;</span> d2, f m n)) a b)</span></code></pre></div>
<p>Good luck finding a musically meaningful <code>pure</code> for such a thing!</p>
<p>Ok, so let’s say we commit to the pointwise zippy instance as our applicative instance. Is there a corresponding monad? Such a thing would substitute notes with more music. My first idea of what to do with such a thing would be to replace chords with texture. For example, we could replace chords with broken chords, or with basslines that target the same notes.</p>
<p>Anyway, the answer is yes, there is such a monad. But it’s musically kinda troublesome. Assume we have the following function:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="ot">notes ::</span> <span class="dt">Music</span> a <span class="ot">-&gt;</span> [(<span class="dt">Maybe</span> <span class="dt">Interval</span>, a)]</span></code></pre></div>
<p>which will convert a <code>Music a</code> into its notes and an optional temporal interval (optional because <code>pure</code> goes on forever.) Then, we can write our bind as:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a>m <span class="op">&gt;&gt;=</span> f <span class="ot">=</span> <span class="fu">flip</span> <span class="fu">foldMap</span> (notes m) \<span class="kw">case</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>  (<span class="dt">Nothing</span>, a) <span class="ot">-&gt;</span> f a</span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>  (<span class="dt">Just</span> (start, duration), a) <span class="ot">-&gt;</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>    offset start <span class="op">$</span> _ duration <span class="op">$</span> f a</span></code></pre></div>
<p>where <code>offset</code> changes when a piece of music occurs. We are left with a hole of type:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Duration</span> <span class="ot">-&gt;</span> <span class="dt">Music</span> a <span class="ot">-&gt;</span> <span class="dt">Music</span> a</span></code></pre></div>
<p>whose semantics sure better be that it forces the given <code>Music</code> to fit in the alotted time. There are two reasonable candidates here:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="ot">scaleTo  ::</span> <span class="dt">Duration</span> <span class="ot">-&gt;</span> <span class="dt">Music</span> a <span class="ot">-&gt;</span> <span class="dt">Music</span> a</span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a><span class="fu">truncate</span><span class="ot"> ::</span> <span class="dt">Duration</span> <span class="ot">-&gt;</span> <span class="dt">Music</span> a <span class="ot">-&gt;</span> <span class="dt">Music</span> a</span></code></pre></div>
<p>where <code>scaleTo</code> changes the local interpretation of time such that the entire musical argument is played within the given duration, and <code>truncate</code> just takes the first <code>Duration</code>’s worth of time. Truncate is too obviously unhelpful here, since the <code>&gt;&gt;=</code> continuation doesn’t know how much time it’s been given, and thus most binds will drop almost all of their resulting music.</p>
<p>Therefore we will go with <code>scaleTo</code>. Which satisfies all of the algebraic (monad) laws, but results in some truly mystifying tunes. The problem here is that this is not an operation which respects musical meter. Each subsequent bind results in a correspondingly smaller share of the pie. Thus by using only bind and mconcat, it’s easy to get a bar full of quarter notes, followed by a bar of sixty-fourth notes, followed by two bars full of of 13-tuplets. If you want to get a steady rhythm out of the whole thing, you need a global view on how many binds deep you’re ever going to go, and you need to ensure locally that you only produce a small powers-of-two number of notes, or else you will accidentally introduce tuplets.</p>
<p>It’s a mess. But algebraically it’s fine.</p>
<h2 id="what-music-seems-like-it-should-be">What Music Seems Like It Should Be</h2>
<p>The above foray into monads seems tentatively promising for amateur would-be algorithmic composers (read: people like me.) But I have been reading <a href="https://www.goodreads.com/book/show/36288013-musical-composition">several</a> <a href="https://www.goodreads.com/book/show/890009.Twentieth_Century_Harmony">books</a> on musical composition lately, and my big takeaway from them is <em>just how damn contextual notes are.</em></p>
<p>So maybe this means we want more of a comonadic interface. One in which you can <code>extend</code> every note, by taking into account all of the notes in its local vicinity. This feels just as right as the monadic approach does, albeit in a completely different way. Being able to give a comonad instance for <code>Music</code> would require us to somehow reckon with having only a single <code>a</code> at any given time. Which appeals to my functional programmer soul, but again, I don’t know how to do it.</p>
<p>But imagine if we did have a comonadic instance. We could perform voice leading by inspecting what the next note was, and by futzing around with our pitch. We could do some sort of reharmonization by shifting notes around according to what else is happening.</p>
<p>But maybe all of this is just folly.</p>
<p>Music as it’s actually practiced doesn’t seem to have much of the functionaly-compositional properties we like—ie, that we can abstract and encapsulate. But music doesn’t appear to be like that! Instead, a happy melody takes a different character when played on major vs minor chords. Adding a dissonant interval can completely reconceptualize other notes.</p>
<p>It feels like a bit of a bummer to end like this, but I don’t really know where to go from here. I’ve worked something like six completely-different approaches over the last few months, and what’s documented here is the most promising bits and pieces. My next thought is that maybe music actually forms a <a href="https://reasonablypolymorphic.com/blog/review-sheafs/">sheaf</a>, which is to say that it is a global solution that respects many local constraints.</p>
<p>All of this research into music has given me much more thoughts about <em>music qua music</em> which I will try to articulate the next time I have an evening to myself. Until then.</p>
        ]]>
      </content>
    </entry>
    <entry>
      <title>Arrows to Arrows, Categories to Queries</title>
      <id>blog/arrows-to-arrows/index.html</id>
      <link href='blog/arrows-to-arrows/index.html'/>
      <published>2025-10-14T14:31:00Z</published>
      <updated>2025-10-14T14:31:00Z</updated>

      <content type="html" xml:base="https://reasonablypolymorphic.com">
        <![CDATA[
        <p>I’ve had a little time off of work as of late, and been spending it in characteristically unwise ways. In particular, I’ve written a <a href="https://github.com/isovector/catlang">little programming language that compiles to SQL</a>. I call it <em>catlang</em>. That’s not to say that I’ve written a new query language. It’s a programming language, whose compiler spits out one giant <code>SELECT</code> statement. When you run that query in postgres, you get the output of your program.</p>
<p>Why have I done this? Because I needed a funny compilation target to test out the actual features of the language, which is that its intermediary language is a bunch of abstract category theory nonsense. Which I’ll get to. But I’m sure you first want to see this bad boy in action.</p>
<p>Behold, the function that returns 100 regardless of what input you give it. But it does it with the equivalent of a while loop:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a>count <span class="op">:</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Int</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>count <span class="ot">=</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>  x <span class="ot">-&gt;</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>    loop x</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>      i <span class="ot">-&gt;</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>        n <span class="ot">&lt;-</span> join <span class="fu">id</span> <span class="fu">id</span> <span class="op">-&lt;</span> i</span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>        z <span class="ot">&lt;-</span> <span class="fu">abs</span> <span class="op">.</span> (<span class="op">-</span>) <span class="op">-&lt;</span> (n, <span class="dv">100</span>)</span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>        <span class="kw">case</span> z <span class="kw">of</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>          inl _ <span class="ot">-&gt;</span> inr <span class="op">.</span> (<span class="op">+</span>) <span class="op">-&lt;</span> (n, <span class="dv">1</span>)</span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>          inr _ <span class="ot">-&gt;</span> inl <span class="op">-&lt;</span> n</span></code></pre></div>
<p>If you’re familiar with <a href="/blog/arrowized-frp/">arrow notation</a>, you’ll notice the above looks kinda like one big <code>proc</code> block. This is not a coincidence (because nothing is a coincidence). I figured if I were to go through all of this work, we might as well get a working arrow desugarer out of the mix. But I digress; that’s a story for another time.</p>
<p>Anyway, what’s going on here is we have an arrow <code>count</code>, which takes a single argument <code>x</code>. We then loop, starting from the value of <code>x</code>. Inside the loop, we now have a new variable <code>i</code>, which we do some voodoo on to compute <code>n</code>—the current value of the loop variable. Then we subtract 100 from <code>n</code>, and take the absolute value. The <code>abs</code> function here is a bit odd; it returns <code>Left (abs x)</code> if the input was negative, and <code>Right x</code> otherwise. Then we branch on the output of <code>abs</code>, where <code>Left</code> and <code>Right</code> have been renamed <code>inl</code> and <code>inr</code> respectively. If <code>n - 100</code> was less than zero, we find ourselves in the <code>inl</code> case, where we add 1 to <code>n</code> and wrap the whole thing in <code>inr</code>—which the loop interprets as “loop again with this new value.” Otherwise, <code>n - 100</code> was non-negative, and so we can return <code>n</code> directly.</p>
<p>Is it roundabout? You bet! The obtuseness here is not directly a feature, I was just looking for conceptually simple things I could do which would be easy to desugar into category-theoretical stuff. Which brings us to the intermediary language. After desugaring the source syntax for <code>count</code> above, we’re left with this IL representation:</p>
<pre><code>  id △ id
⨟ cochoice
    ( undist
    ⨟   ( (prj₁ ⨟ id ▽ id) △ id
          ⨟   ( prj₁ △ 100
              ⨟ (-)
              ⨟ abs
              )
            △ id
          ⨟ prj₁ △ id
          ⨟ dist
          ⨟   ( (prj₂ ⨟ prj₂ ⨟ prj₁) △ 1
              ⨟ (+)
              ⨟ inr
              )
            ▽ ( prj₂
              ⨟ prj₂
              ⨟ prj₁
              ⨟ inl
              )
        )
      △ prj₂
    ⨟ dist
    )
⨟ prj₁</code></pre>
<p>We’ll discuss all of this momentarily, but for now, just let your eyes glaze over the pretty unicode.</p>
<p>The underlying idea here is that each of these remaining symbols has very simple and specific algebraic semantics. For example, <code>A ⨟ B</code> means “do <code>A</code> and pipe the result into <code>B</code>.” By giving a transformation from this categorical IL into other domains, it becomes trivial to compile catlang to all sorts of weird compilation targets. Like SQL.</p>
<p>You’re probably wondering what the generated SQL looks like. Take a peek if you dare.</p>
<details>
<summary>
Ungodly Compiled SQL
</summary>
<div class="sourceCode" id="cb3"><pre class="sourceCode sql"><code class="sourceCode sql"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">SELECT</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>f0 <span class="kw">AS</span> f0</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="kw">FROM</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>(<span class="kw">SELECT</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a> f0 <span class="kw">AS</span> f0, f1 <span class="kw">AS</span> f1</span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a> <span class="kw">FROM</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a> (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>  <span class="kw">FROM</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a>  (<span class="kw">WITH</span> t0 <span class="kw">AS</span></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a>   (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a>    <span class="kw">FROM</span></span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a>    (<span class="kw">WITH</span> RECURSIVE recursion <span class="kw">AS</span></span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a>     (<span class="kw">SELECT</span></span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a>      clock_timestamp() <span class="kw">as</span> step</span>
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true" tabindex="-1"></a>      , <span class="op">*</span></span>
<span id="cb3-16"><a href="#cb3-16" aria-hidden="true" tabindex="-1"></a>      <span class="kw">FROM</span></span>
<span id="cb3-17"><a href="#cb3-17" aria-hidden="true" tabindex="-1"></a>      (<span class="kw">WITH</span> t1 <span class="kw">AS</span></span>
<span id="cb3-18"><a href="#cb3-18" aria-hidden="true" tabindex="-1"></a>       (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-19"><a href="#cb3-19" aria-hidden="true" tabindex="-1"></a>        <span class="kw">FROM</span></span>
<span id="cb3-20"><a href="#cb3-20" aria-hidden="true" tabindex="-1"></a>        (<span class="kw">SELECT</span></span>
<span id="cb3-21"><a href="#cb3-21" aria-hidden="true" tabindex="-1"></a>         f0 <span class="kw">AS</span> f0, f1 <span class="kw">AS</span> f1, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f2, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f3</span>
<span id="cb3-22"><a href="#cb3-22" aria-hidden="true" tabindex="-1"></a>         <span class="kw">FROM</span></span>
<span id="cb3-23"><a href="#cb3-23" aria-hidden="true" tabindex="-1"></a>         (<span class="kw">WITH</span> t2 <span class="kw">AS</span></span>
<span id="cb3-24"><a href="#cb3-24" aria-hidden="true" tabindex="-1"></a>          (<span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> (<span class="kw">SELECT</span> <span class="dv">0</span> <span class="kw">as</span> f0) <span class="kw">AS</span> _)</span>
<span id="cb3-25"><a href="#cb3-25" aria-hidden="true" tabindex="-1"></a>          <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-26"><a href="#cb3-26" aria-hidden="true" tabindex="-1"></a>          <span class="kw">FROM</span></span>
<span id="cb3-27"><a href="#cb3-27" aria-hidden="true" tabindex="-1"></a>          (<span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> (<span class="kw">SELECT</span> f0 <span class="kw">AS</span> f0 <span class="kw">FROM</span> t2 <span class="kw">AS</span> _) <span class="kw">AS</span> _</span>
<span id="cb3-28"><a href="#cb3-28" aria-hidden="true" tabindex="-1"></a>           <span class="kw">CROSS</span> <span class="kw">JOIN</span></span>
<span id="cb3-29"><a href="#cb3-29" aria-hidden="true" tabindex="-1"></a>           (<span class="kw">SELECT</span> f0 <span class="kw">AS</span> f1 <span class="kw">FROM</span> t2 <span class="kw">AS</span> _))</span>
<span id="cb3-30"><a href="#cb3-30" aria-hidden="true" tabindex="-1"></a>          <span class="kw">AS</span> _)</span>
<span id="cb3-31"><a href="#cb3-31" aria-hidden="true" tabindex="-1"></a>         <span class="kw">AS</span> _)</span>
<span id="cb3-32"><a href="#cb3-32" aria-hidden="true" tabindex="-1"></a>        <span class="kw">AS</span> _)</span>
<span id="cb3-33"><a href="#cb3-33" aria-hidden="true" tabindex="-1"></a>       <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-34"><a href="#cb3-34" aria-hidden="true" tabindex="-1"></a>       <span class="kw">FROM</span></span>
<span id="cb3-35"><a href="#cb3-35" aria-hidden="true" tabindex="-1"></a>       (<span class="kw">WITH</span> t3 <span class="kw">AS</span></span>
<span id="cb3-36"><a href="#cb3-36" aria-hidden="true" tabindex="-1"></a>        (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-37"><a href="#cb3-37" aria-hidden="true" tabindex="-1"></a>         <span class="kw">FROM</span></span>
<span id="cb3-38"><a href="#cb3-38" aria-hidden="true" tabindex="-1"></a>         (<span class="co">-- undist</span></span>
<span id="cb3-39"><a href="#cb3-39" aria-hidden="true" tabindex="-1"></a>          <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-40"><a href="#cb3-40" aria-hidden="true" tabindex="-1"></a>          <span class="kw">FROM</span></span>
<span id="cb3-41"><a href="#cb3-41" aria-hidden="true" tabindex="-1"></a>          (<span class="kw">SELECT</span></span>
<span id="cb3-42"><a href="#cb3-42" aria-hidden="true" tabindex="-1"></a>           f0 <span class="kw">AS</span> f0, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f1, f1 <span class="kw">AS</span> f2</span>
<span id="cb3-43"><a href="#cb3-43" aria-hidden="true" tabindex="-1"></a>           <span class="kw">FROM</span></span>
<span id="cb3-44"><a href="#cb3-44" aria-hidden="true" tabindex="-1"></a>           (<span class="co">-- undist1</span></span>
<span id="cb3-45"><a href="#cb3-45" aria-hidden="true" tabindex="-1"></a>            <span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> t1 <span class="kw">AS</span> _ <span class="kw">WHERE</span> <span class="ot">&quot;f0&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)</span>
<span id="cb3-46"><a href="#cb3-46" aria-hidden="true" tabindex="-1"></a>           <span class="kw">AS</span> _)</span>
<span id="cb3-47"><a href="#cb3-47" aria-hidden="true" tabindex="-1"></a>          <span class="kw">AS</span> _</span>
<span id="cb3-48"><a href="#cb3-48" aria-hidden="true" tabindex="-1"></a>          <span class="kw">UNION</span></span>
<span id="cb3-49"><a href="#cb3-49" aria-hidden="true" tabindex="-1"></a>          <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-50"><a href="#cb3-50" aria-hidden="true" tabindex="-1"></a>          <span class="kw">FROM</span></span>
<span id="cb3-51"><a href="#cb3-51" aria-hidden="true" tabindex="-1"></a>          (<span class="kw">SELECT</span></span>
<span id="cb3-52"><a href="#cb3-52" aria-hidden="true" tabindex="-1"></a>           <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f0, f2 <span class="kw">AS</span> f1, f3 <span class="kw">AS</span> f2</span>
<span id="cb3-53"><a href="#cb3-53" aria-hidden="true" tabindex="-1"></a>           <span class="kw">FROM</span></span>
<span id="cb3-54"><a href="#cb3-54" aria-hidden="true" tabindex="-1"></a>           (<span class="co">-- dist2</span></span>
<span id="cb3-55"><a href="#cb3-55" aria-hidden="true" tabindex="-1"></a>            <span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> t1 <span class="kw">AS</span> _ <span class="kw">WHERE</span> <span class="ot">&quot;f2&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)</span>
<span id="cb3-56"><a href="#cb3-56" aria-hidden="true" tabindex="-1"></a>           <span class="kw">AS</span> _)</span>
<span id="cb3-57"><a href="#cb3-57" aria-hidden="true" tabindex="-1"></a>          <span class="kw">AS</span> _)</span>
<span id="cb3-58"><a href="#cb3-58" aria-hidden="true" tabindex="-1"></a>         <span class="kw">AS</span> _)</span>
<span id="cb3-59"><a href="#cb3-59" aria-hidden="true" tabindex="-1"></a>        <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-60"><a href="#cb3-60" aria-hidden="true" tabindex="-1"></a>        <span class="kw">FROM</span></span>
<span id="cb3-61"><a href="#cb3-61" aria-hidden="true" tabindex="-1"></a>        (<span class="kw">WITH</span> t4 <span class="kw">AS</span></span>
<span id="cb3-62"><a href="#cb3-62" aria-hidden="true" tabindex="-1"></a>         (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-63"><a href="#cb3-63" aria-hidden="true" tabindex="-1"></a>          <span class="kw">FROM</span></span>
<span id="cb3-64"><a href="#cb3-64" aria-hidden="true" tabindex="-1"></a>          (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-65"><a href="#cb3-65" aria-hidden="true" tabindex="-1"></a>           <span class="kw">FROM</span></span>
<span id="cb3-66"><a href="#cb3-66" aria-hidden="true" tabindex="-1"></a>           (<span class="kw">SELECT</span></span>
<span id="cb3-67"><a href="#cb3-67" aria-hidden="true" tabindex="-1"></a>            f0 <span class="kw">AS</span> f0, f1 <span class="kw">AS</span> f1</span>
<span id="cb3-68"><a href="#cb3-68" aria-hidden="true" tabindex="-1"></a>            <span class="kw">FROM</span></span>
<span id="cb3-69"><a href="#cb3-69" aria-hidden="true" tabindex="-1"></a>            (<span class="kw">WITH</span> t5 <span class="kw">AS</span></span>
<span id="cb3-70"><a href="#cb3-70" aria-hidden="true" tabindex="-1"></a>             (<span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> t3 <span class="kw">AS</span> _)</span>
<span id="cb3-71"><a href="#cb3-71" aria-hidden="true" tabindex="-1"></a>             <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-72"><a href="#cb3-72" aria-hidden="true" tabindex="-1"></a>             <span class="kw">FROM</span></span>
<span id="cb3-73"><a href="#cb3-73" aria-hidden="true" tabindex="-1"></a>             (<span class="kw">WITH</span> t6 <span class="kw">AS</span></span>
<span id="cb3-74"><a href="#cb3-74" aria-hidden="true" tabindex="-1"></a>              (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-75"><a href="#cb3-75" aria-hidden="true" tabindex="-1"></a>               <span class="kw">FROM</span></span>
<span id="cb3-76"><a href="#cb3-76" aria-hidden="true" tabindex="-1"></a>               (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-77"><a href="#cb3-77" aria-hidden="true" tabindex="-1"></a>                <span class="kw">FROM</span></span>
<span id="cb3-78"><a href="#cb3-78" aria-hidden="true" tabindex="-1"></a>                (<span class="kw">SELECT</span></span>
<span id="cb3-79"><a href="#cb3-79" aria-hidden="true" tabindex="-1"></a>                 f0 <span class="kw">AS</span> f0</span>
<span id="cb3-80"><a href="#cb3-80" aria-hidden="true" tabindex="-1"></a>                 <span class="kw">FROM</span></span>
<span id="cb3-81"><a href="#cb3-81" aria-hidden="true" tabindex="-1"></a>                 (<span class="kw">WITH</span> t7 <span class="kw">AS</span></span>
<span id="cb3-82"><a href="#cb3-82" aria-hidden="true" tabindex="-1"></a>                  (<span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> (<span class="kw">SELECT</span> f0 <span class="kw">AS</span> f0, f1 <span class="kw">AS</span> f1 <span class="kw">FROM</span> t5 <span class="kw">AS</span> _) <span class="kw">AS</span> _)</span>
<span id="cb3-83"><a href="#cb3-83" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-84"><a href="#cb3-84" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">FROM</span></span>
<span id="cb3-85"><a href="#cb3-85" aria-hidden="true" tabindex="-1"></a>                  (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-86"><a href="#cb3-86" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">FROM</span></span>
<span id="cb3-87"><a href="#cb3-87" aria-hidden="true" tabindex="-1"></a>                   (<span class="kw">SELECT</span></span>
<span id="cb3-88"><a href="#cb3-88" aria-hidden="true" tabindex="-1"></a>                    f0 <span class="kw">AS</span> f0</span>
<span id="cb3-89"><a href="#cb3-89" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">FROM</span></span>
<span id="cb3-90"><a href="#cb3-90" aria-hidden="true" tabindex="-1"></a>                    (<span class="co">-- join1</span></span>
<span id="cb3-91"><a href="#cb3-91" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> t7 <span class="kw">AS</span> _ <span class="kw">WHERE</span> <span class="ot">&quot;f0&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)</span>
<span id="cb3-92"><a href="#cb3-92" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">AS</span> _)</span>
<span id="cb3-93"><a href="#cb3-93" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">AS</span> _</span>
<span id="cb3-94"><a href="#cb3-94" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">UNION</span></span>
<span id="cb3-95"><a href="#cb3-95" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-96"><a href="#cb3-96" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">FROM</span></span>
<span id="cb3-97"><a href="#cb3-97" aria-hidden="true" tabindex="-1"></a>                   (<span class="kw">SELECT</span></span>
<span id="cb3-98"><a href="#cb3-98" aria-hidden="true" tabindex="-1"></a>                    f1 <span class="kw">AS</span> f0</span>
<span id="cb3-99"><a href="#cb3-99" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">FROM</span></span>
<span id="cb3-100"><a href="#cb3-100" aria-hidden="true" tabindex="-1"></a>                    (<span class="co">-- join2</span></span>
<span id="cb3-101"><a href="#cb3-101" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> t7 <span class="kw">AS</span> _ <span class="kw">WHERE</span> <span class="ot">&quot;f1&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)</span>
<span id="cb3-102"><a href="#cb3-102" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">AS</span> _)</span>
<span id="cb3-103"><a href="#cb3-103" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">AS</span> _)</span>
<span id="cb3-104"><a href="#cb3-104" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">AS</span> _)</span>
<span id="cb3-105"><a href="#cb3-105" aria-hidden="true" tabindex="-1"></a>                 <span class="kw">AS</span> _)</span>
<span id="cb3-106"><a href="#cb3-106" aria-hidden="true" tabindex="-1"></a>                <span class="kw">AS</span> _</span>
<span id="cb3-107"><a href="#cb3-107" aria-hidden="true" tabindex="-1"></a>                <span class="kw">CROSS</span> <span class="kw">JOIN</span></span>
<span id="cb3-108"><a href="#cb3-108" aria-hidden="true" tabindex="-1"></a>                (<span class="kw">SELECT</span> f0 <span class="kw">AS</span> f1, f1 <span class="kw">AS</span> f2, f2 <span class="kw">AS</span> f3 <span class="kw">FROM</span> t5 <span class="kw">AS</span> _))</span>
<span id="cb3-109"><a href="#cb3-109" aria-hidden="true" tabindex="-1"></a>               <span class="kw">AS</span> _)</span>
<span id="cb3-110"><a href="#cb3-110" aria-hidden="true" tabindex="-1"></a>              <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-111"><a href="#cb3-111" aria-hidden="true" tabindex="-1"></a>              <span class="kw">FROM</span></span>
<span id="cb3-112"><a href="#cb3-112" aria-hidden="true" tabindex="-1"></a>              (<span class="kw">WITH</span> t8 <span class="kw">AS</span></span>
<span id="cb3-113"><a href="#cb3-113" aria-hidden="true" tabindex="-1"></a>               (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-114"><a href="#cb3-114" aria-hidden="true" tabindex="-1"></a>                <span class="kw">FROM</span></span>
<span id="cb3-115"><a href="#cb3-115" aria-hidden="true" tabindex="-1"></a>                (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-116"><a href="#cb3-116" aria-hidden="true" tabindex="-1"></a>                 <span class="kw">FROM</span></span>
<span id="cb3-117"><a href="#cb3-117" aria-hidden="true" tabindex="-1"></a>                 (<span class="kw">SELECT</span></span>
<span id="cb3-118"><a href="#cb3-118" aria-hidden="true" tabindex="-1"></a>                  f0 <span class="kw">AS</span> f0, f1 <span class="kw">AS</span> f1</span>
<span id="cb3-119"><a href="#cb3-119" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">FROM</span></span>
<span id="cb3-120"><a href="#cb3-120" aria-hidden="true" tabindex="-1"></a>                  (<span class="kw">WITH</span> t9 <span class="kw">AS</span></span>
<span id="cb3-121"><a href="#cb3-121" aria-hidden="true" tabindex="-1"></a>                   (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-122"><a href="#cb3-122" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">FROM</span></span>
<span id="cb3-123"><a href="#cb3-123" aria-hidden="true" tabindex="-1"></a>                    (<span class="kw">SELECT</span></span>
<span id="cb3-124"><a href="#cb3-124" aria-hidden="true" tabindex="-1"></a>                     f0 <span class="op">-</span> f1 <span class="kw">AS</span> f0</span>
<span id="cb3-125"><a href="#cb3-125" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">FROM</span></span>
<span id="cb3-126"><a href="#cb3-126" aria-hidden="true" tabindex="-1"></a>                     (<span class="kw">WITH</span> t10 <span class="kw">AS</span></span>
<span id="cb3-127"><a href="#cb3-127" aria-hidden="true" tabindex="-1"></a>                      (<span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> t6 <span class="kw">AS</span> _)</span>
<span id="cb3-128"><a href="#cb3-128" aria-hidden="true" tabindex="-1"></a>                      <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-129"><a href="#cb3-129" aria-hidden="true" tabindex="-1"></a>                      <span class="kw">FROM</span></span>
<span id="cb3-130"><a href="#cb3-130" aria-hidden="true" tabindex="-1"></a>                      (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-131"><a href="#cb3-131" aria-hidden="true" tabindex="-1"></a>                       <span class="kw">FROM</span></span>
<span id="cb3-132"><a href="#cb3-132" aria-hidden="true" tabindex="-1"></a>                       (<span class="kw">SELECT</span> f0 <span class="kw">AS</span> f0 <span class="kw">FROM</span> (<span class="kw">SELECT</span> f0 <span class="kw">AS</span> f0 <span class="kw">FROM</span> t10 <span class="kw">AS</span> _) <span class="kw">AS</span> _)</span>
<span id="cb3-133"><a href="#cb3-133" aria-hidden="true" tabindex="-1"></a>                       <span class="kw">AS</span> _</span>
<span id="cb3-134"><a href="#cb3-134" aria-hidden="true" tabindex="-1"></a>                       <span class="kw">CROSS</span> <span class="kw">JOIN</span></span>
<span id="cb3-135"><a href="#cb3-135" aria-hidden="true" tabindex="-1"></a>                       (<span class="kw">SELECT</span> f0 <span class="kw">AS</span> f1 <span class="kw">FROM</span> (<span class="kw">SELECT</span> <span class="dv">100</span> <span class="kw">as</span> f0 <span class="kw">FROM</span> t10 <span class="kw">AS</span> _) <span class="kw">AS</span> _))</span>
<span id="cb3-136"><a href="#cb3-136" aria-hidden="true" tabindex="-1"></a>                      <span class="kw">AS</span> _)</span>
<span id="cb3-137"><a href="#cb3-137" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">AS</span> _)</span>
<span id="cb3-138"><a href="#cb3-138" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">AS</span> _)</span>
<span id="cb3-139"><a href="#cb3-139" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-140"><a href="#cb3-140" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">FROM</span></span>
<span id="cb3-141"><a href="#cb3-141" aria-hidden="true" tabindex="-1"></a>                   (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-142"><a href="#cb3-142" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">FROM</span></span>
<span id="cb3-143"><a href="#cb3-143" aria-hidden="true" tabindex="-1"></a>                    (<span class="kw">SELECT</span></span>
<span id="cb3-144"><a href="#cb3-144" aria-hidden="true" tabindex="-1"></a>                     <span class="fu">abs</span>(f0) <span class="kw">as</span> f0, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">as</span> f1</span>
<span id="cb3-145"><a href="#cb3-145" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">FROM</span></span>
<span id="cb3-146"><a href="#cb3-146" aria-hidden="true" tabindex="-1"></a>                     t9</span>
<span id="cb3-147"><a href="#cb3-147" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">AS</span> _</span>
<span id="cb3-148"><a href="#cb3-148" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">WHERE</span></span>
<span id="cb3-149"><a href="#cb3-149" aria-hidden="true" tabindex="-1"></a>                     f0 <span class="op">&lt;</span> <span class="dv">0</span>)</span>
<span id="cb3-150"><a href="#cb3-150" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">AS</span> _</span>
<span id="cb3-151"><a href="#cb3-151" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">UNION</span></span>
<span id="cb3-152"><a href="#cb3-152" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-153"><a href="#cb3-153" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">FROM</span></span>
<span id="cb3-154"><a href="#cb3-154" aria-hidden="true" tabindex="-1"></a>                    (<span class="kw">SELECT</span> <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">as</span> f0, f0 <span class="kw">as</span> f1 <span class="kw">FROM</span> t9 <span class="kw">AS</span> _ <span class="kw">WHERE</span> f0 <span class="op">&gt;=</span> <span class="dv">0</span>)</span>
<span id="cb3-155"><a href="#cb3-155" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">AS</span> _)</span>
<span id="cb3-156"><a href="#cb3-156" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">AS</span> _)</span>
<span id="cb3-157"><a href="#cb3-157" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">AS</span> _)</span>
<span id="cb3-158"><a href="#cb3-158" aria-hidden="true" tabindex="-1"></a>                 <span class="kw">AS</span> _</span>
<span id="cb3-159"><a href="#cb3-159" aria-hidden="true" tabindex="-1"></a>                 <span class="kw">CROSS</span> <span class="kw">JOIN</span></span>
<span id="cb3-160"><a href="#cb3-160" aria-hidden="true" tabindex="-1"></a>                 (<span class="kw">SELECT</span> f0 <span class="kw">AS</span> f2, f1 <span class="kw">AS</span> f3, f2 <span class="kw">AS</span> f4, f3 <span class="kw">AS</span> f5 <span class="kw">FROM</span> t6 <span class="kw">AS</span> _))</span>
<span id="cb3-161"><a href="#cb3-161" aria-hidden="true" tabindex="-1"></a>                <span class="kw">AS</span> _)</span>
<span id="cb3-162"><a href="#cb3-162" aria-hidden="true" tabindex="-1"></a>               <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-163"><a href="#cb3-163" aria-hidden="true" tabindex="-1"></a>               <span class="kw">FROM</span></span>
<span id="cb3-164"><a href="#cb3-164" aria-hidden="true" tabindex="-1"></a>               (<span class="kw">WITH</span> t11 <span class="kw">AS</span></span>
<span id="cb3-165"><a href="#cb3-165" aria-hidden="true" tabindex="-1"></a>                (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-166"><a href="#cb3-166" aria-hidden="true" tabindex="-1"></a>                 <span class="kw">FROM</span></span>
<span id="cb3-167"><a href="#cb3-167" aria-hidden="true" tabindex="-1"></a>                 (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-168"><a href="#cb3-168" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">FROM</span></span>
<span id="cb3-169"><a href="#cb3-169" aria-hidden="true" tabindex="-1"></a>                  (<span class="kw">SELECT</span></span>
<span id="cb3-170"><a href="#cb3-170" aria-hidden="true" tabindex="-1"></a>                   f0 <span class="kw">AS</span> f0, f1 <span class="kw">AS</span> f1</span>
<span id="cb3-171"><a href="#cb3-171" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">FROM</span></span>
<span id="cb3-172"><a href="#cb3-172" aria-hidden="true" tabindex="-1"></a>                   (<span class="kw">SELECT</span> f0 <span class="kw">AS</span> f0, f1 <span class="kw">AS</span> f1 <span class="kw">FROM</span> t8 <span class="kw">AS</span> _)</span>
<span id="cb3-173"><a href="#cb3-173" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">AS</span> _)</span>
<span id="cb3-174"><a href="#cb3-174" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">AS</span> _</span>
<span id="cb3-175"><a href="#cb3-175" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">CROSS</span> <span class="kw">JOIN</span></span>
<span id="cb3-176"><a href="#cb3-176" aria-hidden="true" tabindex="-1"></a>                  (<span class="kw">SELECT</span></span>
<span id="cb3-177"><a href="#cb3-177" aria-hidden="true" tabindex="-1"></a>                   f0 <span class="kw">AS</span> f2, f1 <span class="kw">AS</span> f3, f2 <span class="kw">AS</span> f4, f3 <span class="kw">AS</span> f5, f4 <span class="kw">AS</span> f6, f5 <span class="kw">AS</span> f7</span>
<span id="cb3-178"><a href="#cb3-178" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">FROM</span></span>
<span id="cb3-179"><a href="#cb3-179" aria-hidden="true" tabindex="-1"></a>                   t8</span>
<span id="cb3-180"><a href="#cb3-180" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">AS</span> _))</span>
<span id="cb3-181"><a href="#cb3-181" aria-hidden="true" tabindex="-1"></a>                 <span class="kw">AS</span> _)</span>
<span id="cb3-182"><a href="#cb3-182" aria-hidden="true" tabindex="-1"></a>                <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-183"><a href="#cb3-183" aria-hidden="true" tabindex="-1"></a>                <span class="kw">FROM</span></span>
<span id="cb3-184"><a href="#cb3-184" aria-hidden="true" tabindex="-1"></a>                (<span class="kw">WITH</span> t12 <span class="kw">AS</span></span>
<span id="cb3-185"><a href="#cb3-185" aria-hidden="true" tabindex="-1"></a>                 (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-186"><a href="#cb3-186" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">FROM</span></span>
<span id="cb3-187"><a href="#cb3-187" aria-hidden="true" tabindex="-1"></a>                  (<span class="co">-- dist</span></span>
<span id="cb3-188"><a href="#cb3-188" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-189"><a href="#cb3-189" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">FROM</span></span>
<span id="cb3-190"><a href="#cb3-190" aria-hidden="true" tabindex="-1"></a>                   (<span class="kw">SELECT</span></span>
<span id="cb3-191"><a href="#cb3-191" aria-hidden="true" tabindex="-1"></a>                    f0 <span class="kw">AS</span> f0, f2 <span class="kw">AS</span> f1, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f10, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f11, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f12, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f13, f3 <span class="kw">AS</span> f2, f4 <span class="kw">AS</span> f3, f5 <span class="kw">AS</span> f4, f6 <span class="kw">AS</span> f5, f7 <span class="kw">AS</span> f6, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f7, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f8, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f9</span>
<span id="cb3-192"><a href="#cb3-192" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">FROM</span></span>
<span id="cb3-193"><a href="#cb3-193" aria-hidden="true" tabindex="-1"></a>                    (<span class="co">-- dist1</span></span>
<span id="cb3-194"><a href="#cb3-194" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> t11 <span class="kw">AS</span> _ <span class="kw">WHERE</span> <span class="ot">&quot;f0&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)</span>
<span id="cb3-195"><a href="#cb3-195" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">AS</span> _)</span>
<span id="cb3-196"><a href="#cb3-196" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">AS</span> _</span>
<span id="cb3-197"><a href="#cb3-197" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">UNION</span></span>
<span id="cb3-198"><a href="#cb3-198" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-199"><a href="#cb3-199" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">FROM</span></span>
<span id="cb3-200"><a href="#cb3-200" aria-hidden="true" tabindex="-1"></a>                   (<span class="kw">SELECT</span></span>
<span id="cb3-201"><a href="#cb3-201" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f0, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f1, f4 <span class="kw">AS</span> f10, f5 <span class="kw">AS</span> f11, f6 <span class="kw">AS</span> f12, f7 <span class="kw">AS</span> f13, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f2, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f3, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f4, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f5, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f6, f1 <span class="kw">AS</span> f7, f2 <span class="kw">AS</span> f8, f3 <span class="kw">AS</span> f9</span>
<span id="cb3-202"><a href="#cb3-202" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">FROM</span></span>
<span id="cb3-203"><a href="#cb3-203" aria-hidden="true" tabindex="-1"></a>                    (<span class="co">-- dist2</span></span>
<span id="cb3-204"><a href="#cb3-204" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> t11 <span class="kw">AS</span> _ <span class="kw">WHERE</span> <span class="ot">&quot;f1&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)</span>
<span id="cb3-205"><a href="#cb3-205" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">AS</span> _)</span>
<span id="cb3-206"><a href="#cb3-206" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">AS</span> _)</span>
<span id="cb3-207"><a href="#cb3-207" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">AS</span> _)</span>
<span id="cb3-208"><a href="#cb3-208" aria-hidden="true" tabindex="-1"></a>                 <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-209"><a href="#cb3-209" aria-hidden="true" tabindex="-1"></a>                 <span class="kw">FROM</span></span>
<span id="cb3-210"><a href="#cb3-210" aria-hidden="true" tabindex="-1"></a>                 (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-211"><a href="#cb3-211" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">FROM</span></span>
<span id="cb3-212"><a href="#cb3-212" aria-hidden="true" tabindex="-1"></a>                  (<span class="kw">SELECT</span></span>
<span id="cb3-213"><a href="#cb3-213" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f0, f0 <span class="kw">AS</span> f1</span>
<span id="cb3-214"><a href="#cb3-214" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">FROM</span></span>
<span id="cb3-215"><a href="#cb3-215" aria-hidden="true" tabindex="-1"></a>                   (<span class="kw">SELECT</span></span>
<span id="cb3-216"><a href="#cb3-216" aria-hidden="true" tabindex="-1"></a>                    f0 <span class="op">+</span> f1 <span class="kw">AS</span> f0</span>
<span id="cb3-217"><a href="#cb3-217" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">FROM</span></span>
<span id="cb3-218"><a href="#cb3-218" aria-hidden="true" tabindex="-1"></a>                    (<span class="kw">WITH</span> t13 <span class="kw">AS</span></span>
<span id="cb3-219"><a href="#cb3-219" aria-hidden="true" tabindex="-1"></a>                     (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-220"><a href="#cb3-220" aria-hidden="true" tabindex="-1"></a>                      <span class="kw">FROM</span></span>
<span id="cb3-221"><a href="#cb3-221" aria-hidden="true" tabindex="-1"></a>                      (<span class="kw">SELECT</span></span>
<span id="cb3-222"><a href="#cb3-222" aria-hidden="true" tabindex="-1"></a>                       f0 <span class="kw">AS</span> f0, f1 <span class="kw">AS</span> f1, f2 <span class="kw">AS</span> f2, f3 <span class="kw">AS</span> f3, f4 <span class="kw">AS</span> f4, f5 <span class="kw">AS</span> f5, f6 <span class="kw">AS</span> f6</span>
<span id="cb3-223"><a href="#cb3-223" aria-hidden="true" tabindex="-1"></a>                       <span class="kw">FROM</span></span>
<span id="cb3-224"><a href="#cb3-224" aria-hidden="true" tabindex="-1"></a>                       (<span class="co">-- join1</span></span>
<span id="cb3-225"><a href="#cb3-225" aria-hidden="true" tabindex="-1"></a>                        <span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> t12 <span class="kw">AS</span> _</span>
<span id="cb3-226"><a href="#cb3-226" aria-hidden="true" tabindex="-1"></a>                        <span class="kw">WHERE</span></span>
<span id="cb3-227"><a href="#cb3-227" aria-hidden="true" tabindex="-1"></a>                        (<span class="ot">&quot;f0&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>) <span class="kw">AND</span> (((<span class="ot">&quot;f1&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>) <span class="kw">OR</span> (<span class="ot">&quot;f2&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)) <span class="kw">AND</span> ((<span class="ot">&quot;f3&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>) <span class="kw">AND</span> (((<span class="ot">&quot;f4&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>) <span class="kw">OR</span> (<span class="ot">&quot;f5&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)) <span class="kw">AND</span> (<span class="ot">&quot;f6&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)))))</span>
<span id="cb3-228"><a href="#cb3-228" aria-hidden="true" tabindex="-1"></a>                       <span class="kw">AS</span> _)</span>
<span id="cb3-229"><a href="#cb3-229" aria-hidden="true" tabindex="-1"></a>                      <span class="kw">AS</span> _)</span>
<span id="cb3-230"><a href="#cb3-230" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-231"><a href="#cb3-231" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">FROM</span></span>
<span id="cb3-232"><a href="#cb3-232" aria-hidden="true" tabindex="-1"></a>                     (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-233"><a href="#cb3-233" aria-hidden="true" tabindex="-1"></a>                      <span class="kw">FROM</span></span>
<span id="cb3-234"><a href="#cb3-234" aria-hidden="true" tabindex="-1"></a>                      (<span class="kw">SELECT</span></span>
<span id="cb3-235"><a href="#cb3-235" aria-hidden="true" tabindex="-1"></a>                       f0 <span class="kw">AS</span> f0</span>
<span id="cb3-236"><a href="#cb3-236" aria-hidden="true" tabindex="-1"></a>                       <span class="kw">FROM</span></span>
<span id="cb3-237"><a href="#cb3-237" aria-hidden="true" tabindex="-1"></a>                       (<span class="kw">SELECT</span></span>
<span id="cb3-238"><a href="#cb3-238" aria-hidden="true" tabindex="-1"></a>                        f0 <span class="kw">AS</span> f0</span>
<span id="cb3-239"><a href="#cb3-239" aria-hidden="true" tabindex="-1"></a>                        <span class="kw">FROM</span></span>
<span id="cb3-240"><a href="#cb3-240" aria-hidden="true" tabindex="-1"></a>                        (<span class="kw">SELECT</span></span>
<span id="cb3-241"><a href="#cb3-241" aria-hidden="true" tabindex="-1"></a>                         f2 <span class="kw">AS</span> f0, f3 <span class="kw">AS</span> f1, f4 <span class="kw">AS</span> f2, f5 <span class="kw">AS</span> f3</span>
<span id="cb3-242"><a href="#cb3-242" aria-hidden="true" tabindex="-1"></a>                         <span class="kw">FROM</span></span>
<span id="cb3-243"><a href="#cb3-243" aria-hidden="true" tabindex="-1"></a>                         (<span class="kw">SELECT</span></span>
<span id="cb3-244"><a href="#cb3-244" aria-hidden="true" tabindex="-1"></a>                          f1 <span class="kw">AS</span> f0, f2 <span class="kw">AS</span> f1, f3 <span class="kw">AS</span> f2, f4 <span class="kw">AS</span> f3, f5 <span class="kw">AS</span> f4, f6 <span class="kw">AS</span> f5</span>
<span id="cb3-245"><a href="#cb3-245" aria-hidden="true" tabindex="-1"></a>                          <span class="kw">FROM</span></span>
<span id="cb3-246"><a href="#cb3-246" aria-hidden="true" tabindex="-1"></a>                          t13</span>
<span id="cb3-247"><a href="#cb3-247" aria-hidden="true" tabindex="-1"></a>                          <span class="kw">AS</span> _)</span>
<span id="cb3-248"><a href="#cb3-248" aria-hidden="true" tabindex="-1"></a>                         <span class="kw">AS</span> _)</span>
<span id="cb3-249"><a href="#cb3-249" aria-hidden="true" tabindex="-1"></a>                        <span class="kw">AS</span> _)</span>
<span id="cb3-250"><a href="#cb3-250" aria-hidden="true" tabindex="-1"></a>                       <span class="kw">AS</span> _)</span>
<span id="cb3-251"><a href="#cb3-251" aria-hidden="true" tabindex="-1"></a>                      <span class="kw">AS</span> _</span>
<span id="cb3-252"><a href="#cb3-252" aria-hidden="true" tabindex="-1"></a>                      <span class="kw">CROSS</span> <span class="kw">JOIN</span></span>
<span id="cb3-253"><a href="#cb3-253" aria-hidden="true" tabindex="-1"></a>                      (<span class="kw">SELECT</span> f0 <span class="kw">AS</span> f1 <span class="kw">FROM</span> (<span class="kw">SELECT</span> <span class="dv">1</span> <span class="kw">as</span> f0 <span class="kw">FROM</span> t13 <span class="kw">AS</span> _) <span class="kw">AS</span> _))</span>
<span id="cb3-254"><a href="#cb3-254" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">AS</span> _)</span>
<span id="cb3-255"><a href="#cb3-255" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">AS</span> _)</span>
<span id="cb3-256"><a href="#cb3-256" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">AS</span> _)</span>
<span id="cb3-257"><a href="#cb3-257" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">AS</span> _</span>
<span id="cb3-258"><a href="#cb3-258" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">UNION</span></span>
<span id="cb3-259"><a href="#cb3-259" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-260"><a href="#cb3-260" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">FROM</span></span>
<span id="cb3-261"><a href="#cb3-261" aria-hidden="true" tabindex="-1"></a>                  (<span class="kw">SELECT</span></span>
<span id="cb3-262"><a href="#cb3-262" aria-hidden="true" tabindex="-1"></a>                   f0 <span class="kw">AS</span> f0, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f1</span>
<span id="cb3-263"><a href="#cb3-263" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">FROM</span></span>
<span id="cb3-264"><a href="#cb3-264" aria-hidden="true" tabindex="-1"></a>                   (<span class="kw">SELECT</span></span>
<span id="cb3-265"><a href="#cb3-265" aria-hidden="true" tabindex="-1"></a>                    f0 <span class="kw">AS</span> f0</span>
<span id="cb3-266"><a href="#cb3-266" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">FROM</span></span>
<span id="cb3-267"><a href="#cb3-267" aria-hidden="true" tabindex="-1"></a>                    (<span class="kw">SELECT</span></span>
<span id="cb3-268"><a href="#cb3-268" aria-hidden="true" tabindex="-1"></a>                     f2 <span class="kw">AS</span> f0, f3 <span class="kw">AS</span> f1, f4 <span class="kw">AS</span> f2, f5 <span class="kw">AS</span> f3</span>
<span id="cb3-269"><a href="#cb3-269" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">FROM</span></span>
<span id="cb3-270"><a href="#cb3-270" aria-hidden="true" tabindex="-1"></a>                     (<span class="kw">SELECT</span></span>
<span id="cb3-271"><a href="#cb3-271" aria-hidden="true" tabindex="-1"></a>                      f1 <span class="kw">AS</span> f0, f2 <span class="kw">AS</span> f1, f3 <span class="kw">AS</span> f2, f4 <span class="kw">AS</span> f3, f5 <span class="kw">AS</span> f4, f6 <span class="kw">AS</span> f5</span>
<span id="cb3-272"><a href="#cb3-272" aria-hidden="true" tabindex="-1"></a>                      <span class="kw">FROM</span></span>
<span id="cb3-273"><a href="#cb3-273" aria-hidden="true" tabindex="-1"></a>                      (<span class="kw">SELECT</span></span>
<span id="cb3-274"><a href="#cb3-274" aria-hidden="true" tabindex="-1"></a>                       f7 <span class="kw">AS</span> f0, f8 <span class="kw">AS</span> f1, f9 <span class="kw">AS</span> f2, f10 <span class="kw">AS</span> f3, f11 <span class="kw">AS</span> f4, f12 <span class="kw">AS</span> f5, f13 <span class="kw">AS</span> f6</span>
<span id="cb3-275"><a href="#cb3-275" aria-hidden="true" tabindex="-1"></a>                       <span class="kw">FROM</span></span>
<span id="cb3-276"><a href="#cb3-276" aria-hidden="true" tabindex="-1"></a>                       (<span class="co">-- join2</span></span>
<span id="cb3-277"><a href="#cb3-277" aria-hidden="true" tabindex="-1"></a>                        <span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> t12 <span class="kw">AS</span> _</span>
<span id="cb3-278"><a href="#cb3-278" aria-hidden="true" tabindex="-1"></a>                        <span class="kw">WHERE</span></span>
<span id="cb3-279"><a href="#cb3-279" aria-hidden="true" tabindex="-1"></a>                        (<span class="ot">&quot;f7&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>) <span class="kw">AND</span> (((<span class="ot">&quot;f8&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>) <span class="kw">OR</span> (<span class="ot">&quot;f9&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)) <span class="kw">AND</span> ((<span class="ot">&quot;f10&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>) <span class="kw">AND</span> (((<span class="ot">&quot;f11&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>) <span class="kw">OR</span> (<span class="ot">&quot;f12&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)) <span class="kw">AND</span> (<span class="ot">&quot;f13&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)))))</span>
<span id="cb3-280"><a href="#cb3-280" aria-hidden="true" tabindex="-1"></a>                       <span class="kw">AS</span> _)</span>
<span id="cb3-281"><a href="#cb3-281" aria-hidden="true" tabindex="-1"></a>                      <span class="kw">AS</span> _)</span>
<span id="cb3-282"><a href="#cb3-282" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">AS</span> _)</span>
<span id="cb3-283"><a href="#cb3-283" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">AS</span> _)</span>
<span id="cb3-284"><a href="#cb3-284" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">AS</span> _)</span>
<span id="cb3-285"><a href="#cb3-285" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">AS</span> _)</span>
<span id="cb3-286"><a href="#cb3-286" aria-hidden="true" tabindex="-1"></a>                 <span class="kw">AS</span> _)</span>
<span id="cb3-287"><a href="#cb3-287" aria-hidden="true" tabindex="-1"></a>                <span class="kw">AS</span> _)</span>
<span id="cb3-288"><a href="#cb3-288" aria-hidden="true" tabindex="-1"></a>               <span class="kw">AS</span> _)</span>
<span id="cb3-289"><a href="#cb3-289" aria-hidden="true" tabindex="-1"></a>              <span class="kw">AS</span> _)</span>
<span id="cb3-290"><a href="#cb3-290" aria-hidden="true" tabindex="-1"></a>             <span class="kw">AS</span> _)</span>
<span id="cb3-291"><a href="#cb3-291" aria-hidden="true" tabindex="-1"></a>            <span class="kw">AS</span> _)</span>
<span id="cb3-292"><a href="#cb3-292" aria-hidden="true" tabindex="-1"></a>           <span class="kw">AS</span> _</span>
<span id="cb3-293"><a href="#cb3-293" aria-hidden="true" tabindex="-1"></a>           <span class="kw">CROSS</span> <span class="kw">JOIN</span></span>
<span id="cb3-294"><a href="#cb3-294" aria-hidden="true" tabindex="-1"></a>           (<span class="kw">SELECT</span> f0 <span class="kw">AS</span> f2 <span class="kw">FROM</span> (<span class="kw">SELECT</span> f2 <span class="kw">AS</span> f0 <span class="kw">FROM</span> t3 <span class="kw">AS</span> _) <span class="kw">AS</span> _))</span>
<span id="cb3-295"><a href="#cb3-295" aria-hidden="true" tabindex="-1"></a>          <span class="kw">AS</span> _)</span>
<span id="cb3-296"><a href="#cb3-296" aria-hidden="true" tabindex="-1"></a>         <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-297"><a href="#cb3-297" aria-hidden="true" tabindex="-1"></a>         <span class="kw">FROM</span></span>
<span id="cb3-298"><a href="#cb3-298" aria-hidden="true" tabindex="-1"></a>         (<span class="co">-- dist</span></span>
<span id="cb3-299"><a href="#cb3-299" aria-hidden="true" tabindex="-1"></a>          <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-300"><a href="#cb3-300" aria-hidden="true" tabindex="-1"></a>          <span class="kw">FROM</span></span>
<span id="cb3-301"><a href="#cb3-301" aria-hidden="true" tabindex="-1"></a>          (<span class="kw">SELECT</span></span>
<span id="cb3-302"><a href="#cb3-302" aria-hidden="true" tabindex="-1"></a>           f0 <span class="kw">AS</span> f0, f2 <span class="kw">AS</span> f1, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f2, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f3</span>
<span id="cb3-303"><a href="#cb3-303" aria-hidden="true" tabindex="-1"></a>           <span class="kw">FROM</span></span>
<span id="cb3-304"><a href="#cb3-304" aria-hidden="true" tabindex="-1"></a>           (<span class="co">-- dist1</span></span>
<span id="cb3-305"><a href="#cb3-305" aria-hidden="true" tabindex="-1"></a>            <span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> t4 <span class="kw">AS</span> _ <span class="kw">WHERE</span> <span class="ot">&quot;f0&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)</span>
<span id="cb3-306"><a href="#cb3-306" aria-hidden="true" tabindex="-1"></a>           <span class="kw">AS</span> _)</span>
<span id="cb3-307"><a href="#cb3-307" aria-hidden="true" tabindex="-1"></a>          <span class="kw">AS</span> _</span>
<span id="cb3-308"><a href="#cb3-308" aria-hidden="true" tabindex="-1"></a>          <span class="kw">UNION</span></span>
<span id="cb3-309"><a href="#cb3-309" aria-hidden="true" tabindex="-1"></a>          <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-310"><a href="#cb3-310" aria-hidden="true" tabindex="-1"></a>          <span class="kw">FROM</span></span>
<span id="cb3-311"><a href="#cb3-311" aria-hidden="true" tabindex="-1"></a>          (<span class="kw">SELECT</span></span>
<span id="cb3-312"><a href="#cb3-312" aria-hidden="true" tabindex="-1"></a>           <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f0, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f1, f1 <span class="kw">AS</span> f2, f2 <span class="kw">AS</span> f3</span>
<span id="cb3-313"><a href="#cb3-313" aria-hidden="true" tabindex="-1"></a>           <span class="kw">FROM</span></span>
<span id="cb3-314"><a href="#cb3-314" aria-hidden="true" tabindex="-1"></a>           (<span class="co">-- dist2</span></span>
<span id="cb3-315"><a href="#cb3-315" aria-hidden="true" tabindex="-1"></a>            <span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> t4 <span class="kw">AS</span> _ <span class="kw">WHERE</span> <span class="ot">&quot;f1&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)</span>
<span id="cb3-316"><a href="#cb3-316" aria-hidden="true" tabindex="-1"></a>           <span class="kw">AS</span> _)</span>
<span id="cb3-317"><a href="#cb3-317" aria-hidden="true" tabindex="-1"></a>          <span class="kw">AS</span> _)</span>
<span id="cb3-318"><a href="#cb3-318" aria-hidden="true" tabindex="-1"></a>         <span class="kw">AS</span> _)</span>
<span id="cb3-319"><a href="#cb3-319" aria-hidden="true" tabindex="-1"></a>        <span class="kw">AS</span> _)</span>
<span id="cb3-320"><a href="#cb3-320" aria-hidden="true" tabindex="-1"></a>       <span class="kw">AS</span> _)</span>
<span id="cb3-321"><a href="#cb3-321" aria-hidden="true" tabindex="-1"></a>      <span class="kw">AS</span> _</span>
<span id="cb3-322"><a href="#cb3-322" aria-hidden="true" tabindex="-1"></a>      <span class="kw">UNION</span> <span class="kw">ALL</span></span>
<span id="cb3-323"><a href="#cb3-323" aria-hidden="true" tabindex="-1"></a>      <span class="kw">SELECT</span></span>
<span id="cb3-324"><a href="#cb3-324" aria-hidden="true" tabindex="-1"></a>      clock_timestamp() <span class="kw">as</span> step</span>
<span id="cb3-325"><a href="#cb3-325" aria-hidden="true" tabindex="-1"></a>      , <span class="op">*</span></span>
<span id="cb3-326"><a href="#cb3-326" aria-hidden="true" tabindex="-1"></a>      <span class="kw">FROM</span></span>
<span id="cb3-327"><a href="#cb3-327" aria-hidden="true" tabindex="-1"></a>      (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-328"><a href="#cb3-328" aria-hidden="true" tabindex="-1"></a>       <span class="kw">FROM</span></span>
<span id="cb3-329"><a href="#cb3-329" aria-hidden="true" tabindex="-1"></a>       (<span class="kw">WITH</span> t14 <span class="kw">AS</span></span>
<span id="cb3-330"><a href="#cb3-330" aria-hidden="true" tabindex="-1"></a>        (<span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> recursion <span class="kw">AS</span> _)</span>
<span id="cb3-331"><a href="#cb3-331" aria-hidden="true" tabindex="-1"></a>        <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-332"><a href="#cb3-332" aria-hidden="true" tabindex="-1"></a>        <span class="kw">FROM</span></span>
<span id="cb3-333"><a href="#cb3-333" aria-hidden="true" tabindex="-1"></a>        (<span class="kw">WITH</span> t15 <span class="kw">AS</span></span>
<span id="cb3-334"><a href="#cb3-334" aria-hidden="true" tabindex="-1"></a>         (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-335"><a href="#cb3-335" aria-hidden="true" tabindex="-1"></a>          <span class="kw">FROM</span></span>
<span id="cb3-336"><a href="#cb3-336" aria-hidden="true" tabindex="-1"></a>          (<span class="co">-- undist</span></span>
<span id="cb3-337"><a href="#cb3-337" aria-hidden="true" tabindex="-1"></a>           <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-338"><a href="#cb3-338" aria-hidden="true" tabindex="-1"></a>           <span class="kw">FROM</span></span>
<span id="cb3-339"><a href="#cb3-339" aria-hidden="true" tabindex="-1"></a>           (<span class="kw">SELECT</span></span>
<span id="cb3-340"><a href="#cb3-340" aria-hidden="true" tabindex="-1"></a>            f0 <span class="kw">AS</span> f0, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f1, f1 <span class="kw">AS</span> f2</span>
<span id="cb3-341"><a href="#cb3-341" aria-hidden="true" tabindex="-1"></a>            <span class="kw">FROM</span></span>
<span id="cb3-342"><a href="#cb3-342" aria-hidden="true" tabindex="-1"></a>            (<span class="co">-- undist1</span></span>
<span id="cb3-343"><a href="#cb3-343" aria-hidden="true" tabindex="-1"></a>             <span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> t14 <span class="kw">AS</span> _ <span class="kw">WHERE</span> <span class="ot">&quot;f0&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)</span>
<span id="cb3-344"><a href="#cb3-344" aria-hidden="true" tabindex="-1"></a>            <span class="kw">AS</span> _)</span>
<span id="cb3-345"><a href="#cb3-345" aria-hidden="true" tabindex="-1"></a>           <span class="kw">AS</span> _</span>
<span id="cb3-346"><a href="#cb3-346" aria-hidden="true" tabindex="-1"></a>           <span class="kw">UNION</span></span>
<span id="cb3-347"><a href="#cb3-347" aria-hidden="true" tabindex="-1"></a>           <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-348"><a href="#cb3-348" aria-hidden="true" tabindex="-1"></a>           <span class="kw">FROM</span></span>
<span id="cb3-349"><a href="#cb3-349" aria-hidden="true" tabindex="-1"></a>           (<span class="kw">SELECT</span></span>
<span id="cb3-350"><a href="#cb3-350" aria-hidden="true" tabindex="-1"></a>            <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f0, f2 <span class="kw">AS</span> f1, f3 <span class="kw">AS</span> f2</span>
<span id="cb3-351"><a href="#cb3-351" aria-hidden="true" tabindex="-1"></a>            <span class="kw">FROM</span></span>
<span id="cb3-352"><a href="#cb3-352" aria-hidden="true" tabindex="-1"></a>            (<span class="co">-- dist2</span></span>
<span id="cb3-353"><a href="#cb3-353" aria-hidden="true" tabindex="-1"></a>             <span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> t14 <span class="kw">AS</span> _ <span class="kw">WHERE</span> <span class="ot">&quot;f2&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)</span>
<span id="cb3-354"><a href="#cb3-354" aria-hidden="true" tabindex="-1"></a>            <span class="kw">AS</span> _)</span>
<span id="cb3-355"><a href="#cb3-355" aria-hidden="true" tabindex="-1"></a>           <span class="kw">AS</span> _)</span>
<span id="cb3-356"><a href="#cb3-356" aria-hidden="true" tabindex="-1"></a>          <span class="kw">AS</span> _)</span>
<span id="cb3-357"><a href="#cb3-357" aria-hidden="true" tabindex="-1"></a>         <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-358"><a href="#cb3-358" aria-hidden="true" tabindex="-1"></a>         <span class="kw">FROM</span></span>
<span id="cb3-359"><a href="#cb3-359" aria-hidden="true" tabindex="-1"></a>         (<span class="kw">WITH</span> t16 <span class="kw">AS</span></span>
<span id="cb3-360"><a href="#cb3-360" aria-hidden="true" tabindex="-1"></a>          (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-361"><a href="#cb3-361" aria-hidden="true" tabindex="-1"></a>           <span class="kw">FROM</span></span>
<span id="cb3-362"><a href="#cb3-362" aria-hidden="true" tabindex="-1"></a>           (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-363"><a href="#cb3-363" aria-hidden="true" tabindex="-1"></a>            <span class="kw">FROM</span></span>
<span id="cb3-364"><a href="#cb3-364" aria-hidden="true" tabindex="-1"></a>            (<span class="kw">SELECT</span></span>
<span id="cb3-365"><a href="#cb3-365" aria-hidden="true" tabindex="-1"></a>             f0 <span class="kw">AS</span> f0, f1 <span class="kw">AS</span> f1</span>
<span id="cb3-366"><a href="#cb3-366" aria-hidden="true" tabindex="-1"></a>             <span class="kw">FROM</span></span>
<span id="cb3-367"><a href="#cb3-367" aria-hidden="true" tabindex="-1"></a>             (<span class="kw">WITH</span> t17 <span class="kw">AS</span></span>
<span id="cb3-368"><a href="#cb3-368" aria-hidden="true" tabindex="-1"></a>              (<span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> t15 <span class="kw">AS</span> _)</span>
<span id="cb3-369"><a href="#cb3-369" aria-hidden="true" tabindex="-1"></a>              <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-370"><a href="#cb3-370" aria-hidden="true" tabindex="-1"></a>              <span class="kw">FROM</span></span>
<span id="cb3-371"><a href="#cb3-371" aria-hidden="true" tabindex="-1"></a>              (<span class="kw">WITH</span> t18 <span class="kw">AS</span></span>
<span id="cb3-372"><a href="#cb3-372" aria-hidden="true" tabindex="-1"></a>               (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-373"><a href="#cb3-373" aria-hidden="true" tabindex="-1"></a>                <span class="kw">FROM</span></span>
<span id="cb3-374"><a href="#cb3-374" aria-hidden="true" tabindex="-1"></a>                (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-375"><a href="#cb3-375" aria-hidden="true" tabindex="-1"></a>                 <span class="kw">FROM</span></span>
<span id="cb3-376"><a href="#cb3-376" aria-hidden="true" tabindex="-1"></a>                 (<span class="kw">SELECT</span></span>
<span id="cb3-377"><a href="#cb3-377" aria-hidden="true" tabindex="-1"></a>                  f0 <span class="kw">AS</span> f0</span>
<span id="cb3-378"><a href="#cb3-378" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">FROM</span></span>
<span id="cb3-379"><a href="#cb3-379" aria-hidden="true" tabindex="-1"></a>                  (<span class="kw">WITH</span> t19 <span class="kw">AS</span></span>
<span id="cb3-380"><a href="#cb3-380" aria-hidden="true" tabindex="-1"></a>                   (<span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> (<span class="kw">SELECT</span> f0 <span class="kw">AS</span> f0, f1 <span class="kw">AS</span> f1 <span class="kw">FROM</span> t17 <span class="kw">AS</span> _) <span class="kw">AS</span> _)</span>
<span id="cb3-381"><a href="#cb3-381" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-382"><a href="#cb3-382" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">FROM</span></span>
<span id="cb3-383"><a href="#cb3-383" aria-hidden="true" tabindex="-1"></a>                   (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-384"><a href="#cb3-384" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">FROM</span></span>
<span id="cb3-385"><a href="#cb3-385" aria-hidden="true" tabindex="-1"></a>                    (<span class="kw">SELECT</span></span>
<span id="cb3-386"><a href="#cb3-386" aria-hidden="true" tabindex="-1"></a>                     f0 <span class="kw">AS</span> f0</span>
<span id="cb3-387"><a href="#cb3-387" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">FROM</span></span>
<span id="cb3-388"><a href="#cb3-388" aria-hidden="true" tabindex="-1"></a>                     (<span class="co">-- join1</span></span>
<span id="cb3-389"><a href="#cb3-389" aria-hidden="true" tabindex="-1"></a>                      <span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> t19 <span class="kw">AS</span> _ <span class="kw">WHERE</span> <span class="ot">&quot;f0&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)</span>
<span id="cb3-390"><a href="#cb3-390" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">AS</span> _)</span>
<span id="cb3-391"><a href="#cb3-391" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">AS</span> _</span>
<span id="cb3-392"><a href="#cb3-392" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">UNION</span></span>
<span id="cb3-393"><a href="#cb3-393" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-394"><a href="#cb3-394" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">FROM</span></span>
<span id="cb3-395"><a href="#cb3-395" aria-hidden="true" tabindex="-1"></a>                    (<span class="kw">SELECT</span></span>
<span id="cb3-396"><a href="#cb3-396" aria-hidden="true" tabindex="-1"></a>                     f1 <span class="kw">AS</span> f0</span>
<span id="cb3-397"><a href="#cb3-397" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">FROM</span></span>
<span id="cb3-398"><a href="#cb3-398" aria-hidden="true" tabindex="-1"></a>                     (<span class="co">-- join2</span></span>
<span id="cb3-399"><a href="#cb3-399" aria-hidden="true" tabindex="-1"></a>                      <span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> t19 <span class="kw">AS</span> _ <span class="kw">WHERE</span> <span class="ot">&quot;f1&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)</span>
<span id="cb3-400"><a href="#cb3-400" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">AS</span> _)</span>
<span id="cb3-401"><a href="#cb3-401" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">AS</span> _)</span>
<span id="cb3-402"><a href="#cb3-402" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">AS</span> _)</span>
<span id="cb3-403"><a href="#cb3-403" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">AS</span> _)</span>
<span id="cb3-404"><a href="#cb3-404" aria-hidden="true" tabindex="-1"></a>                 <span class="kw">AS</span> _</span>
<span id="cb3-405"><a href="#cb3-405" aria-hidden="true" tabindex="-1"></a>                 <span class="kw">CROSS</span> <span class="kw">JOIN</span></span>
<span id="cb3-406"><a href="#cb3-406" aria-hidden="true" tabindex="-1"></a>                 (<span class="kw">SELECT</span> f0 <span class="kw">AS</span> f1, f1 <span class="kw">AS</span> f2, f2 <span class="kw">AS</span> f3 <span class="kw">FROM</span> t17 <span class="kw">AS</span> _))</span>
<span id="cb3-407"><a href="#cb3-407" aria-hidden="true" tabindex="-1"></a>                <span class="kw">AS</span> _)</span>
<span id="cb3-408"><a href="#cb3-408" aria-hidden="true" tabindex="-1"></a>               <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-409"><a href="#cb3-409" aria-hidden="true" tabindex="-1"></a>               <span class="kw">FROM</span></span>
<span id="cb3-410"><a href="#cb3-410" aria-hidden="true" tabindex="-1"></a>               (<span class="kw">WITH</span> t20 <span class="kw">AS</span></span>
<span id="cb3-411"><a href="#cb3-411" aria-hidden="true" tabindex="-1"></a>                (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-412"><a href="#cb3-412" aria-hidden="true" tabindex="-1"></a>                 <span class="kw">FROM</span></span>
<span id="cb3-413"><a href="#cb3-413" aria-hidden="true" tabindex="-1"></a>                 (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-414"><a href="#cb3-414" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">FROM</span></span>
<span id="cb3-415"><a href="#cb3-415" aria-hidden="true" tabindex="-1"></a>                  (<span class="kw">SELECT</span></span>
<span id="cb3-416"><a href="#cb3-416" aria-hidden="true" tabindex="-1"></a>                   f0 <span class="kw">AS</span> f0, f1 <span class="kw">AS</span> f1</span>
<span id="cb3-417"><a href="#cb3-417" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">FROM</span></span>
<span id="cb3-418"><a href="#cb3-418" aria-hidden="true" tabindex="-1"></a>                   (<span class="kw">WITH</span> t21 <span class="kw">AS</span></span>
<span id="cb3-419"><a href="#cb3-419" aria-hidden="true" tabindex="-1"></a>                    (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-420"><a href="#cb3-420" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">FROM</span></span>
<span id="cb3-421"><a href="#cb3-421" aria-hidden="true" tabindex="-1"></a>                     (<span class="kw">SELECT</span></span>
<span id="cb3-422"><a href="#cb3-422" aria-hidden="true" tabindex="-1"></a>                      f0 <span class="op">-</span> f1 <span class="kw">AS</span> f0</span>
<span id="cb3-423"><a href="#cb3-423" aria-hidden="true" tabindex="-1"></a>                      <span class="kw">FROM</span></span>
<span id="cb3-424"><a href="#cb3-424" aria-hidden="true" tabindex="-1"></a>                      (<span class="kw">WITH</span> t22 <span class="kw">AS</span></span>
<span id="cb3-425"><a href="#cb3-425" aria-hidden="true" tabindex="-1"></a>                       (<span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> t18 <span class="kw">AS</span> _)</span>
<span id="cb3-426"><a href="#cb3-426" aria-hidden="true" tabindex="-1"></a>                       <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-427"><a href="#cb3-427" aria-hidden="true" tabindex="-1"></a>                       <span class="kw">FROM</span></span>
<span id="cb3-428"><a href="#cb3-428" aria-hidden="true" tabindex="-1"></a>                       (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-429"><a href="#cb3-429" aria-hidden="true" tabindex="-1"></a>                        <span class="kw">FROM</span></span>
<span id="cb3-430"><a href="#cb3-430" aria-hidden="true" tabindex="-1"></a>                        (<span class="kw">SELECT</span> f0 <span class="kw">AS</span> f0 <span class="kw">FROM</span> (<span class="kw">SELECT</span> f0 <span class="kw">AS</span> f0 <span class="kw">FROM</span> t22 <span class="kw">AS</span> _) <span class="kw">AS</span> _)</span>
<span id="cb3-431"><a href="#cb3-431" aria-hidden="true" tabindex="-1"></a>                        <span class="kw">AS</span> _</span>
<span id="cb3-432"><a href="#cb3-432" aria-hidden="true" tabindex="-1"></a>                        <span class="kw">CROSS</span> <span class="kw">JOIN</span></span>
<span id="cb3-433"><a href="#cb3-433" aria-hidden="true" tabindex="-1"></a>                        (<span class="kw">SELECT</span> f0 <span class="kw">AS</span> f1 <span class="kw">FROM</span> (<span class="kw">SELECT</span> <span class="dv">100</span> <span class="kw">as</span> f0 <span class="kw">FROM</span> t22 <span class="kw">AS</span> _) <span class="kw">AS</span> _))</span>
<span id="cb3-434"><a href="#cb3-434" aria-hidden="true" tabindex="-1"></a>                       <span class="kw">AS</span> _)</span>
<span id="cb3-435"><a href="#cb3-435" aria-hidden="true" tabindex="-1"></a>                      <span class="kw">AS</span> _)</span>
<span id="cb3-436"><a href="#cb3-436" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">AS</span> _)</span>
<span id="cb3-437"><a href="#cb3-437" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-438"><a href="#cb3-438" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">FROM</span></span>
<span id="cb3-439"><a href="#cb3-439" aria-hidden="true" tabindex="-1"></a>                    (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-440"><a href="#cb3-440" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">FROM</span></span>
<span id="cb3-441"><a href="#cb3-441" aria-hidden="true" tabindex="-1"></a>                     (<span class="kw">SELECT</span></span>
<span id="cb3-442"><a href="#cb3-442" aria-hidden="true" tabindex="-1"></a>                      <span class="fu">abs</span>(f0) <span class="kw">as</span> f0, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">as</span> f1</span>
<span id="cb3-443"><a href="#cb3-443" aria-hidden="true" tabindex="-1"></a>                      <span class="kw">FROM</span></span>
<span id="cb3-444"><a href="#cb3-444" aria-hidden="true" tabindex="-1"></a>                      t21</span>
<span id="cb3-445"><a href="#cb3-445" aria-hidden="true" tabindex="-1"></a>                      <span class="kw">AS</span> _</span>
<span id="cb3-446"><a href="#cb3-446" aria-hidden="true" tabindex="-1"></a>                      <span class="kw">WHERE</span></span>
<span id="cb3-447"><a href="#cb3-447" aria-hidden="true" tabindex="-1"></a>                      f0 <span class="op">&lt;</span> <span class="dv">0</span>)</span>
<span id="cb3-448"><a href="#cb3-448" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">AS</span> _</span>
<span id="cb3-449"><a href="#cb3-449" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">UNION</span></span>
<span id="cb3-450"><a href="#cb3-450" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-451"><a href="#cb3-451" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">FROM</span></span>
<span id="cb3-452"><a href="#cb3-452" aria-hidden="true" tabindex="-1"></a>                     (<span class="kw">SELECT</span> <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">as</span> f0, f0 <span class="kw">as</span> f1 <span class="kw">FROM</span> t21 <span class="kw">AS</span> _ <span class="kw">WHERE</span> f0 <span class="op">&gt;=</span> <span class="dv">0</span>)</span>
<span id="cb3-453"><a href="#cb3-453" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">AS</span> _)</span>
<span id="cb3-454"><a href="#cb3-454" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">AS</span> _)</span>
<span id="cb3-455"><a href="#cb3-455" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">AS</span> _)</span>
<span id="cb3-456"><a href="#cb3-456" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">AS</span> _</span>
<span id="cb3-457"><a href="#cb3-457" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">CROSS</span> <span class="kw">JOIN</span></span>
<span id="cb3-458"><a href="#cb3-458" aria-hidden="true" tabindex="-1"></a>                  (<span class="kw">SELECT</span> f0 <span class="kw">AS</span> f2, f1 <span class="kw">AS</span> f3, f2 <span class="kw">AS</span> f4, f3 <span class="kw">AS</span> f5 <span class="kw">FROM</span> t18 <span class="kw">AS</span> _))</span>
<span id="cb3-459"><a href="#cb3-459" aria-hidden="true" tabindex="-1"></a>                 <span class="kw">AS</span> _)</span>
<span id="cb3-460"><a href="#cb3-460" aria-hidden="true" tabindex="-1"></a>                <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-461"><a href="#cb3-461" aria-hidden="true" tabindex="-1"></a>                <span class="kw">FROM</span></span>
<span id="cb3-462"><a href="#cb3-462" aria-hidden="true" tabindex="-1"></a>                (<span class="kw">WITH</span> t23 <span class="kw">AS</span></span>
<span id="cb3-463"><a href="#cb3-463" aria-hidden="true" tabindex="-1"></a>                 (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-464"><a href="#cb3-464" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">FROM</span></span>
<span id="cb3-465"><a href="#cb3-465" aria-hidden="true" tabindex="-1"></a>                  (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-466"><a href="#cb3-466" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">FROM</span></span>
<span id="cb3-467"><a href="#cb3-467" aria-hidden="true" tabindex="-1"></a>                   (<span class="kw">SELECT</span></span>
<span id="cb3-468"><a href="#cb3-468" aria-hidden="true" tabindex="-1"></a>                    f0 <span class="kw">AS</span> f0, f1 <span class="kw">AS</span> f1</span>
<span id="cb3-469"><a href="#cb3-469" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">FROM</span></span>
<span id="cb3-470"><a href="#cb3-470" aria-hidden="true" tabindex="-1"></a>                    (<span class="kw">SELECT</span> f0 <span class="kw">AS</span> f0, f1 <span class="kw">AS</span> f1 <span class="kw">FROM</span> t20 <span class="kw">AS</span> _)</span>
<span id="cb3-471"><a href="#cb3-471" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">AS</span> _)</span>
<span id="cb3-472"><a href="#cb3-472" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">AS</span> _</span>
<span id="cb3-473"><a href="#cb3-473" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">CROSS</span> <span class="kw">JOIN</span></span>
<span id="cb3-474"><a href="#cb3-474" aria-hidden="true" tabindex="-1"></a>                   (<span class="kw">SELECT</span></span>
<span id="cb3-475"><a href="#cb3-475" aria-hidden="true" tabindex="-1"></a>                    f0 <span class="kw">AS</span> f2, f1 <span class="kw">AS</span> f3, f2 <span class="kw">AS</span> f4, f3 <span class="kw">AS</span> f5, f4 <span class="kw">AS</span> f6, f5 <span class="kw">AS</span> f7</span>
<span id="cb3-476"><a href="#cb3-476" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">FROM</span></span>
<span id="cb3-477"><a href="#cb3-477" aria-hidden="true" tabindex="-1"></a>                    t20</span>
<span id="cb3-478"><a href="#cb3-478" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">AS</span> _))</span>
<span id="cb3-479"><a href="#cb3-479" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">AS</span> _)</span>
<span id="cb3-480"><a href="#cb3-480" aria-hidden="true" tabindex="-1"></a>                 <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-481"><a href="#cb3-481" aria-hidden="true" tabindex="-1"></a>                 <span class="kw">FROM</span></span>
<span id="cb3-482"><a href="#cb3-482" aria-hidden="true" tabindex="-1"></a>                 (<span class="kw">WITH</span> t24 <span class="kw">AS</span></span>
<span id="cb3-483"><a href="#cb3-483" aria-hidden="true" tabindex="-1"></a>                  (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-484"><a href="#cb3-484" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">FROM</span></span>
<span id="cb3-485"><a href="#cb3-485" aria-hidden="true" tabindex="-1"></a>                   (<span class="co">-- dist</span></span>
<span id="cb3-486"><a href="#cb3-486" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-487"><a href="#cb3-487" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">FROM</span></span>
<span id="cb3-488"><a href="#cb3-488" aria-hidden="true" tabindex="-1"></a>                    (<span class="kw">SELECT</span></span>
<span id="cb3-489"><a href="#cb3-489" aria-hidden="true" tabindex="-1"></a>                     f0 <span class="kw">AS</span> f0, f2 <span class="kw">AS</span> f1, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f10, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f11, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f12, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f13, f3 <span class="kw">AS</span> f2, f4 <span class="kw">AS</span> f3, f5 <span class="kw">AS</span> f4, f6 <span class="kw">AS</span> f5, f7 <span class="kw">AS</span> f6, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f7, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f8, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f9</span>
<span id="cb3-490"><a href="#cb3-490" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">FROM</span></span>
<span id="cb3-491"><a href="#cb3-491" aria-hidden="true" tabindex="-1"></a>                     (<span class="co">-- dist1</span></span>
<span id="cb3-492"><a href="#cb3-492" aria-hidden="true" tabindex="-1"></a>                      <span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> t23 <span class="kw">AS</span> _ <span class="kw">WHERE</span> <span class="ot">&quot;f0&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)</span>
<span id="cb3-493"><a href="#cb3-493" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">AS</span> _)</span>
<span id="cb3-494"><a href="#cb3-494" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">AS</span> _</span>
<span id="cb3-495"><a href="#cb3-495" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">UNION</span></span>
<span id="cb3-496"><a href="#cb3-496" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-497"><a href="#cb3-497" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">FROM</span></span>
<span id="cb3-498"><a href="#cb3-498" aria-hidden="true" tabindex="-1"></a>                    (<span class="kw">SELECT</span></span>
<span id="cb3-499"><a href="#cb3-499" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f0, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f1, f4 <span class="kw">AS</span> f10, f5 <span class="kw">AS</span> f11, f6 <span class="kw">AS</span> f12, f7 <span class="kw">AS</span> f13, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f2, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f3, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f4, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f5, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f6, f1 <span class="kw">AS</span> f7, f2 <span class="kw">AS</span> f8, f3 <span class="kw">AS</span> f9</span>
<span id="cb3-500"><a href="#cb3-500" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">FROM</span></span>
<span id="cb3-501"><a href="#cb3-501" aria-hidden="true" tabindex="-1"></a>                     (<span class="co">-- dist2</span></span>
<span id="cb3-502"><a href="#cb3-502" aria-hidden="true" tabindex="-1"></a>                      <span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> t23 <span class="kw">AS</span> _ <span class="kw">WHERE</span> <span class="ot">&quot;f1&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)</span>
<span id="cb3-503"><a href="#cb3-503" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">AS</span> _)</span>
<span id="cb3-504"><a href="#cb3-504" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">AS</span> _)</span>
<span id="cb3-505"><a href="#cb3-505" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">AS</span> _)</span>
<span id="cb3-506"><a href="#cb3-506" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-507"><a href="#cb3-507" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">FROM</span></span>
<span id="cb3-508"><a href="#cb3-508" aria-hidden="true" tabindex="-1"></a>                  (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-509"><a href="#cb3-509" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">FROM</span></span>
<span id="cb3-510"><a href="#cb3-510" aria-hidden="true" tabindex="-1"></a>                   (<span class="kw">SELECT</span></span>
<span id="cb3-511"><a href="#cb3-511" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f0, f0 <span class="kw">AS</span> f1</span>
<span id="cb3-512"><a href="#cb3-512" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">FROM</span></span>
<span id="cb3-513"><a href="#cb3-513" aria-hidden="true" tabindex="-1"></a>                    (<span class="kw">SELECT</span></span>
<span id="cb3-514"><a href="#cb3-514" aria-hidden="true" tabindex="-1"></a>                     f0 <span class="op">+</span> f1 <span class="kw">AS</span> f0</span>
<span id="cb3-515"><a href="#cb3-515" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">FROM</span></span>
<span id="cb3-516"><a href="#cb3-516" aria-hidden="true" tabindex="-1"></a>                     (<span class="kw">WITH</span> t25 <span class="kw">AS</span></span>
<span id="cb3-517"><a href="#cb3-517" aria-hidden="true" tabindex="-1"></a>                      (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-518"><a href="#cb3-518" aria-hidden="true" tabindex="-1"></a>                       <span class="kw">FROM</span></span>
<span id="cb3-519"><a href="#cb3-519" aria-hidden="true" tabindex="-1"></a>                       (<span class="kw">SELECT</span></span>
<span id="cb3-520"><a href="#cb3-520" aria-hidden="true" tabindex="-1"></a>                        f0 <span class="kw">AS</span> f0, f1 <span class="kw">AS</span> f1, f2 <span class="kw">AS</span> f2, f3 <span class="kw">AS</span> f3, f4 <span class="kw">AS</span> f4, f5 <span class="kw">AS</span> f5, f6 <span class="kw">AS</span> f6</span>
<span id="cb3-521"><a href="#cb3-521" aria-hidden="true" tabindex="-1"></a>                        <span class="kw">FROM</span></span>
<span id="cb3-522"><a href="#cb3-522" aria-hidden="true" tabindex="-1"></a>                        (<span class="co">-- join1</span></span>
<span id="cb3-523"><a href="#cb3-523" aria-hidden="true" tabindex="-1"></a>                         <span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> t24 <span class="kw">AS</span> _</span>
<span id="cb3-524"><a href="#cb3-524" aria-hidden="true" tabindex="-1"></a>                         <span class="kw">WHERE</span></span>
<span id="cb3-525"><a href="#cb3-525" aria-hidden="true" tabindex="-1"></a>                         (<span class="ot">&quot;f0&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>) <span class="kw">AND</span> (((<span class="ot">&quot;f1&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>) <span class="kw">OR</span> (<span class="ot">&quot;f2&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)) <span class="kw">AND</span> ((<span class="ot">&quot;f3&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>) <span class="kw">AND</span> (((<span class="ot">&quot;f4&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>) <span class="kw">OR</span> (<span class="ot">&quot;f5&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)) <span class="kw">AND</span> (<span class="ot">&quot;f6&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)))))</span>
<span id="cb3-526"><a href="#cb3-526" aria-hidden="true" tabindex="-1"></a>                        <span class="kw">AS</span> _)</span>
<span id="cb3-527"><a href="#cb3-527" aria-hidden="true" tabindex="-1"></a>                       <span class="kw">AS</span> _)</span>
<span id="cb3-528"><a href="#cb3-528" aria-hidden="true" tabindex="-1"></a>                      <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-529"><a href="#cb3-529" aria-hidden="true" tabindex="-1"></a>                      <span class="kw">FROM</span></span>
<span id="cb3-530"><a href="#cb3-530" aria-hidden="true" tabindex="-1"></a>                      (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-531"><a href="#cb3-531" aria-hidden="true" tabindex="-1"></a>                       <span class="kw">FROM</span></span>
<span id="cb3-532"><a href="#cb3-532" aria-hidden="true" tabindex="-1"></a>                       (<span class="kw">SELECT</span></span>
<span id="cb3-533"><a href="#cb3-533" aria-hidden="true" tabindex="-1"></a>                        f0 <span class="kw">AS</span> f0</span>
<span id="cb3-534"><a href="#cb3-534" aria-hidden="true" tabindex="-1"></a>                        <span class="kw">FROM</span></span>
<span id="cb3-535"><a href="#cb3-535" aria-hidden="true" tabindex="-1"></a>                        (<span class="kw">SELECT</span></span>
<span id="cb3-536"><a href="#cb3-536" aria-hidden="true" tabindex="-1"></a>                         f0 <span class="kw">AS</span> f0</span>
<span id="cb3-537"><a href="#cb3-537" aria-hidden="true" tabindex="-1"></a>                         <span class="kw">FROM</span></span>
<span id="cb3-538"><a href="#cb3-538" aria-hidden="true" tabindex="-1"></a>                         (<span class="kw">SELECT</span></span>
<span id="cb3-539"><a href="#cb3-539" aria-hidden="true" tabindex="-1"></a>                          f2 <span class="kw">AS</span> f0, f3 <span class="kw">AS</span> f1, f4 <span class="kw">AS</span> f2, f5 <span class="kw">AS</span> f3</span>
<span id="cb3-540"><a href="#cb3-540" aria-hidden="true" tabindex="-1"></a>                          <span class="kw">FROM</span></span>
<span id="cb3-541"><a href="#cb3-541" aria-hidden="true" tabindex="-1"></a>                          (<span class="kw">SELECT</span></span>
<span id="cb3-542"><a href="#cb3-542" aria-hidden="true" tabindex="-1"></a>                           f1 <span class="kw">AS</span> f0, f2 <span class="kw">AS</span> f1, f3 <span class="kw">AS</span> f2, f4 <span class="kw">AS</span> f3, f5 <span class="kw">AS</span> f4, f6 <span class="kw">AS</span> f5</span>
<span id="cb3-543"><a href="#cb3-543" aria-hidden="true" tabindex="-1"></a>                           <span class="kw">FROM</span></span>
<span id="cb3-544"><a href="#cb3-544" aria-hidden="true" tabindex="-1"></a>                           t25</span>
<span id="cb3-545"><a href="#cb3-545" aria-hidden="true" tabindex="-1"></a>                           <span class="kw">AS</span> _)</span>
<span id="cb3-546"><a href="#cb3-546" aria-hidden="true" tabindex="-1"></a>                          <span class="kw">AS</span> _)</span>
<span id="cb3-547"><a href="#cb3-547" aria-hidden="true" tabindex="-1"></a>                         <span class="kw">AS</span> _)</span>
<span id="cb3-548"><a href="#cb3-548" aria-hidden="true" tabindex="-1"></a>                        <span class="kw">AS</span> _)</span>
<span id="cb3-549"><a href="#cb3-549" aria-hidden="true" tabindex="-1"></a>                       <span class="kw">AS</span> _</span>
<span id="cb3-550"><a href="#cb3-550" aria-hidden="true" tabindex="-1"></a>                       <span class="kw">CROSS</span> <span class="kw">JOIN</span></span>
<span id="cb3-551"><a href="#cb3-551" aria-hidden="true" tabindex="-1"></a>                       (<span class="kw">SELECT</span> f0 <span class="kw">AS</span> f1 <span class="kw">FROM</span> (<span class="kw">SELECT</span> <span class="dv">1</span> <span class="kw">as</span> f0 <span class="kw">FROM</span> t25 <span class="kw">AS</span> _) <span class="kw">AS</span> _))</span>
<span id="cb3-552"><a href="#cb3-552" aria-hidden="true" tabindex="-1"></a>                      <span class="kw">AS</span> _)</span>
<span id="cb3-553"><a href="#cb3-553" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">AS</span> _)</span>
<span id="cb3-554"><a href="#cb3-554" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">AS</span> _)</span>
<span id="cb3-555"><a href="#cb3-555" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">AS</span> _</span>
<span id="cb3-556"><a href="#cb3-556" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">UNION</span></span>
<span id="cb3-557"><a href="#cb3-557" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-558"><a href="#cb3-558" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">FROM</span></span>
<span id="cb3-559"><a href="#cb3-559" aria-hidden="true" tabindex="-1"></a>                   (<span class="kw">SELECT</span></span>
<span id="cb3-560"><a href="#cb3-560" aria-hidden="true" tabindex="-1"></a>                    f0 <span class="kw">AS</span> f0, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f1</span>
<span id="cb3-561"><a href="#cb3-561" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">FROM</span></span>
<span id="cb3-562"><a href="#cb3-562" aria-hidden="true" tabindex="-1"></a>                    (<span class="kw">SELECT</span></span>
<span id="cb3-563"><a href="#cb3-563" aria-hidden="true" tabindex="-1"></a>                     f0 <span class="kw">AS</span> f0</span>
<span id="cb3-564"><a href="#cb3-564" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">FROM</span></span>
<span id="cb3-565"><a href="#cb3-565" aria-hidden="true" tabindex="-1"></a>                     (<span class="kw">SELECT</span></span>
<span id="cb3-566"><a href="#cb3-566" aria-hidden="true" tabindex="-1"></a>                      f2 <span class="kw">AS</span> f0, f3 <span class="kw">AS</span> f1, f4 <span class="kw">AS</span> f2, f5 <span class="kw">AS</span> f3</span>
<span id="cb3-567"><a href="#cb3-567" aria-hidden="true" tabindex="-1"></a>                      <span class="kw">FROM</span></span>
<span id="cb3-568"><a href="#cb3-568" aria-hidden="true" tabindex="-1"></a>                      (<span class="kw">SELECT</span></span>
<span id="cb3-569"><a href="#cb3-569" aria-hidden="true" tabindex="-1"></a>                       f1 <span class="kw">AS</span> f0, f2 <span class="kw">AS</span> f1, f3 <span class="kw">AS</span> f2, f4 <span class="kw">AS</span> f3, f5 <span class="kw">AS</span> f4, f6 <span class="kw">AS</span> f5</span>
<span id="cb3-570"><a href="#cb3-570" aria-hidden="true" tabindex="-1"></a>                       <span class="kw">FROM</span></span>
<span id="cb3-571"><a href="#cb3-571" aria-hidden="true" tabindex="-1"></a>                       (<span class="kw">SELECT</span></span>
<span id="cb3-572"><a href="#cb3-572" aria-hidden="true" tabindex="-1"></a>                        f7 <span class="kw">AS</span> f0, f8 <span class="kw">AS</span> f1, f9 <span class="kw">AS</span> f2, f10 <span class="kw">AS</span> f3, f11 <span class="kw">AS</span> f4, f12 <span class="kw">AS</span> f5, f13 <span class="kw">AS</span> f6</span>
<span id="cb3-573"><a href="#cb3-573" aria-hidden="true" tabindex="-1"></a>                        <span class="kw">FROM</span></span>
<span id="cb3-574"><a href="#cb3-574" aria-hidden="true" tabindex="-1"></a>                        (<span class="co">-- join2</span></span>
<span id="cb3-575"><a href="#cb3-575" aria-hidden="true" tabindex="-1"></a>                         <span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> t24 <span class="kw">AS</span> _</span>
<span id="cb3-576"><a href="#cb3-576" aria-hidden="true" tabindex="-1"></a>                         <span class="kw">WHERE</span></span>
<span id="cb3-577"><a href="#cb3-577" aria-hidden="true" tabindex="-1"></a>                         (<span class="ot">&quot;f7&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>) <span class="kw">AND</span> (((<span class="ot">&quot;f8&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>) <span class="kw">OR</span> (<span class="ot">&quot;f9&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)) <span class="kw">AND</span> ((<span class="ot">&quot;f10&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>) <span class="kw">AND</span> (((<span class="ot">&quot;f11&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>) <span class="kw">OR</span> (<span class="ot">&quot;f12&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)) <span class="kw">AND</span> (<span class="ot">&quot;f13&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)))))</span>
<span id="cb3-578"><a href="#cb3-578" aria-hidden="true" tabindex="-1"></a>                        <span class="kw">AS</span> _)</span>
<span id="cb3-579"><a href="#cb3-579" aria-hidden="true" tabindex="-1"></a>                       <span class="kw">AS</span> _)</span>
<span id="cb3-580"><a href="#cb3-580" aria-hidden="true" tabindex="-1"></a>                      <span class="kw">AS</span> _)</span>
<span id="cb3-581"><a href="#cb3-581" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">AS</span> _)</span>
<span id="cb3-582"><a href="#cb3-582" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">AS</span> _)</span>
<span id="cb3-583"><a href="#cb3-583" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">AS</span> _)</span>
<span id="cb3-584"><a href="#cb3-584" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">AS</span> _)</span>
<span id="cb3-585"><a href="#cb3-585" aria-hidden="true" tabindex="-1"></a>                 <span class="kw">AS</span> _)</span>
<span id="cb3-586"><a href="#cb3-586" aria-hidden="true" tabindex="-1"></a>                <span class="kw">AS</span> _)</span>
<span id="cb3-587"><a href="#cb3-587" aria-hidden="true" tabindex="-1"></a>               <span class="kw">AS</span> _)</span>
<span id="cb3-588"><a href="#cb3-588" aria-hidden="true" tabindex="-1"></a>              <span class="kw">AS</span> _)</span>
<span id="cb3-589"><a href="#cb3-589" aria-hidden="true" tabindex="-1"></a>             <span class="kw">AS</span> _)</span>
<span id="cb3-590"><a href="#cb3-590" aria-hidden="true" tabindex="-1"></a>            <span class="kw">AS</span> _</span>
<span id="cb3-591"><a href="#cb3-591" aria-hidden="true" tabindex="-1"></a>            <span class="kw">CROSS</span> <span class="kw">JOIN</span></span>
<span id="cb3-592"><a href="#cb3-592" aria-hidden="true" tabindex="-1"></a>            (<span class="kw">SELECT</span> f0 <span class="kw">AS</span> f2 <span class="kw">FROM</span> (<span class="kw">SELECT</span> f2 <span class="kw">AS</span> f0 <span class="kw">FROM</span> t15 <span class="kw">AS</span> _) <span class="kw">AS</span> _))</span>
<span id="cb3-593"><a href="#cb3-593" aria-hidden="true" tabindex="-1"></a>           <span class="kw">AS</span> _)</span>
<span id="cb3-594"><a href="#cb3-594" aria-hidden="true" tabindex="-1"></a>          <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-595"><a href="#cb3-595" aria-hidden="true" tabindex="-1"></a>          <span class="kw">FROM</span></span>
<span id="cb3-596"><a href="#cb3-596" aria-hidden="true" tabindex="-1"></a>          (<span class="co">-- dist</span></span>
<span id="cb3-597"><a href="#cb3-597" aria-hidden="true" tabindex="-1"></a>           <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-598"><a href="#cb3-598" aria-hidden="true" tabindex="-1"></a>           <span class="kw">FROM</span></span>
<span id="cb3-599"><a href="#cb3-599" aria-hidden="true" tabindex="-1"></a>           (<span class="kw">SELECT</span></span>
<span id="cb3-600"><a href="#cb3-600" aria-hidden="true" tabindex="-1"></a>            f0 <span class="kw">AS</span> f0, f2 <span class="kw">AS</span> f1, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f2, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f3</span>
<span id="cb3-601"><a href="#cb3-601" aria-hidden="true" tabindex="-1"></a>            <span class="kw">FROM</span></span>
<span id="cb3-602"><a href="#cb3-602" aria-hidden="true" tabindex="-1"></a>            (<span class="co">-- dist1</span></span>
<span id="cb3-603"><a href="#cb3-603" aria-hidden="true" tabindex="-1"></a>             <span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> t16 <span class="kw">AS</span> _ <span class="kw">WHERE</span> <span class="ot">&quot;f0&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)</span>
<span id="cb3-604"><a href="#cb3-604" aria-hidden="true" tabindex="-1"></a>            <span class="kw">AS</span> _)</span>
<span id="cb3-605"><a href="#cb3-605" aria-hidden="true" tabindex="-1"></a>           <span class="kw">AS</span> _</span>
<span id="cb3-606"><a href="#cb3-606" aria-hidden="true" tabindex="-1"></a>           <span class="kw">UNION</span></span>
<span id="cb3-607"><a href="#cb3-607" aria-hidden="true" tabindex="-1"></a>           <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-608"><a href="#cb3-608" aria-hidden="true" tabindex="-1"></a>           <span class="kw">FROM</span></span>
<span id="cb3-609"><a href="#cb3-609" aria-hidden="true" tabindex="-1"></a>           (<span class="kw">SELECT</span></span>
<span id="cb3-610"><a href="#cb3-610" aria-hidden="true" tabindex="-1"></a>            <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f0, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f1, f1 <span class="kw">AS</span> f2, f2 <span class="kw">AS</span> f3</span>
<span id="cb3-611"><a href="#cb3-611" aria-hidden="true" tabindex="-1"></a>            <span class="kw">FROM</span></span>
<span id="cb3-612"><a href="#cb3-612" aria-hidden="true" tabindex="-1"></a>            (<span class="co">-- dist2</span></span>
<span id="cb3-613"><a href="#cb3-613" aria-hidden="true" tabindex="-1"></a>             <span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> t16 <span class="kw">AS</span> _ <span class="kw">WHERE</span> <span class="ot">&quot;f1&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)</span>
<span id="cb3-614"><a href="#cb3-614" aria-hidden="true" tabindex="-1"></a>            <span class="kw">AS</span> _)</span>
<span id="cb3-615"><a href="#cb3-615" aria-hidden="true" tabindex="-1"></a>           <span class="kw">AS</span> _)</span>
<span id="cb3-616"><a href="#cb3-616" aria-hidden="true" tabindex="-1"></a>          <span class="kw">AS</span> _)</span>
<span id="cb3-617"><a href="#cb3-617" aria-hidden="true" tabindex="-1"></a>         <span class="kw">AS</span> _)</span>
<span id="cb3-618"><a href="#cb3-618" aria-hidden="true" tabindex="-1"></a>        <span class="kw">AS</span> _)</span>
<span id="cb3-619"><a href="#cb3-619" aria-hidden="true" tabindex="-1"></a>       <span class="kw">AS</span> _</span>
<span id="cb3-620"><a href="#cb3-620" aria-hidden="true" tabindex="-1"></a>       <span class="kw">WHERE</span></span>
<span id="cb3-621"><a href="#cb3-621" aria-hidden="true" tabindex="-1"></a>       (<span class="ot">&quot;f2&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>) <span class="kw">AND</span> (<span class="ot">&quot;f3&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>))</span>
<span id="cb3-622"><a href="#cb3-622" aria-hidden="true" tabindex="-1"></a>      <span class="kw">AS</span> _)</span>
<span id="cb3-623"><a href="#cb3-623" aria-hidden="true" tabindex="-1"></a>     <span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> recursion <span class="kw">ORDER</span> <span class="kw">BY</span> step <span class="kw">DESC</span> <span class="kw">LIMIT</span> <span class="dv">1</span>)</span>
<span id="cb3-624"><a href="#cb3-624" aria-hidden="true" tabindex="-1"></a>    <span class="kw">AS</span> _)</span>
<span id="cb3-625"><a href="#cb3-625" aria-hidden="true" tabindex="-1"></a>   <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-626"><a href="#cb3-626" aria-hidden="true" tabindex="-1"></a>   <span class="kw">FROM</span></span>
<span id="cb3-627"><a href="#cb3-627" aria-hidden="true" tabindex="-1"></a>   (<span class="kw">WITH</span> t26 <span class="kw">AS</span></span>
<span id="cb3-628"><a href="#cb3-628" aria-hidden="true" tabindex="-1"></a>    (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-629"><a href="#cb3-629" aria-hidden="true" tabindex="-1"></a>     <span class="kw">FROM</span></span>
<span id="cb3-630"><a href="#cb3-630" aria-hidden="true" tabindex="-1"></a>     (<span class="co">-- undist</span></span>
<span id="cb3-631"><a href="#cb3-631" aria-hidden="true" tabindex="-1"></a>      <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-632"><a href="#cb3-632" aria-hidden="true" tabindex="-1"></a>      <span class="kw">FROM</span></span>
<span id="cb3-633"><a href="#cb3-633" aria-hidden="true" tabindex="-1"></a>      (<span class="kw">SELECT</span></span>
<span id="cb3-634"><a href="#cb3-634" aria-hidden="true" tabindex="-1"></a>       f0 <span class="kw">AS</span> f0, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f1, f1 <span class="kw">AS</span> f2</span>
<span id="cb3-635"><a href="#cb3-635" aria-hidden="true" tabindex="-1"></a>       <span class="kw">FROM</span></span>
<span id="cb3-636"><a href="#cb3-636" aria-hidden="true" tabindex="-1"></a>       (<span class="co">-- undist1</span></span>
<span id="cb3-637"><a href="#cb3-637" aria-hidden="true" tabindex="-1"></a>        <span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> t0 <span class="kw">AS</span> _ <span class="kw">WHERE</span> <span class="ot">&quot;f0&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)</span>
<span id="cb3-638"><a href="#cb3-638" aria-hidden="true" tabindex="-1"></a>       <span class="kw">AS</span> _)</span>
<span id="cb3-639"><a href="#cb3-639" aria-hidden="true" tabindex="-1"></a>      <span class="kw">AS</span> _</span>
<span id="cb3-640"><a href="#cb3-640" aria-hidden="true" tabindex="-1"></a>      <span class="kw">UNION</span></span>
<span id="cb3-641"><a href="#cb3-641" aria-hidden="true" tabindex="-1"></a>      <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-642"><a href="#cb3-642" aria-hidden="true" tabindex="-1"></a>      <span class="kw">FROM</span></span>
<span id="cb3-643"><a href="#cb3-643" aria-hidden="true" tabindex="-1"></a>      (<span class="kw">SELECT</span></span>
<span id="cb3-644"><a href="#cb3-644" aria-hidden="true" tabindex="-1"></a>       <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f0, f2 <span class="kw">AS</span> f1, f3 <span class="kw">AS</span> f2</span>
<span id="cb3-645"><a href="#cb3-645" aria-hidden="true" tabindex="-1"></a>       <span class="kw">FROM</span></span>
<span id="cb3-646"><a href="#cb3-646" aria-hidden="true" tabindex="-1"></a>       (<span class="co">-- dist2</span></span>
<span id="cb3-647"><a href="#cb3-647" aria-hidden="true" tabindex="-1"></a>        <span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> t0 <span class="kw">AS</span> _ <span class="kw">WHERE</span> <span class="ot">&quot;f2&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)</span>
<span id="cb3-648"><a href="#cb3-648" aria-hidden="true" tabindex="-1"></a>       <span class="kw">AS</span> _)</span>
<span id="cb3-649"><a href="#cb3-649" aria-hidden="true" tabindex="-1"></a>      <span class="kw">AS</span> _)</span>
<span id="cb3-650"><a href="#cb3-650" aria-hidden="true" tabindex="-1"></a>     <span class="kw">AS</span> _)</span>
<span id="cb3-651"><a href="#cb3-651" aria-hidden="true" tabindex="-1"></a>    <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-652"><a href="#cb3-652" aria-hidden="true" tabindex="-1"></a>    <span class="kw">FROM</span></span>
<span id="cb3-653"><a href="#cb3-653" aria-hidden="true" tabindex="-1"></a>    (<span class="kw">WITH</span> t27 <span class="kw">AS</span></span>
<span id="cb3-654"><a href="#cb3-654" aria-hidden="true" tabindex="-1"></a>     (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-655"><a href="#cb3-655" aria-hidden="true" tabindex="-1"></a>      <span class="kw">FROM</span></span>
<span id="cb3-656"><a href="#cb3-656" aria-hidden="true" tabindex="-1"></a>      (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-657"><a href="#cb3-657" aria-hidden="true" tabindex="-1"></a>       <span class="kw">FROM</span></span>
<span id="cb3-658"><a href="#cb3-658" aria-hidden="true" tabindex="-1"></a>       (<span class="kw">SELECT</span></span>
<span id="cb3-659"><a href="#cb3-659" aria-hidden="true" tabindex="-1"></a>        f0 <span class="kw">AS</span> f0, f1 <span class="kw">AS</span> f1</span>
<span id="cb3-660"><a href="#cb3-660" aria-hidden="true" tabindex="-1"></a>        <span class="kw">FROM</span></span>
<span id="cb3-661"><a href="#cb3-661" aria-hidden="true" tabindex="-1"></a>        (<span class="kw">WITH</span> t28 <span class="kw">AS</span></span>
<span id="cb3-662"><a href="#cb3-662" aria-hidden="true" tabindex="-1"></a>         (<span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> t26 <span class="kw">AS</span> _)</span>
<span id="cb3-663"><a href="#cb3-663" aria-hidden="true" tabindex="-1"></a>         <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-664"><a href="#cb3-664" aria-hidden="true" tabindex="-1"></a>         <span class="kw">FROM</span></span>
<span id="cb3-665"><a href="#cb3-665" aria-hidden="true" tabindex="-1"></a>         (<span class="kw">WITH</span> t29 <span class="kw">AS</span></span>
<span id="cb3-666"><a href="#cb3-666" aria-hidden="true" tabindex="-1"></a>          (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-667"><a href="#cb3-667" aria-hidden="true" tabindex="-1"></a>           <span class="kw">FROM</span></span>
<span id="cb3-668"><a href="#cb3-668" aria-hidden="true" tabindex="-1"></a>           (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-669"><a href="#cb3-669" aria-hidden="true" tabindex="-1"></a>            <span class="kw">FROM</span></span>
<span id="cb3-670"><a href="#cb3-670" aria-hidden="true" tabindex="-1"></a>            (<span class="kw">SELECT</span></span>
<span id="cb3-671"><a href="#cb3-671" aria-hidden="true" tabindex="-1"></a>             f0 <span class="kw">AS</span> f0</span>
<span id="cb3-672"><a href="#cb3-672" aria-hidden="true" tabindex="-1"></a>             <span class="kw">FROM</span></span>
<span id="cb3-673"><a href="#cb3-673" aria-hidden="true" tabindex="-1"></a>             (<span class="kw">WITH</span> t30 <span class="kw">AS</span></span>
<span id="cb3-674"><a href="#cb3-674" aria-hidden="true" tabindex="-1"></a>              (<span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> (<span class="kw">SELECT</span> f0 <span class="kw">AS</span> f0, f1 <span class="kw">AS</span> f1 <span class="kw">FROM</span> t28 <span class="kw">AS</span> _) <span class="kw">AS</span> _)</span>
<span id="cb3-675"><a href="#cb3-675" aria-hidden="true" tabindex="-1"></a>              <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-676"><a href="#cb3-676" aria-hidden="true" tabindex="-1"></a>              <span class="kw">FROM</span></span>
<span id="cb3-677"><a href="#cb3-677" aria-hidden="true" tabindex="-1"></a>              (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-678"><a href="#cb3-678" aria-hidden="true" tabindex="-1"></a>               <span class="kw">FROM</span></span>
<span id="cb3-679"><a href="#cb3-679" aria-hidden="true" tabindex="-1"></a>               (<span class="kw">SELECT</span></span>
<span id="cb3-680"><a href="#cb3-680" aria-hidden="true" tabindex="-1"></a>                f0 <span class="kw">AS</span> f0</span>
<span id="cb3-681"><a href="#cb3-681" aria-hidden="true" tabindex="-1"></a>                <span class="kw">FROM</span></span>
<span id="cb3-682"><a href="#cb3-682" aria-hidden="true" tabindex="-1"></a>                (<span class="co">-- join1</span></span>
<span id="cb3-683"><a href="#cb3-683" aria-hidden="true" tabindex="-1"></a>                 <span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> t30 <span class="kw">AS</span> _ <span class="kw">WHERE</span> <span class="ot">&quot;f0&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)</span>
<span id="cb3-684"><a href="#cb3-684" aria-hidden="true" tabindex="-1"></a>                <span class="kw">AS</span> _)</span>
<span id="cb3-685"><a href="#cb3-685" aria-hidden="true" tabindex="-1"></a>               <span class="kw">AS</span> _</span>
<span id="cb3-686"><a href="#cb3-686" aria-hidden="true" tabindex="-1"></a>               <span class="kw">UNION</span></span>
<span id="cb3-687"><a href="#cb3-687" aria-hidden="true" tabindex="-1"></a>               <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-688"><a href="#cb3-688" aria-hidden="true" tabindex="-1"></a>               <span class="kw">FROM</span></span>
<span id="cb3-689"><a href="#cb3-689" aria-hidden="true" tabindex="-1"></a>               (<span class="kw">SELECT</span></span>
<span id="cb3-690"><a href="#cb3-690" aria-hidden="true" tabindex="-1"></a>                f1 <span class="kw">AS</span> f0</span>
<span id="cb3-691"><a href="#cb3-691" aria-hidden="true" tabindex="-1"></a>                <span class="kw">FROM</span></span>
<span id="cb3-692"><a href="#cb3-692" aria-hidden="true" tabindex="-1"></a>                (<span class="co">-- join2</span></span>
<span id="cb3-693"><a href="#cb3-693" aria-hidden="true" tabindex="-1"></a>                 <span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> t30 <span class="kw">AS</span> _ <span class="kw">WHERE</span> <span class="ot">&quot;f1&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)</span>
<span id="cb3-694"><a href="#cb3-694" aria-hidden="true" tabindex="-1"></a>                <span class="kw">AS</span> _)</span>
<span id="cb3-695"><a href="#cb3-695" aria-hidden="true" tabindex="-1"></a>               <span class="kw">AS</span> _)</span>
<span id="cb3-696"><a href="#cb3-696" aria-hidden="true" tabindex="-1"></a>              <span class="kw">AS</span> _)</span>
<span id="cb3-697"><a href="#cb3-697" aria-hidden="true" tabindex="-1"></a>             <span class="kw">AS</span> _)</span>
<span id="cb3-698"><a href="#cb3-698" aria-hidden="true" tabindex="-1"></a>            <span class="kw">AS</span> _</span>
<span id="cb3-699"><a href="#cb3-699" aria-hidden="true" tabindex="-1"></a>            <span class="kw">CROSS</span> <span class="kw">JOIN</span></span>
<span id="cb3-700"><a href="#cb3-700" aria-hidden="true" tabindex="-1"></a>            (<span class="kw">SELECT</span> f0 <span class="kw">AS</span> f1, f1 <span class="kw">AS</span> f2, f2 <span class="kw">AS</span> f3 <span class="kw">FROM</span> t28 <span class="kw">AS</span> _))</span>
<span id="cb3-701"><a href="#cb3-701" aria-hidden="true" tabindex="-1"></a>           <span class="kw">AS</span> _)</span>
<span id="cb3-702"><a href="#cb3-702" aria-hidden="true" tabindex="-1"></a>          <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-703"><a href="#cb3-703" aria-hidden="true" tabindex="-1"></a>          <span class="kw">FROM</span></span>
<span id="cb3-704"><a href="#cb3-704" aria-hidden="true" tabindex="-1"></a>          (<span class="kw">WITH</span> t31 <span class="kw">AS</span></span>
<span id="cb3-705"><a href="#cb3-705" aria-hidden="true" tabindex="-1"></a>           (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-706"><a href="#cb3-706" aria-hidden="true" tabindex="-1"></a>            <span class="kw">FROM</span></span>
<span id="cb3-707"><a href="#cb3-707" aria-hidden="true" tabindex="-1"></a>            (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-708"><a href="#cb3-708" aria-hidden="true" tabindex="-1"></a>             <span class="kw">FROM</span></span>
<span id="cb3-709"><a href="#cb3-709" aria-hidden="true" tabindex="-1"></a>             (<span class="kw">SELECT</span></span>
<span id="cb3-710"><a href="#cb3-710" aria-hidden="true" tabindex="-1"></a>              f0 <span class="kw">AS</span> f0, f1 <span class="kw">AS</span> f1</span>
<span id="cb3-711"><a href="#cb3-711" aria-hidden="true" tabindex="-1"></a>              <span class="kw">FROM</span></span>
<span id="cb3-712"><a href="#cb3-712" aria-hidden="true" tabindex="-1"></a>              (<span class="kw">WITH</span> t32 <span class="kw">AS</span></span>
<span id="cb3-713"><a href="#cb3-713" aria-hidden="true" tabindex="-1"></a>               (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-714"><a href="#cb3-714" aria-hidden="true" tabindex="-1"></a>                <span class="kw">FROM</span></span>
<span id="cb3-715"><a href="#cb3-715" aria-hidden="true" tabindex="-1"></a>                (<span class="kw">SELECT</span></span>
<span id="cb3-716"><a href="#cb3-716" aria-hidden="true" tabindex="-1"></a>                 f0 <span class="op">-</span> f1 <span class="kw">AS</span> f0</span>
<span id="cb3-717"><a href="#cb3-717" aria-hidden="true" tabindex="-1"></a>                 <span class="kw">FROM</span></span>
<span id="cb3-718"><a href="#cb3-718" aria-hidden="true" tabindex="-1"></a>                 (<span class="kw">WITH</span> t33 <span class="kw">AS</span></span>
<span id="cb3-719"><a href="#cb3-719" aria-hidden="true" tabindex="-1"></a>                  (<span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> t29 <span class="kw">AS</span> _)</span>
<span id="cb3-720"><a href="#cb3-720" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-721"><a href="#cb3-721" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">FROM</span></span>
<span id="cb3-722"><a href="#cb3-722" aria-hidden="true" tabindex="-1"></a>                  (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-723"><a href="#cb3-723" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">FROM</span></span>
<span id="cb3-724"><a href="#cb3-724" aria-hidden="true" tabindex="-1"></a>                   (<span class="kw">SELECT</span> f0 <span class="kw">AS</span> f0 <span class="kw">FROM</span> (<span class="kw">SELECT</span> f0 <span class="kw">AS</span> f0 <span class="kw">FROM</span> t33 <span class="kw">AS</span> _) <span class="kw">AS</span> _)</span>
<span id="cb3-725"><a href="#cb3-725" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">AS</span> _</span>
<span id="cb3-726"><a href="#cb3-726" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">CROSS</span> <span class="kw">JOIN</span></span>
<span id="cb3-727"><a href="#cb3-727" aria-hidden="true" tabindex="-1"></a>                   (<span class="kw">SELECT</span> f0 <span class="kw">AS</span> f1 <span class="kw">FROM</span> (<span class="kw">SELECT</span> <span class="dv">100</span> <span class="kw">as</span> f0 <span class="kw">FROM</span> t33 <span class="kw">AS</span> _) <span class="kw">AS</span> _))</span>
<span id="cb3-728"><a href="#cb3-728" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">AS</span> _)</span>
<span id="cb3-729"><a href="#cb3-729" aria-hidden="true" tabindex="-1"></a>                 <span class="kw">AS</span> _)</span>
<span id="cb3-730"><a href="#cb3-730" aria-hidden="true" tabindex="-1"></a>                <span class="kw">AS</span> _)</span>
<span id="cb3-731"><a href="#cb3-731" aria-hidden="true" tabindex="-1"></a>               <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-732"><a href="#cb3-732" aria-hidden="true" tabindex="-1"></a>               <span class="kw">FROM</span></span>
<span id="cb3-733"><a href="#cb3-733" aria-hidden="true" tabindex="-1"></a>               (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-734"><a href="#cb3-734" aria-hidden="true" tabindex="-1"></a>                <span class="kw">FROM</span></span>
<span id="cb3-735"><a href="#cb3-735" aria-hidden="true" tabindex="-1"></a>                (<span class="kw">SELECT</span></span>
<span id="cb3-736"><a href="#cb3-736" aria-hidden="true" tabindex="-1"></a>                 <span class="fu">abs</span>(f0) <span class="kw">as</span> f0, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">as</span> f1</span>
<span id="cb3-737"><a href="#cb3-737" aria-hidden="true" tabindex="-1"></a>                 <span class="kw">FROM</span></span>
<span id="cb3-738"><a href="#cb3-738" aria-hidden="true" tabindex="-1"></a>                 t32</span>
<span id="cb3-739"><a href="#cb3-739" aria-hidden="true" tabindex="-1"></a>                 <span class="kw">AS</span> _</span>
<span id="cb3-740"><a href="#cb3-740" aria-hidden="true" tabindex="-1"></a>                 <span class="kw">WHERE</span></span>
<span id="cb3-741"><a href="#cb3-741" aria-hidden="true" tabindex="-1"></a>                 f0 <span class="op">&lt;</span> <span class="dv">0</span>)</span>
<span id="cb3-742"><a href="#cb3-742" aria-hidden="true" tabindex="-1"></a>                <span class="kw">AS</span> _</span>
<span id="cb3-743"><a href="#cb3-743" aria-hidden="true" tabindex="-1"></a>                <span class="kw">UNION</span></span>
<span id="cb3-744"><a href="#cb3-744" aria-hidden="true" tabindex="-1"></a>                <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-745"><a href="#cb3-745" aria-hidden="true" tabindex="-1"></a>                <span class="kw">FROM</span></span>
<span id="cb3-746"><a href="#cb3-746" aria-hidden="true" tabindex="-1"></a>                (<span class="kw">SELECT</span> <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">as</span> f0, f0 <span class="kw">as</span> f1 <span class="kw">FROM</span> t32 <span class="kw">AS</span> _ <span class="kw">WHERE</span> f0 <span class="op">&gt;=</span> <span class="dv">0</span>)</span>
<span id="cb3-747"><a href="#cb3-747" aria-hidden="true" tabindex="-1"></a>                <span class="kw">AS</span> _)</span>
<span id="cb3-748"><a href="#cb3-748" aria-hidden="true" tabindex="-1"></a>               <span class="kw">AS</span> _)</span>
<span id="cb3-749"><a href="#cb3-749" aria-hidden="true" tabindex="-1"></a>              <span class="kw">AS</span> _)</span>
<span id="cb3-750"><a href="#cb3-750" aria-hidden="true" tabindex="-1"></a>             <span class="kw">AS</span> _</span>
<span id="cb3-751"><a href="#cb3-751" aria-hidden="true" tabindex="-1"></a>             <span class="kw">CROSS</span> <span class="kw">JOIN</span></span>
<span id="cb3-752"><a href="#cb3-752" aria-hidden="true" tabindex="-1"></a>             (<span class="kw">SELECT</span> f0 <span class="kw">AS</span> f2, f1 <span class="kw">AS</span> f3, f2 <span class="kw">AS</span> f4, f3 <span class="kw">AS</span> f5 <span class="kw">FROM</span> t29 <span class="kw">AS</span> _))</span>
<span id="cb3-753"><a href="#cb3-753" aria-hidden="true" tabindex="-1"></a>            <span class="kw">AS</span> _)</span>
<span id="cb3-754"><a href="#cb3-754" aria-hidden="true" tabindex="-1"></a>           <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-755"><a href="#cb3-755" aria-hidden="true" tabindex="-1"></a>           <span class="kw">FROM</span></span>
<span id="cb3-756"><a href="#cb3-756" aria-hidden="true" tabindex="-1"></a>           (<span class="kw">WITH</span> t34 <span class="kw">AS</span></span>
<span id="cb3-757"><a href="#cb3-757" aria-hidden="true" tabindex="-1"></a>            (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-758"><a href="#cb3-758" aria-hidden="true" tabindex="-1"></a>             <span class="kw">FROM</span></span>
<span id="cb3-759"><a href="#cb3-759" aria-hidden="true" tabindex="-1"></a>             (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-760"><a href="#cb3-760" aria-hidden="true" tabindex="-1"></a>              <span class="kw">FROM</span></span>
<span id="cb3-761"><a href="#cb3-761" aria-hidden="true" tabindex="-1"></a>              (<span class="kw">SELECT</span></span>
<span id="cb3-762"><a href="#cb3-762" aria-hidden="true" tabindex="-1"></a>               f0 <span class="kw">AS</span> f0, f1 <span class="kw">AS</span> f1</span>
<span id="cb3-763"><a href="#cb3-763" aria-hidden="true" tabindex="-1"></a>               <span class="kw">FROM</span></span>
<span id="cb3-764"><a href="#cb3-764" aria-hidden="true" tabindex="-1"></a>               (<span class="kw">SELECT</span> f0 <span class="kw">AS</span> f0, f1 <span class="kw">AS</span> f1 <span class="kw">FROM</span> t31 <span class="kw">AS</span> _)</span>
<span id="cb3-765"><a href="#cb3-765" aria-hidden="true" tabindex="-1"></a>               <span class="kw">AS</span> _)</span>
<span id="cb3-766"><a href="#cb3-766" aria-hidden="true" tabindex="-1"></a>              <span class="kw">AS</span> _</span>
<span id="cb3-767"><a href="#cb3-767" aria-hidden="true" tabindex="-1"></a>              <span class="kw">CROSS</span> <span class="kw">JOIN</span></span>
<span id="cb3-768"><a href="#cb3-768" aria-hidden="true" tabindex="-1"></a>              (<span class="kw">SELECT</span></span>
<span id="cb3-769"><a href="#cb3-769" aria-hidden="true" tabindex="-1"></a>               f0 <span class="kw">AS</span> f2, f1 <span class="kw">AS</span> f3, f2 <span class="kw">AS</span> f4, f3 <span class="kw">AS</span> f5, f4 <span class="kw">AS</span> f6, f5 <span class="kw">AS</span> f7</span>
<span id="cb3-770"><a href="#cb3-770" aria-hidden="true" tabindex="-1"></a>               <span class="kw">FROM</span></span>
<span id="cb3-771"><a href="#cb3-771" aria-hidden="true" tabindex="-1"></a>               t31</span>
<span id="cb3-772"><a href="#cb3-772" aria-hidden="true" tabindex="-1"></a>               <span class="kw">AS</span> _))</span>
<span id="cb3-773"><a href="#cb3-773" aria-hidden="true" tabindex="-1"></a>             <span class="kw">AS</span> _)</span>
<span id="cb3-774"><a href="#cb3-774" aria-hidden="true" tabindex="-1"></a>            <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-775"><a href="#cb3-775" aria-hidden="true" tabindex="-1"></a>            <span class="kw">FROM</span></span>
<span id="cb3-776"><a href="#cb3-776" aria-hidden="true" tabindex="-1"></a>            (<span class="kw">WITH</span> t35 <span class="kw">AS</span></span>
<span id="cb3-777"><a href="#cb3-777" aria-hidden="true" tabindex="-1"></a>             (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-778"><a href="#cb3-778" aria-hidden="true" tabindex="-1"></a>              <span class="kw">FROM</span></span>
<span id="cb3-779"><a href="#cb3-779" aria-hidden="true" tabindex="-1"></a>              (<span class="co">-- dist</span></span>
<span id="cb3-780"><a href="#cb3-780" aria-hidden="true" tabindex="-1"></a>               <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-781"><a href="#cb3-781" aria-hidden="true" tabindex="-1"></a>               <span class="kw">FROM</span></span>
<span id="cb3-782"><a href="#cb3-782" aria-hidden="true" tabindex="-1"></a>               (<span class="kw">SELECT</span></span>
<span id="cb3-783"><a href="#cb3-783" aria-hidden="true" tabindex="-1"></a>                f0 <span class="kw">AS</span> f0, f2 <span class="kw">AS</span> f1, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f10, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f11, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f12, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f13, f3 <span class="kw">AS</span> f2, f4 <span class="kw">AS</span> f3, f5 <span class="kw">AS</span> f4, f6 <span class="kw">AS</span> f5, f7 <span class="kw">AS</span> f6, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f7, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f8, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f9</span>
<span id="cb3-784"><a href="#cb3-784" aria-hidden="true" tabindex="-1"></a>                <span class="kw">FROM</span></span>
<span id="cb3-785"><a href="#cb3-785" aria-hidden="true" tabindex="-1"></a>                (<span class="co">-- dist1</span></span>
<span id="cb3-786"><a href="#cb3-786" aria-hidden="true" tabindex="-1"></a>                 <span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> t34 <span class="kw">AS</span> _ <span class="kw">WHERE</span> <span class="ot">&quot;f0&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)</span>
<span id="cb3-787"><a href="#cb3-787" aria-hidden="true" tabindex="-1"></a>                <span class="kw">AS</span> _)</span>
<span id="cb3-788"><a href="#cb3-788" aria-hidden="true" tabindex="-1"></a>               <span class="kw">AS</span> _</span>
<span id="cb3-789"><a href="#cb3-789" aria-hidden="true" tabindex="-1"></a>               <span class="kw">UNION</span></span>
<span id="cb3-790"><a href="#cb3-790" aria-hidden="true" tabindex="-1"></a>               <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-791"><a href="#cb3-791" aria-hidden="true" tabindex="-1"></a>               <span class="kw">FROM</span></span>
<span id="cb3-792"><a href="#cb3-792" aria-hidden="true" tabindex="-1"></a>               (<span class="kw">SELECT</span></span>
<span id="cb3-793"><a href="#cb3-793" aria-hidden="true" tabindex="-1"></a>                <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f0, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f1, f4 <span class="kw">AS</span> f10, f5 <span class="kw">AS</span> f11, f6 <span class="kw">AS</span> f12, f7 <span class="kw">AS</span> f13, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f2, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f3, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f4, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f5, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f6, f1 <span class="kw">AS</span> f7, f2 <span class="kw">AS</span> f8, f3 <span class="kw">AS</span> f9</span>
<span id="cb3-794"><a href="#cb3-794" aria-hidden="true" tabindex="-1"></a>                <span class="kw">FROM</span></span>
<span id="cb3-795"><a href="#cb3-795" aria-hidden="true" tabindex="-1"></a>                (<span class="co">-- dist2</span></span>
<span id="cb3-796"><a href="#cb3-796" aria-hidden="true" tabindex="-1"></a>                 <span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> t34 <span class="kw">AS</span> _ <span class="kw">WHERE</span> <span class="ot">&quot;f1&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)</span>
<span id="cb3-797"><a href="#cb3-797" aria-hidden="true" tabindex="-1"></a>                <span class="kw">AS</span> _)</span>
<span id="cb3-798"><a href="#cb3-798" aria-hidden="true" tabindex="-1"></a>               <span class="kw">AS</span> _)</span>
<span id="cb3-799"><a href="#cb3-799" aria-hidden="true" tabindex="-1"></a>              <span class="kw">AS</span> _)</span>
<span id="cb3-800"><a href="#cb3-800" aria-hidden="true" tabindex="-1"></a>             <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-801"><a href="#cb3-801" aria-hidden="true" tabindex="-1"></a>             <span class="kw">FROM</span></span>
<span id="cb3-802"><a href="#cb3-802" aria-hidden="true" tabindex="-1"></a>             (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-803"><a href="#cb3-803" aria-hidden="true" tabindex="-1"></a>              <span class="kw">FROM</span></span>
<span id="cb3-804"><a href="#cb3-804" aria-hidden="true" tabindex="-1"></a>              (<span class="kw">SELECT</span></span>
<span id="cb3-805"><a href="#cb3-805" aria-hidden="true" tabindex="-1"></a>               <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f0, f0 <span class="kw">AS</span> f1</span>
<span id="cb3-806"><a href="#cb3-806" aria-hidden="true" tabindex="-1"></a>               <span class="kw">FROM</span></span>
<span id="cb3-807"><a href="#cb3-807" aria-hidden="true" tabindex="-1"></a>               (<span class="kw">SELECT</span></span>
<span id="cb3-808"><a href="#cb3-808" aria-hidden="true" tabindex="-1"></a>                f0 <span class="op">+</span> f1 <span class="kw">AS</span> f0</span>
<span id="cb3-809"><a href="#cb3-809" aria-hidden="true" tabindex="-1"></a>                <span class="kw">FROM</span></span>
<span id="cb3-810"><a href="#cb3-810" aria-hidden="true" tabindex="-1"></a>                (<span class="kw">WITH</span> t36 <span class="kw">AS</span></span>
<span id="cb3-811"><a href="#cb3-811" aria-hidden="true" tabindex="-1"></a>                 (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-812"><a href="#cb3-812" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">FROM</span></span>
<span id="cb3-813"><a href="#cb3-813" aria-hidden="true" tabindex="-1"></a>                  (<span class="kw">SELECT</span></span>
<span id="cb3-814"><a href="#cb3-814" aria-hidden="true" tabindex="-1"></a>                   f0 <span class="kw">AS</span> f0, f1 <span class="kw">AS</span> f1, f2 <span class="kw">AS</span> f2, f3 <span class="kw">AS</span> f3, f4 <span class="kw">AS</span> f4, f5 <span class="kw">AS</span> f5, f6 <span class="kw">AS</span> f6</span>
<span id="cb3-815"><a href="#cb3-815" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">FROM</span></span>
<span id="cb3-816"><a href="#cb3-816" aria-hidden="true" tabindex="-1"></a>                   (<span class="co">-- join1</span></span>
<span id="cb3-817"><a href="#cb3-817" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> t35 <span class="kw">AS</span> _</span>
<span id="cb3-818"><a href="#cb3-818" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">WHERE</span></span>
<span id="cb3-819"><a href="#cb3-819" aria-hidden="true" tabindex="-1"></a>                    (<span class="ot">&quot;f0&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>) <span class="kw">AND</span> (((<span class="ot">&quot;f1&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>) <span class="kw">OR</span> (<span class="ot">&quot;f2&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)) <span class="kw">AND</span> ((<span class="ot">&quot;f3&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>) <span class="kw">AND</span> (((<span class="ot">&quot;f4&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>) <span class="kw">OR</span> (<span class="ot">&quot;f5&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)) <span class="kw">AND</span> (<span class="ot">&quot;f6&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)))))</span>
<span id="cb3-820"><a href="#cb3-820" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">AS</span> _)</span>
<span id="cb3-821"><a href="#cb3-821" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">AS</span> _)</span>
<span id="cb3-822"><a href="#cb3-822" aria-hidden="true" tabindex="-1"></a>                 <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-823"><a href="#cb3-823" aria-hidden="true" tabindex="-1"></a>                 <span class="kw">FROM</span></span>
<span id="cb3-824"><a href="#cb3-824" aria-hidden="true" tabindex="-1"></a>                 (<span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-825"><a href="#cb3-825" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">FROM</span></span>
<span id="cb3-826"><a href="#cb3-826" aria-hidden="true" tabindex="-1"></a>                  (<span class="kw">SELECT</span></span>
<span id="cb3-827"><a href="#cb3-827" aria-hidden="true" tabindex="-1"></a>                   f0 <span class="kw">AS</span> f0</span>
<span id="cb3-828"><a href="#cb3-828" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">FROM</span></span>
<span id="cb3-829"><a href="#cb3-829" aria-hidden="true" tabindex="-1"></a>                   (<span class="kw">SELECT</span></span>
<span id="cb3-830"><a href="#cb3-830" aria-hidden="true" tabindex="-1"></a>                    f0 <span class="kw">AS</span> f0</span>
<span id="cb3-831"><a href="#cb3-831" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">FROM</span></span>
<span id="cb3-832"><a href="#cb3-832" aria-hidden="true" tabindex="-1"></a>                    (<span class="kw">SELECT</span></span>
<span id="cb3-833"><a href="#cb3-833" aria-hidden="true" tabindex="-1"></a>                     f2 <span class="kw">AS</span> f0, f3 <span class="kw">AS</span> f1, f4 <span class="kw">AS</span> f2, f5 <span class="kw">AS</span> f3</span>
<span id="cb3-834"><a href="#cb3-834" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">FROM</span></span>
<span id="cb3-835"><a href="#cb3-835" aria-hidden="true" tabindex="-1"></a>                     (<span class="kw">SELECT</span></span>
<span id="cb3-836"><a href="#cb3-836" aria-hidden="true" tabindex="-1"></a>                      f1 <span class="kw">AS</span> f0, f2 <span class="kw">AS</span> f1, f3 <span class="kw">AS</span> f2, f4 <span class="kw">AS</span> f3, f5 <span class="kw">AS</span> f4, f6 <span class="kw">AS</span> f5</span>
<span id="cb3-837"><a href="#cb3-837" aria-hidden="true" tabindex="-1"></a>                      <span class="kw">FROM</span></span>
<span id="cb3-838"><a href="#cb3-838" aria-hidden="true" tabindex="-1"></a>                      t36</span>
<span id="cb3-839"><a href="#cb3-839" aria-hidden="true" tabindex="-1"></a>                      <span class="kw">AS</span> _)</span>
<span id="cb3-840"><a href="#cb3-840" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">AS</span> _)</span>
<span id="cb3-841"><a href="#cb3-841" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">AS</span> _)</span>
<span id="cb3-842"><a href="#cb3-842" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">AS</span> _)</span>
<span id="cb3-843"><a href="#cb3-843" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">AS</span> _</span>
<span id="cb3-844"><a href="#cb3-844" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">CROSS</span> <span class="kw">JOIN</span></span>
<span id="cb3-845"><a href="#cb3-845" aria-hidden="true" tabindex="-1"></a>                  (<span class="kw">SELECT</span> f0 <span class="kw">AS</span> f1 <span class="kw">FROM</span> (<span class="kw">SELECT</span> <span class="dv">1</span> <span class="kw">as</span> f0 <span class="kw">FROM</span> t36 <span class="kw">AS</span> _) <span class="kw">AS</span> _))</span>
<span id="cb3-846"><a href="#cb3-846" aria-hidden="true" tabindex="-1"></a>                 <span class="kw">AS</span> _)</span>
<span id="cb3-847"><a href="#cb3-847" aria-hidden="true" tabindex="-1"></a>                <span class="kw">AS</span> _)</span>
<span id="cb3-848"><a href="#cb3-848" aria-hidden="true" tabindex="-1"></a>               <span class="kw">AS</span> _)</span>
<span id="cb3-849"><a href="#cb3-849" aria-hidden="true" tabindex="-1"></a>              <span class="kw">AS</span> _</span>
<span id="cb3-850"><a href="#cb3-850" aria-hidden="true" tabindex="-1"></a>              <span class="kw">UNION</span></span>
<span id="cb3-851"><a href="#cb3-851" aria-hidden="true" tabindex="-1"></a>              <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-852"><a href="#cb3-852" aria-hidden="true" tabindex="-1"></a>              <span class="kw">FROM</span></span>
<span id="cb3-853"><a href="#cb3-853" aria-hidden="true" tabindex="-1"></a>              (<span class="kw">SELECT</span></span>
<span id="cb3-854"><a href="#cb3-854" aria-hidden="true" tabindex="-1"></a>               f0 <span class="kw">AS</span> f0, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f1</span>
<span id="cb3-855"><a href="#cb3-855" aria-hidden="true" tabindex="-1"></a>               <span class="kw">FROM</span></span>
<span id="cb3-856"><a href="#cb3-856" aria-hidden="true" tabindex="-1"></a>               (<span class="kw">SELECT</span></span>
<span id="cb3-857"><a href="#cb3-857" aria-hidden="true" tabindex="-1"></a>                f0 <span class="kw">AS</span> f0</span>
<span id="cb3-858"><a href="#cb3-858" aria-hidden="true" tabindex="-1"></a>                <span class="kw">FROM</span></span>
<span id="cb3-859"><a href="#cb3-859" aria-hidden="true" tabindex="-1"></a>                (<span class="kw">SELECT</span></span>
<span id="cb3-860"><a href="#cb3-860" aria-hidden="true" tabindex="-1"></a>                 f2 <span class="kw">AS</span> f0, f3 <span class="kw">AS</span> f1, f4 <span class="kw">AS</span> f2, f5 <span class="kw">AS</span> f3</span>
<span id="cb3-861"><a href="#cb3-861" aria-hidden="true" tabindex="-1"></a>                 <span class="kw">FROM</span></span>
<span id="cb3-862"><a href="#cb3-862" aria-hidden="true" tabindex="-1"></a>                 (<span class="kw">SELECT</span></span>
<span id="cb3-863"><a href="#cb3-863" aria-hidden="true" tabindex="-1"></a>                  f1 <span class="kw">AS</span> f0, f2 <span class="kw">AS</span> f1, f3 <span class="kw">AS</span> f2, f4 <span class="kw">AS</span> f3, f5 <span class="kw">AS</span> f4, f6 <span class="kw">AS</span> f5</span>
<span id="cb3-864"><a href="#cb3-864" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">FROM</span></span>
<span id="cb3-865"><a href="#cb3-865" aria-hidden="true" tabindex="-1"></a>                  (<span class="kw">SELECT</span></span>
<span id="cb3-866"><a href="#cb3-866" aria-hidden="true" tabindex="-1"></a>                   f7 <span class="kw">AS</span> f0, f8 <span class="kw">AS</span> f1, f9 <span class="kw">AS</span> f2, f10 <span class="kw">AS</span> f3, f11 <span class="kw">AS</span> f4, f12 <span class="kw">AS</span> f5, f13 <span class="kw">AS</span> f6</span>
<span id="cb3-867"><a href="#cb3-867" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">FROM</span></span>
<span id="cb3-868"><a href="#cb3-868" aria-hidden="true" tabindex="-1"></a>                   (<span class="co">-- join2</span></span>
<span id="cb3-869"><a href="#cb3-869" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> t35 <span class="kw">AS</span> _</span>
<span id="cb3-870"><a href="#cb3-870" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">WHERE</span></span>
<span id="cb3-871"><a href="#cb3-871" aria-hidden="true" tabindex="-1"></a>                    (<span class="ot">&quot;f7&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>) <span class="kw">AND</span> (((<span class="ot">&quot;f8&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>) <span class="kw">OR</span> (<span class="ot">&quot;f9&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)) <span class="kw">AND</span> ((<span class="ot">&quot;f10&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>) <span class="kw">AND</span> (((<span class="ot">&quot;f11&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>) <span class="kw">OR</span> (<span class="ot">&quot;f12&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)) <span class="kw">AND</span> (<span class="ot">&quot;f13&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)))))</span>
<span id="cb3-872"><a href="#cb3-872" aria-hidden="true" tabindex="-1"></a>                   <span class="kw">AS</span> _)</span>
<span id="cb3-873"><a href="#cb3-873" aria-hidden="true" tabindex="-1"></a>                  <span class="kw">AS</span> _)</span>
<span id="cb3-874"><a href="#cb3-874" aria-hidden="true" tabindex="-1"></a>                 <span class="kw">AS</span> _)</span>
<span id="cb3-875"><a href="#cb3-875" aria-hidden="true" tabindex="-1"></a>                <span class="kw">AS</span> _)</span>
<span id="cb3-876"><a href="#cb3-876" aria-hidden="true" tabindex="-1"></a>               <span class="kw">AS</span> _)</span>
<span id="cb3-877"><a href="#cb3-877" aria-hidden="true" tabindex="-1"></a>              <span class="kw">AS</span> _)</span>
<span id="cb3-878"><a href="#cb3-878" aria-hidden="true" tabindex="-1"></a>             <span class="kw">AS</span> _)</span>
<span id="cb3-879"><a href="#cb3-879" aria-hidden="true" tabindex="-1"></a>            <span class="kw">AS</span> _)</span>
<span id="cb3-880"><a href="#cb3-880" aria-hidden="true" tabindex="-1"></a>           <span class="kw">AS</span> _)</span>
<span id="cb3-881"><a href="#cb3-881" aria-hidden="true" tabindex="-1"></a>          <span class="kw">AS</span> _)</span>
<span id="cb3-882"><a href="#cb3-882" aria-hidden="true" tabindex="-1"></a>         <span class="kw">AS</span> _)</span>
<span id="cb3-883"><a href="#cb3-883" aria-hidden="true" tabindex="-1"></a>        <span class="kw">AS</span> _)</span>
<span id="cb3-884"><a href="#cb3-884" aria-hidden="true" tabindex="-1"></a>       <span class="kw">AS</span> _</span>
<span id="cb3-885"><a href="#cb3-885" aria-hidden="true" tabindex="-1"></a>       <span class="kw">CROSS</span> <span class="kw">JOIN</span></span>
<span id="cb3-886"><a href="#cb3-886" aria-hidden="true" tabindex="-1"></a>       (<span class="kw">SELECT</span> f0 <span class="kw">AS</span> f2 <span class="kw">FROM</span> (<span class="kw">SELECT</span> f2 <span class="kw">AS</span> f0 <span class="kw">FROM</span> t26 <span class="kw">AS</span> _) <span class="kw">AS</span> _))</span>
<span id="cb3-887"><a href="#cb3-887" aria-hidden="true" tabindex="-1"></a>      <span class="kw">AS</span> _)</span>
<span id="cb3-888"><a href="#cb3-888" aria-hidden="true" tabindex="-1"></a>     <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-889"><a href="#cb3-889" aria-hidden="true" tabindex="-1"></a>     <span class="kw">FROM</span></span>
<span id="cb3-890"><a href="#cb3-890" aria-hidden="true" tabindex="-1"></a>     (<span class="co">-- dist</span></span>
<span id="cb3-891"><a href="#cb3-891" aria-hidden="true" tabindex="-1"></a>      <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-892"><a href="#cb3-892" aria-hidden="true" tabindex="-1"></a>      <span class="kw">FROM</span></span>
<span id="cb3-893"><a href="#cb3-893" aria-hidden="true" tabindex="-1"></a>      (<span class="kw">SELECT</span></span>
<span id="cb3-894"><a href="#cb3-894" aria-hidden="true" tabindex="-1"></a>       f0 <span class="kw">AS</span> f0, f2 <span class="kw">AS</span> f1, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f2, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f3</span>
<span id="cb3-895"><a href="#cb3-895" aria-hidden="true" tabindex="-1"></a>       <span class="kw">FROM</span></span>
<span id="cb3-896"><a href="#cb3-896" aria-hidden="true" tabindex="-1"></a>       (<span class="co">-- dist1</span></span>
<span id="cb3-897"><a href="#cb3-897" aria-hidden="true" tabindex="-1"></a>        <span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> t27 <span class="kw">AS</span> _ <span class="kw">WHERE</span> <span class="ot">&quot;f0&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)</span>
<span id="cb3-898"><a href="#cb3-898" aria-hidden="true" tabindex="-1"></a>       <span class="kw">AS</span> _)</span>
<span id="cb3-899"><a href="#cb3-899" aria-hidden="true" tabindex="-1"></a>      <span class="kw">AS</span> _</span>
<span id="cb3-900"><a href="#cb3-900" aria-hidden="true" tabindex="-1"></a>      <span class="kw">UNION</span></span>
<span id="cb3-901"><a href="#cb3-901" aria-hidden="true" tabindex="-1"></a>      <span class="kw">SELECT</span> <span class="op">*</span></span>
<span id="cb3-902"><a href="#cb3-902" aria-hidden="true" tabindex="-1"></a>      <span class="kw">FROM</span></span>
<span id="cb3-903"><a href="#cb3-903" aria-hidden="true" tabindex="-1"></a>      (<span class="kw">SELECT</span></span>
<span id="cb3-904"><a href="#cb3-904" aria-hidden="true" tabindex="-1"></a>       <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f0, <span class="kw">NULL</span>:<span class="ch">:integer</span> <span class="kw">AS</span> f1, f1 <span class="kw">AS</span> f2, f2 <span class="kw">AS</span> f3</span>
<span id="cb3-905"><a href="#cb3-905" aria-hidden="true" tabindex="-1"></a>       <span class="kw">FROM</span></span>
<span id="cb3-906"><a href="#cb3-906" aria-hidden="true" tabindex="-1"></a>       (<span class="co">-- dist2</span></span>
<span id="cb3-907"><a href="#cb3-907" aria-hidden="true" tabindex="-1"></a>        <span class="kw">SELECT</span> <span class="op">*</span> <span class="kw">FROM</span> t27 <span class="kw">AS</span> _ <span class="kw">WHERE</span> <span class="ot">&quot;f1&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>)</span>
<span id="cb3-908"><a href="#cb3-908" aria-hidden="true" tabindex="-1"></a>       <span class="kw">AS</span> _)</span>
<span id="cb3-909"><a href="#cb3-909" aria-hidden="true" tabindex="-1"></a>      <span class="kw">AS</span> _)</span>
<span id="cb3-910"><a href="#cb3-910" aria-hidden="true" tabindex="-1"></a>     <span class="kw">AS</span> _)</span>
<span id="cb3-911"><a href="#cb3-911" aria-hidden="true" tabindex="-1"></a>    <span class="kw">AS</span> _)</span>
<span id="cb3-912"><a href="#cb3-912" aria-hidden="true" tabindex="-1"></a>   <span class="kw">AS</span> _)</span>
<span id="cb3-913"><a href="#cb3-913" aria-hidden="true" tabindex="-1"></a>  <span class="kw">AS</span> _</span>
<span id="cb3-914"><a href="#cb3-914" aria-hidden="true" tabindex="-1"></a>  <span class="kw">WHERE</span></span>
<span id="cb3-915"><a href="#cb3-915" aria-hidden="true" tabindex="-1"></a>  (<span class="ot">&quot;f0&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>) <span class="kw">AND</span> (<span class="ot">&quot;f1&quot;</span> <span class="kw">IS</span> <span class="kw">NOT</span> <span class="kw">NULL</span>))</span>
<span id="cb3-916"><a href="#cb3-916" aria-hidden="true" tabindex="-1"></a> <span class="kw">AS</span> _)</span>
<span id="cb3-917"><a href="#cb3-917" aria-hidden="true" tabindex="-1"></a><span class="kw">AS</span> _;</span></code></pre></div>
</details>
<p>It’s not pretty, rather amazingly, running the above query in postgres 17 will in fact return a single row with a single column whose value is 100. And you’d better believe it does it by <em>actually looping its way up to 100.</em> If you don’t believe me, make the following change:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="st">-     SELECT * FROM recursion ORDER BY step DESC LIMIT 1)</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="va">+     SELECT * FROM recursion ORDER BY step DESC)</span></span></code></pre></div>
<p>which will instead return a row for each step of the iteration.</p>
<p>There are some obvious optimizations I could make to the generated SQL, but it didn’t seem worth my time, since that’s not the interesting part of the project.</p>
<h2 id="what-the-hell-is-going-on">What the Hell Is Going On?</h2>
<p>Let’s take some time to discuss the underlying category theory here. I am by no means an expert, but what I have learned after a decade of bashing my head against this stuff is that a little goes a long way.</p>
<p>For our intents and purposes, we have types, and arrows (functions) between types. We always have the identity “do nothing arrow” <code>id</code>:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="fu">id</span><span class="ot">  ::</span> a <span class="op">~&gt;</span> a</span></code></pre></div>
<p>and we can compose arrows by lining up one end to another:<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a></p>
<div class="sourceCode" id="cb6"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a>(⨟)<span class="ot"> ::</span> (a <span class="op">~&gt;</span> b) <span class="ot">-&gt;</span> (b <span class="op">~&gt;</span> c) <span class="ot">-&gt;</span> (a <span class="op">~&gt;</span> c)</span></code></pre></div>
<p>Unlike Haskell (or really any programming language, for that matter), we DO NOT have the notion of function application. That is, there is no arrow:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- doesn&#39;t exist!</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="ot">($) ::</span> (a <span class="op">~&gt;</span> b) <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> b</span></code></pre></div>
<p>You can only compose arrows, you can’t apply them. That’s why we call these things “arrows” rather than “functions.”</p>
<p>There are a bundle of arrows for working with product types. The two projection functions correspond to <code>fst</code> and <code>snd</code>, taking individual components out of pairs:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>prj₁<span class="ot"> ::</span> (a, b) <span class="op">~&gt;</span> a</span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>prj₂<span class="ot"> ::</span> (a, b) <span class="op">~&gt;</span> b</span></code></pre></div>
<p>How do we get things into pairs in the first place? We can use the “fork” operation, which takes two arrows computing <code>b</code> and <code>c</code>, and generates a new arrow which generates a pair of <code>(b, c)</code>:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>(△)<span class="ot">  ::</span> (a <span class="op">~&gt;</span> b) <span class="ot">-&gt;</span> (a <span class="op">~&gt;</span> c) <span class="ot">-&gt;</span> (a <span class="op">~&gt;</span> (b, c))</span></code></pre></div>
<p>If you’re coming from a Haskell background, it’s tempting to think of this operation <em>merely</em> as the <code>(,)</code> pair constructor. But you’ll notice from the type of the computation that there can be no data dependency between <code>b</code> and <code>c</code>, thus we are free to parallelize each side of the pair.</p>
<p>In category theory, the distinction between left and right sides of an arrow is rather arbitrary. This gives rise to a notion called <em>duality</em> where we can flip the arrows around, and get cool new behavior. If we dualize all of our product machinery, we get the <em>coproduct</em> machinery, where a coproduct of <code>a</code> and <code>b</code> is “either <code>a</code> or <code>b</code>, but definitely not both nor neither.”</p>
<p>Swapping the arrow direction of <code>prj₁</code> and <code>prj₂</code>, and replacing <code>(,)</code> with <code>Either</code> gives us the following injections:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="ot">inl ::</span> a <span class="op">~&gt;</span> <span class="dt">Either</span> a b</span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="ot">inr ::</span> b <span class="op">~&gt;</span> <span class="dt">Either</span> a b</span></code></pre></div>
<p>and the following “join” operation for eliminating coproducts:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a>(▽)<span class="ot"> ::</span> (a <span class="op">~&gt;</span> c) <span class="ot">-&gt;</span> (b <span class="op">~&gt;</span> c) <span class="ot">-&gt;</span> (<span class="dt">Either</span> a b <span class="op">~&gt;</span> c)</span></code></pre></div>
<p>Again, coming from Haskell this is just the standard <code>either</code> function. It corresponds to a branch between one of two cases.</p>
<p>As you can see, with just these eight operations, we already have a tremendous amount of expressivity. We can express data dependencies via <code>⨟</code> and branching via <code>▽</code>. With <code>△</code> we automatically encode opportunities for parallelism, and gain the ability to build complicated data structures, with <code>prj₁</code> and <code>prj₂</code> allowing us to get the information <em>back out</em> of the data structures.</p>
<p>You’ll notice in the IL that there are no variable names anywhere to be found. The desugaring of the source language builds a stack (via the <code>something to allocate △ id</code> pattern), and replaces subsequent variable lookups with a series of projections on the stack to find the value again. On one hand, this makes the categorical IL rather hard to read, but it makes it very easy to re-target! Many domains do have a notion of grouping, but don’t have a native notion of naming.</p>
<p>For example, in an electronic circuit, I can have a ribbon of 32 wires which represents an <code>Int32</code>. If I have another ribbon of 32 wires, I can trivially route both wires into a 64-wire ribbon corresponding to a pair of <code>(Int32, Int32)</code>.</p>
<p>By eliminating names before we get to the IL, it means no compiler backend ever needs to deal with names. They can just work on a stack representation, and are free to special-case optimize series of projections if they are able to.</p>
<p>Of particular interest to this discussion is how we desugar loops in catlang. The underlying primitive is <code>cochoice</code>:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="ot">cochoice ::</span> (<span class="dt">Either</span> a c <span class="op">~&gt;</span> <span class="dt">Either</span> b c) <span class="ot">-&gt;</span> (a <span class="op">~&gt;</span> b)</span></code></pre></div>
<p>which magically turns an arrow on <code>Either</code>s into an arrow without the eithers. We obviously must <em>run</em> that arrow on eithers. If that function returns <code>inl</code>, then we’re happy and we can just output that. But if the function returns <code>inr</code>, we have no choice but to pass it back in to the eithered arrow. In Haskell, cochoice is implemented as:</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="ot">cochoiceHask ::</span> (<span class="dt">Either</span> a c <span class="ot">-&gt;</span> <span class="dt">Either</span> b c) <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> c</span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>cochoiceHask f <span class="ot">=</span> go <span class="op">.</span> <span class="dt">Left</span></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a><span class="ot">    go ::</span> <span class="dt">Either</span> a c <span class="ot">-&gt;</span> b</span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a>    go eac <span class="ot">=</span></span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a>      <span class="kw">case</span> f eac <span class="kw">of</span></span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Left</span> b <span class="ot">-&gt;</span> b</span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Right</span> c <span class="ot">-&gt;</span> go (<span class="dt">Right</span> c)</span></code></pre></div>
<p>which as you can see, will loop until <code>f</code> finally returns a <code>Left</code>. What’s neat about this formulation of a loop is that we can statically differentiate between our first and subsequent passes through the loop body. The first time through <code>eac</code> is <code>Left</code>, while for all other times it is <code>Right</code>. We don’t take advantage of it in the original <code>count</code> program, but how many times have you written loop code that needs to initialize something its first time through?</p>
<h2 id="compiling-to-sql">Compiling to SQL</h2>
<p>So that’s the underlying theory behind the IL. How can we compile this to SQL now?</p>
<p>As alluded to before, we simply need to give SQL implementations for each of the operations in the intermediary language. As a simple example, <code>id</code> compiles to <code>SELECT * FROM {}</code>, where <code>{}</code> is the input of the arrow.</p>
<p>The hardest part here was working out a data representation. It seems obvious to encode each element of a product as a new column, but what do we do about coproducts? After much work thought, I decided to flatten out the coproducts. So, for example, the type:</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a>(<span class="dt">Int</span>, <span class="dt">Either</span> <span class="dt">Int</span> <span class="dt">Int</span>)</span></code></pre></div>
<p>would be represented as three columns:</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode sql"><code class="sourceCode sql"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a>( f1 <span class="dt">INT</span> <span class="kw">NOT</span> <span class="kw">NULL</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>, f2 <span class="dt">INT</span></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a>, f3 <span class="dt">INT</span></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a>)</span></code></pre></div>
<p>with the constraint that exactly one of <code>f2</code> or <code>f3</code> would be <code>IS NOT NULL</code> at any given point in time.</p>
<p>With this hammered out, almost everything else is pretty trivial. Composition corresponds to a nested query. Forks are <code>CROSS JOIN</code>s which concatenate the columns of each sub-query. Joins are <code>UNION</code>s, where we add a <code>WHERE field IS NOT NULL</code> clause to enforce we’re looking at the correct coproduct constructor.</p>
<p>Cochoice is the only really tricky thing, but it corresponds to a <a href="https://www.postgresql.org/docs/current/queries-with.html#QUERIES-WITH-RECURSIVE">recursive CTE</a>. Generating a recursive CTE table for the computation isn’t too hard, but getting the final value out of it was surprisingly tricky. The semantics of SQL tables is that they are multisets and come with an arbitrary greatest element. Which is to say, you need an column structured in a relevant way in order to query the final result. Due to some quirks in what postgres accepts, and in how I structured my queries, it was prohibitively hard to insert a “how many times have I looped” column and order by that. So instead I cheated and added a <code>clock_timestamp() as step</code> column which looks at the processor clock and ordered by that.</p>
<p>This is clearly a hack, and presumably will cause problems if I ever add some primitives which generate more than one row, but again, this is just for fun and who cares. Send me a <a href="https://github.com/isovector/catlang">pull request</a> if you’re offended by my chicanery!</p>
<h2 id="stupid-directions-to-go-in-the-future">Stupid Directions To Go In the Future</h2>
<p>I’ve run out of vacation time to work on this project, so I’m probably not going to get around to the meta-circular stupidity I was planning.</p>
<p>The compiler still needs a few string-crunching primitives (which are easy to add), but then it would be simple to write a little <a href="https://en.wikipedia.org/wiki/Brainfuck">brainfuck</a> interpreter in catlang. Which I could then compile to SQL. Now we’ve got a brainfuck interpreter running in postgres. Of course, this has been done by hand before, but to my knowledge, never via compilation.</p>
<p>There exist C to brainfuck compilers. And postgres is written in C. So in a move that would make Xzibit proud, we could run postgres in postgres. And of course, it would be fun to run brainfuck in brainfuck. That’d be a cool catlang backend if someone wanted to contribute such a thing.</p>
<h2 id="notes-and-due-diligence-and-what-have-you">Notes and Due Diligence and What Have You</h2>
<p>I am not the first person to do anything like this. The source language of catlang is heavily inspired by <a href="https://www.staff.city.ac.uk/~ross/papers/notation.pdf">Haskell’s arrow syntax</a>, which in turn is essentially a desugaring algorithm for <a href="https://www.cse.chalmers.se/~rjmh/afp-arrows.pdf">Arrows</a>. Arrows are slightly the wrong abstraction because they require an operation <code>arr :: (a -&gt; b) -&gt; (a ~&gt; b)</code>—which requires you to be able to embed Haskell functions in your category, something which is <em>almost never possible.</em></p>
<p>Unfortunately, arrow syntax in Haskell desugars down to <code>arr</code> for almost everything it does, which in turn makes arrow notation effectively useless. In an ideal world, everything I described in this blog post would be a tiny little Haskell library, with arrow notation doing the heavy lifting. But that is just not the world we live in.</p>
<p>Nor am I the first person to notice that there are categorical semantics behind programming languages. I don’t actually know whom to cite on this one, but it is well-established folklore that the lambda calculus corresponds to <a href="https://en.wikipedia.org/wiki/Cartesian_closed_category">cartesian-closed categories</a>. The “closed” part of “cartesian-closed” means we have an operation <code>eval :: (a ~&gt; b, a) ~&gt; b</code>, but everyone and their dog has implemented the lambda calculus, so I thought it would be fun to see how far we can get without it. This is not a limitation on catlang’s turing completeness (since <code>cochoice</code> gives us everything we need.)</p>
<p>I’ve been thinking about writing a <em>category-first</em> programming language for the better part of a decade, ever since I read <a href="http://conal.net/papers/compiling-to-categories/compiling-to-categories.pdf">Compiling to Categories</a>. That paper takes Haskell and desugars it back down to categories. I stole many of the tricks here from that paper.</p>
<p>Anyway. All of the code is available on <a href="https://github.com/isovector/catlang">github</a> if you’re interested in taking a look. The repo isn’t up to my usual coding standards, for which you have my apologies. Of note is the template-haskell backend which can spit out Haskell code; meaning it wouldn’t be very hard to make a quasiquoter to compile catlang into what Haskell’s arrow desugaring <em>ought to be.</em> If there’s enough clamor for such a thing, I’ll see about turning this part into a library.</p>
<section class="footnotes" role="doc-endnotes">
<hr />
<ol>
<li id="fn1" role="doc-endnote"><p>When looking at the types of arrows in this essay, we make the distinction that <code>~&gt;</code> are arrows that we can write in catlang, while <code>-&gt;</code> exist in the metatheory.<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
        ]]>
      </content>
    </entry>
    <entry>
      <title>Theorems for Free Redux</title>
      <id>blog/theorems-for-free-redux/index.html</id>
      <link href='blog/theorems-for-free-redux/index.html'/>
      <published>2025-10-09T11:27:00Z</published>
      <updated>2025-10-09T11:27:00Z</updated>

      <content type="html" xml:base="https://reasonablypolymorphic.com">
        <![CDATA[
        <p>A reader recently got in touch with me regarding my 2017 blog post <a href="/blog/theorems-for-free/">Review: Theorems for Free</a>. He had some questions about the paper/my review, and upon revisiting it, I realized that I had no idea how the paper worked anymore.</p>
<p>So I decided to rehash my understanding, and came up with something much conceptually clearer about what is happening and why.</p>
<p>A quick summary of <em>Theorems for Free</em>:</p>
<blockquote>
<p>For any polymorphic type, we can generate a law that must hold for any value of that type.</p>
</blockquote>
<p>One the examples given is for the function <code>length :: forall a. [a] -&gt; Int</code>, which states that <code>forall f l. length (fmap f l) = length l</code>—namely, that <code>fmap</code> doesn’t change the length of the list.</p>
<p><em>Theorems for Free</em> gives a roundabout and obtuse set of rules for computing these free theorems. But, as usual, the clarity of the idea is obscured by the encoding details.</p>
<p>The actual idea is this:</p>
<blockquote>
<p>Parametrically-polymorphic functions can’t branch on the specific types they are instantiated at.</p>
</blockquote>
<p>Because of this fact, functions must behave the same way, regardless of the type arguments passed to them. So all of the free theorems have the form “replacing the type variables <em>before</em> calling the function is the same as replacing the type variables <em>after</em> calling the function.”</p>
<p>What does it mean to replace a type variable? Well, if we want to replace a type variable <code>a</code> with <code>a'</code>, we will generate a fresh function <code>f :: a -&gt; a'</code>, and then stick it wherever we need to.</p>
<p>For example, given the function <code>id :: a -&gt; a</code>, we generate the free theorem:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">forall</span> f a<span class="op">.</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>  f (<span class="fu">id</span> a) <span class="ot">=</span> <span class="fu">id</span> (f a)</span></code></pre></div>
<p>or, for the function <code>fromJust :: Maybe a -&gt; a</code>, we get:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">forall</span> f ma<span class="op">.</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>  f (fromJust ma) <span class="ot">=</span> fromJust (<span class="fu">fmap</span> f ma)</span></code></pre></div>
<p>This scheme also works for functions in multiple type parameters. Given the function <code>swap :: (a, b) -&gt; (b, a)</code>, we must replace both <code>a</code> and <code>b</code>, giving the free theorem:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">forall</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>    (<span class="ot">f ::</span> a <span class="ot">-&gt;</span> a&#39;)</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>    (<span class="ot">g ::</span> b <span class="ot">-&gt;</span> b&#39;)</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>    (<span class="ot">p ::</span> (a, b))</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>  swap (bimap f g p) <span class="ot">=</span> bimap g f (swap p)</span></code></pre></div>
<p>In the special case where there are no type parameters, we don’t need to do anything. This is what’s happening in the <code>length</code> example given in the introduction.</p>
<p>Simple stuff, right? The obfuscation in the paper comes from the actual technique given to figure out where to apply these type substitutions. The paper is not fully general here, in that it only gives rules for the <code>[]</code> and <code>(-&gt;)</code> type constructors (if I recall correctly.) These rules are further obscured in that they inline the definitions of <code>fmap</code>, rather than writing <code>fmap</code> directly.<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a> But for types in one variable, <code>fmap</code> is exactly the function that performs type substitution.</p>
<section class="footnotes" role="doc-endnotes">
<hr />
<ol>
<li id="fn1" role="doc-endnote"><p>Perhaps this paper predates typeclasses? Very possible.<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
        ]]>
      </content>
    </entry>
    <entry>
      <title>Analyzing API Design via Algebraic Laws</title>
      <id>blog/api-analysis/index.html</id>
      <link href='blog/api-analysis/index.html'/>
      <published>2025-05-05T07:33:00Z</published>
      <updated>2025-05-05T07:33:00Z</updated>

      <content type="html" xml:base="https://reasonablypolymorphic.com">
        <![CDATA[
        <p>The other day, someone asked:</p>
<blockquote>
<p>Why doesn’t [the Data.Map function] <code>unionWith :: (a -&gt; a -&gt; a) -&gt; Map k a -&gt; Map k a -&gt; Map k a</code> allow for different value types the way <code>intersectionWith :: (a -&gt; b -&gt; c) -&gt; Map k a -&gt; Map k b -&gt; Map k c</code> does?</p>
</blockquote>
<p>This is a very reasonable question, and it lead down an interesting rabbit hole of at the intersection of API design and efficient implementation.</p>
<p>To answer the original question, what would the type of a different value type of <code>unionWith</code> look like? It would be something in the flavor of:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ot">unionWith ::</span> (<span class="dt">Maybe</span> a <span class="ot">-&gt;</span> <span class="dt">Maybe</span> b <span class="ot">-&gt;</span> c) <span class="ot">-&gt;</span> <span class="dt">Map</span> k a <span class="ot">-&gt;</span> <span class="dt">Map</span> k b <span class="ot">-&gt;</span> <span class="dt">Map</span> k c</span></code></pre></div>
<p>But this new <code>Maybe a -&gt; Maybe b -&gt; c</code> parameter is somewhat lossy, in that it gives the impression that it could be called with <code>Nothing Nothing</code> as parameters, which doesn’t fit into the vibe of being a “union.”</p>
<p>So instead we could restrict that possibility by using <code>These a b</code>:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">These</span> a b <span class="ot">=</span> <span class="dt">This</span> a <span class="op">|</span> <span class="dt">That</span> b <span class="op">|</span> <span class="dt">These</span> a b</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="ot">unionWith ::</span> (<span class="dt">These</span> a b <span class="ot">-&gt;</span> c) <span class="ot">-&gt;</span> <span class="dt">Map</span> k a <span class="ot">-&gt;</span> <span class="dt">Map</span> k b <span class="ot">-&gt;</span> <span class="dt">Map</span> k c</span></code></pre></div>
<p>which seems reasonable enough.</p>
<hr />
<p>But let’s take <em>reasonableness</em> out of the picture and start again from first principles. Instead let’s ask ourselves the deep philsophical question of <em>what even IS a map?</em></p>
<p>A <code>Map k v</code> is a particularly efficient implementation of functions with type <code>k -&gt; Maybe v</code>. But why is this <code>Maybe</code> here? It’s really only to encode the “default” value of performing a lookup. Nothing goes wrong if we generalize this to be <code>Monoid v =&gt; k -&gt; v</code>. In fact, it helps us make sense of the right bias present in <code>Data.Map</code>, where we see:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="fu">lookup</span> k (singleton k v1 <span class="op">&lt;&gt;</span> singleton k v2) <span class="ot">=</span> <span class="dt">Just</span> v2</span></code></pre></div>
<p>This equality is hard to justify under the normal understanding of <code>Map k v</code> being an encoding of a function <code>k -&gt; Maybe v</code>. But under the general monoid interpretation, we get a nice semigroup homomorphism:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="fu">lookup</span> k (m1 <span class="op">&lt;&gt;</span> m2) <span class="ot">=</span> <span class="fu">lookup</span> k m1 <span class="op">&lt;&gt;</span> <span class="fu">lookup</span> k m2</span></code></pre></div>
<p>where the monoid in question has been specialized to be <a href="https://hackage.haskell.org/package/base-4.21.0.0/docs/Data-Monoid.html#t:Last"><code>Last</code></a>.</p>
<p>Of course, we also have a monoid homomorphism:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="fu">lookup</span> k <span class="fu">mempty</span> <span class="ot">=</span> <span class="fu">mempty</span></span></code></pre></div>
<p>Let’s re-evaluate the original question in terms of this newly-generalized <code>Map</code>. Now that we’ve removed all of the unnecessary baggage of <code>Maybe</code>, we can again think about the desired type of <code>unionWith</code>:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a>unionWith</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="ot">    ::</span> (a <span class="ot">-&gt;</span> b <span class="ot">-&gt;</span> c)</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>    <span class="ot">-&gt;</span> <span class="dt">Map</span> k a</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>    <span class="ot">-&gt;</span> <span class="dt">Map</span> k b</span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>    <span class="ot">-&gt;</span> <span class="dt">Map</span> k c</span></code></pre></div>
<p>which looks <a href="https://hackage.haskell.org/package/base-4.21.0.0/docs/Prelude.html#v:liftA2">awfully familiar</a>. This new type signature automatically resolves our original concerns about “what should we do if the key isn’t present?”—just call the function with <code>mempty</code> as a parameter!</p>
<p>We can give some semantics as to what <code>unionWith</code> ought to do again by relating it to the observation <code>lookup</code>. The relevant law here seems like it ought to be:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="fu">lookup</span> k (unionWith f m n) <span class="ot">=</span> f (<span class="fu">lookup</span> k m) (<span class="fu">lookup</span> k n)</span></code></pre></div>
<p>By choosing a degenerate function <code>f</code>, say, <code>\_ _ -&gt; nontrivial</code>, where <code>nontrivial</code> is some value that is <em>not</em> <code>mempty</code>, we can see the beginnings of a problem:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>  <span class="fu">lookup</span> k (unionWith f m n)</span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="ot">=</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>  f (<span class="fu">lookup</span> k m) (<span class="fu">lookup</span> k n)</span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="ot">=</span> <span class="op">&lt;</span><span class="kw">let</span> f <span class="ot">=</span> \_ _ <span class="ot">-&gt;</span> nontrivial<span class="op">&gt;</span></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a>  nontrivial</span></code></pre></div>
<p>Regardless of the key we lookup in our <code>unionWith</code>ed <code>Map</code>, we need to get back <code>nontrivial</code>. How can we implement such a thing? I see only two ways:</p>
<ol type="1">
<li>explicitly associate every key in the map with <code>nontrivial</code>, or</li>
<li>keep <code>nontrivial</code> around as a default value in the map</li>
</ol>
<p>#1 is clearly a non-starter, given that we want our <code>Map</code>s to be <em>efficient</em> encodings of functions, which leaves us with only #2. This is actually a pretty common construction, which stems immediately from the fact that a pair of monoids is itself a monoid. The construction would look something like this:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb9-1"><a href="#cb9-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">Map</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>  {<span class="ot"> defaultValue ::</span> v</span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>  ,<span class="ot"> implementation ::</span> <span class="dt">Data.Map.Map</span> k v</span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>  }</span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> stock <span class="dt">Generic</span></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Semigroup</span>, <span class="dt">Monoid</span>) via (<span class="dt">Generically</span> (<span class="dt">Map</span> k v))</span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a>unionWith</span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a><span class="ot">    ::</span> (a <span class="ot">-&gt;</span> b <span class="ot">-&gt;</span> c)</span>
<span id="cb9-10"><a href="#cb9-10" aria-hidden="true" tabindex="-1"></a>    <span class="ot">-&gt;</span> <span class="dt">Map</span> k a</span>
<span id="cb9-11"><a href="#cb9-11" aria-hidden="true" tabindex="-1"></a>    <span class="ot">-&gt;</span> <span class="dt">Map</span> k b</span>
<span id="cb9-12"><a href="#cb9-12" aria-hidden="true" tabindex="-1"></a>    <span class="ot">-&gt;</span> <span class="dt">Map</span> k c</span>
<span id="cb9-13"><a href="#cb9-13" aria-hidden="true" tabindex="-1"></a>unionWith f (<span class="dt">Map</span> def1 imp1) (<span class="dt">Map</span> def2 imp2) <span class="ot">=</span></span>
<span id="cb9-14"><a href="#cb9-14" aria-hidden="true" tabindex="-1"></a>  <span class="dt">Map</span> (f def1 def2) (liftA2 f imp1 imp2)</span></code></pre></div>
<p>Seems fine, right? The nail in the coffin comes from when we reintroduce our semigroup homomorphism:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="fu">lookup</span> k (m1 <span class="op">&lt;&gt;</span> m2) <span class="ot">=</span> <span class="fu">lookup</span> k m1 <span class="op">&lt;&gt;</span> <span class="fu">lookup</span> k m2</span></code></pre></div>
<p>Without loss of generalization, take <code>m2 = pure nontrivial</code> (where <code>pure</code> is just <code>unionWith</code> with a constant function.) This gives us:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="fu">lookup</span> k (m1 <span class="op">&lt;&gt;</span> <span class="fu">pure</span> nontrivial) <span class="ot">=</span> <span class="fu">lookup</span> k m1 <span class="op">&lt;&gt;</span> nontrivial</span></code></pre></div>
<p>Making this thing efficient is a further complication! We again have two options:</p>
<ol type="1">
<li>modify the value at every key by multiplying in <code>nontrivial</code>, or</li>
<li>finding a way of suspending this computation</li>
</ol>
<p>#1 clearly requires <span class="math inline">\(O(n)\)</span> work, which again forces us to look at #2. But #2 seems very challenging, because the monoidal values we need to suspend <em>need not</em> span the entire <code>Map</code>. For example, consider a <code>Map</code> constructed a la:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a>((<span class="fu">pure</span> prefix1 <span class="op">&lt;&gt;</span> ((<span class="fu">pure</span> prefix2 <span class="op">&lt;&gt;</span> m) <span class="op">&lt;&gt;</span> n)) <span class="op">&lt;&gt;</span> (p <span class="op">&lt;&gt;</span> <span class="fu">pure</span> suffix)</span></code></pre></div>
<p>Representing this thing efficiently certainly isn’t impossible, but you’re not going to be able to do it on the balanced binary search trees that underlie the implementation of <code>Data.Map.Map</code>.</p>
<hr />
<p>I find this quite an interesting result. I always assumed that <code>Data.Map.Map</code> (or at least, <code>Data.Map.Monoidal.MonoidalMap</code>) didn’t have an <code>Applicative</code> instance because it would require a <code>Monoid</code> constraint on its output—but that’s not the sort of thing we can express in Haskell.</p>
<p>But the analysis above says that’s not actually the reason! It’s that there can be no efficient implementation of <code>Applicative</code>, even if we <em>could</em> constrain the result.</p>
<p>What I find so cool about this style of analysis is that we didn’t actually write any code, nor did we peek into the implementation of <code>Data.Map</code> (except to know that it’s implemented as a balanced BST.) All we did was look at the obvious laws, instantiate them with degenerate inputs, and think about what would be required to to efficiently get the right answer.</p>
        ]]>
      </content>
    </entry>
    <entry>
      <title>Using Obscure Graph Theory to solve PL Problems</title>
      <id>blog/solving-lcsa/index.html</id>
      <link href='blog/solving-lcsa/index.html'/>
      <published>2025-05-04T08:05:00Z</published>
      <updated>2025-05-04T08:05:00Z</updated>

      <content type="html" xml:base="https://reasonablypolymorphic.com">
        <![CDATA[
        <p>Usually I write about <em>solutions</em> to problems I’ve worked out, but I’ve found myself increasingly becoming interesting in <em>where solutions come from.</em> Maybe it’s because I’ve been reading Boorstin’s excellent <a href="https://en.wikipedia.org/wiki/The_Discoverers">The Discoverers</a>, which I’d strongly recommend.</p>
<p>Regardless of why, I thought I’d switch up the usual dance step today, and discuss what solving my most-recent-big-problem actually looked like, in terms of what I tried, where I looked, and what the timeline was.</p>
<h2 id="the-problem">The Problem</h2>
<p>The problem is to serialize a program graph into a series of let-bindings. For example, given the following graph:</p>
<pre><code>      +
    /   \
  f ---&gt; g
  |     / \
  a     \ /
      expensive</code></pre>
<p>which represents the program:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a>f a (g expensive expensive) <span class="op">+</span> g expensive expensive</span></code></pre></div>
<p>Unfortunately, this is a naive representation of the program, since it duplicates the work required to compute <code>expensive</code> four times, and <code>g expensive expensive</code> twice. Instead, we would prefer to generate the equivalent-but-more-efficient program:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> <span class="op">$</span><span class="dv">0</span> <span class="ot">=</span> expensive</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>    <span class="op">$</span><span class="dv">1</span> <span class="ot">=</span> g <span class="op">$</span><span class="dv">0</span> <span class="op">$</span><span class="dv">0</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">in</span> f a <span class="op">$</span><span class="dv">1</span> <span class="op">+</span> <span class="op">$</span><span class="dv">1</span></span></code></pre></div>
<p>This transformation is affectionately known as <em>sharing</em>, since it shares the computed answer whenever there is repeated work to be done.</p>
<p>So this is what we’re trying to do. Given the original graph, determine the best place to insert these let-bindings, for some reasonable definition of “best.” We can assume there are no side effects involved, so any place that an expression is well-scoped is an acceptable solution.</p>
<p>In order to understand some of my attempted solutions, it’s worth noting that our final solution should build something of type <code>Expr</code>, and the original graph is represented as a <code>IntMap (ExprF Int)</code>. <code>ExprF</code> is the <a href="https://hackage.haskell.org/package/recursion-schemes-5.2.3/docs/Data-Functor-Foldable.html#t:Base"><code>Base</code></a> functor of <code>Expr</code>, with all of its self-references replaced by some type variable, in this case <code>Int</code>. Thus, the graph above looks much more like:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>_ <span class="op">:</span> <span class="dt">IntMap</span> (<span class="dt">ExprF</span> <span class="dt">Int</span>)</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>_ <span class="ot">=</span> IM.fromList</span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>  [ (<span class="dv">0</span>, <span class="dt">Apply</span> <span class="st">&quot;+&quot;</span> [<span class="dv">1</span>, <span class="dv">3</span>])</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>  , (<span class="dv">1</span>, <span class="dt">Apply</span> <span class="st">&quot;f&quot;</span> [<span class="dv">2</span>, <span class="dv">3</span>]</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>  , (<span class="dv">2</span>, <span class="op">...</span>)  <span class="co">-- a</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>  , (<span class="dv">3</span>, <span class="dt">Apply</span> <span class="st">&quot;g&quot;</span> [<span class="dv">4</span>, <span class="dv">4</span>])</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>  , (<span class="dv">4</span>, <span class="op">...</span>)  <span class="co">-- expensive</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>  ]</span></code></pre></div>
<h2 id="the-original-solution">The Original Solution</h2>
<p>I spent over a year trying to solve this problem, with various mostly-working solutions during that time. My strategy here was to think really hard, write up some algorithm that seemed plausible, and then run it against our (small) battery of integration tests to make sure it got the same answer as before.</p>
<p>Why not property test it? I tried, but found it very challenging to implement well-typed generators that would reliably introduce shared thunks. But maybe there’s a different lesson to be learned here about writing good generators.</p>
<p>Anyway. For eight months, one of these think-really-hard algorithms fit the bill and didn’t give us any problems. It was a weird, bespoke solution to the problem that independetly kept track of all of the free variables in every graph fragment, and tried to let-bind a fragment as soon as we landed in a context where all of the free variables were in scope. It seemed to work, but it was extremely messy and unmaintainable.</p>
<p>At the time of writing, this sharing algorithm was the only source of let-binds in our entire language, which meant that it didn’t need to account for let-binds <em>in</em> the program.</p>
<p>Of course, that invariant eventually changed. We added a way in the source langauge to introduce <code>let</code>s, which meant my algorithm was wrong. And I had written it sufficiently long ago that I no longer remembered <em>exactly why it worked.</em> Which meant the <a href="https://pages.cs.wisc.edu/~remzi/Naur.pdf">theory of my program was lost, and thus that we ought to rewrite it.</a></p>
<h2 id="unfolding-a-solution">Unfolding a Solution</h2>
<p>I went back to the problem statement, and stared at it for a long time (back to the think-really-hard algorithm!) Upon staring at the problem, I realized that what I was really trying to do was determine where diamond patterns arose in the propgram graph.</p>
<p>Recall our original graph:</p>
<pre><code>      +
    /   \
  f ---&gt; g
  |     / \
  a     \ /
      expensive</code></pre>
<p>If we redraw it such that <code>g</code> is on a different rank than <code>f</code>, then the two diamond patterns become much clearer:</p>
<pre><code>      +
    /  \
  f     |
  | \   |
  a  \ /
      g
     / \
     \ /
   expensive</code></pre>
<p>The insight I came up with is that if a node <code>n</code> is the source of a diamond, then we must let-bind the sink of the diamond immediately before inlining the definition of <code>n</code>.</p>
<p>This gives rise to the question of “how do we identify a diamond?” What we can do is give a mapping from each node to its reachable set of nodes. For example, in the above, we’d compute the map:</p>
<pre><code>+         -&gt; {+, f, a, g, expensive}
f         -&gt; {f, a, g, expensive}
a         -&gt; {a}
g         -&gt; {g, expensive}
expensive -&gt; {expensive}</code></pre>
<p>Then when we go to inline a node, say, <code>+</code>, we can look for any nodes that are reachable via more than one of its immediate subterms. Since the immediate subterms of <code>+</code> are <code>f</code> and <code>g</code>, we can take the intersections of their reachable sets:</p>
<pre><code>{f, a, g, expensive} union {g, expensive}</code></pre>
<p>giving us</p>
<pre><code>{g, expensive}</code></pre>
<p>which is exactly the set of nodes that we need to perform sharing on. If you topologically sort this set, it gives you the order that you should perform your let bindings.</p>
<p>EXCEPT there’s a kink in the whole thing. What happens if one of the terms in this diamond contains free variables? In particular, we might have something like this:</p>
<pre><code>      +
    /  \
  f     |
  | \   |
  a  \ /
      λx
     / \
     \ /
   expensive
      |
      x</code></pre>
<p>This gives us an analogous set of reachable nodes when we look at <code>+</code>, but we obviously can’t lift <code>expensive x</code> above the lambda.</p>
<p>Resolving this problem required giving up on the notion of memoizing the entire reachable set of nodes, and to instead crawl the graph ensuring that everything is well-scoped.</p>
<h2 id="performance-woes">Performance Woes</h2>
<p>My algorithm looked fine, and, importantly, got the right answer in a reasonable amount of time on our (small) battery of integration tests. So I shipped it, commended myself on a job well done, and thought nothing more about it. For about a week, until a bug report came in saying that our compiler now seemed to hang on big programs.</p>
<p>Which was something I hadn’t noticed, since we didn’t have any big programs in our integration tests.</p>
<p>Damn!</p>
<p>Upon digging in to what exactly was so slow, I noticed that my algorithm was <a href="https://accidentallyquadratic.tumblr.com/">accidentally quadratic</a>. I needed to fold over every node in the graph, and that required looking at the entire reachable set underneath it. I had put in some of the obvious safeguards, hoping that they would prune the search tree early, but it wasn’t enough sacrifice for the Great God of Asymptotes.</p>
<p>Did I mention that at this point in the story, having this algorithm working fast was on the critical path of the company? Everybody else was blocked on me figuring this out. Talk about pressure!</p>
<p>Anyway. You’ll notice above that in my description of the algorithm, everything sounds fine. But the juice is in the details, as the common saying goes. Computing reachability isn’t quite the right thing to be using here, as it gave us the wrong answer for the lambda example above. Which is unfortunate because reachability is something we can do in linear time.</p>
<p>And then when reachability didn’t work, I just threw away the fast performance and hoped my bespoke algorithm would do the job. My only redemption comes from the fact that at least it got the right answer, even if it did so very slowly.</p>
<h2 id="finding-the-kernel">Finding the Kernel</h2>
<p>Back to the drawing board.</p>
<p>Whenever I have graph theory problems, I call up my boy Vikrem. He’s good at nerd stuff like this.</p>
<p>We <a href="https://en.wikipedia.org/wiki/Rubber_duck_debugging">rubberducked</a> the problem, and tried to reframe the problem in the language of graph theory. We had a Merkiv–Maguire moment where we indepdently realized that the goal was somehow related to finding the <em>lowest common ancestor</em> (LCA) of a node.</p>
<p>Which is to say, roughly, that we are looking for forks in the diamond diagram. Which we already knew, but it was nice to have some language for.</p>
<p>Our new problem is that LCA is defined only over trees. There are some extensions to DAGs, but none of them seem to be particularly well founded. However, searching for exactly that brought me to <a href="https://stackoverflow.com/questions/14865081/algorithm-to-find-lowest-common-ancestor-in-directed-acyclic-graph">this stackoverflow question</a>, where nestled in the comments is someone suggesting that the poster isn’t looking for LCA, but instead for a related notion the <em>lowest <strong>single</strong> common ancestor.</em> LSCA is defined in a 2010 paper <a href="https://www.sciencedirect.com/science/article/abs/pii/S0020019010000487">New common ancestor problems in trees and directed acyclic graphs</a>.</p>
<p>The standard definition of <code>LCA(x, y) = l</code> is that “<code>l</code> is an ancestor of <code>x</code> and of <code>y</code>, and that no descendent of <code>l</code> has this property.”</p>
<p>But the definition of <code>LSCA(x, y) = l</code> is that “<code>l</code> lies on all root-to-<code>x</code> paths, and that <code>l</code> lies on all root-to-<code>y</code> paths, and that no descendent of <code>l</code> has this property.”</p>
<p>The distinction between the two is easily seen in the following graph:</p>
<pre><code>  0
 / \
1   2
| X |
3   4</code></pre>
<p>Under the standard definition, LCA is not uniquely defined for DAGs. That is, <code>LCA(3, 4) = {1, 2}</code>. But neither 1 nor 2 lies on <em>all</em> paths from the root. Under LSCA therefore we get <code>LSCA(3, 4) = 0</code>, which is the obviously-correct place to let-bind 3 and 4.</p>
<p>The paper gives a preprocessing scheme for computing LSCA by building a “lowest single ancestor” (LSA) tree. The LSA of a node is the LSCA of all of its in-edges. This definition cashes out to mean “the most immediate diamond above any node.” Finally! This is exactly what we’re looking for, since this is where we must insert our let-bindings! Even better, the paper gives us an algorithm for computing the LSA tree in linear time!</p>
<h2 id="the-first-implementer">The First Implementer</h2>
<p>Of course, I’m lazy and would prefer not to implement this thing. So instead I searched on hackage for <code>lsca</code>, and found nothing. But then I searched for <code>lca</code> and found that, like always, <a href="https://hackage.haskell.org/package/lca">Ed Kmett was 13 years ahead of me.</a></p>
<p>The <code>lca</code> package implements an <span class="math inline">\(O(log n)\)</span> algorithm for computing the LCA of any two nodes in a graph. Which is very convenient for me, since the LSCA algorithm requires being able to do this.</p>
<p>Time to roll up the sleeves and get cracking I suppose.</p>
<p>The paper was surprisingly straightforward, and my first attempt implemented the (imperative) algorithms as given (imperatively.) The first step is to do a topological sort on the DAG in order to know in which order one ought to unfold the LSA tree.</p>
<p>But as is so often the case, this topological sort isn’t actually relevant to the algorithm; it’s just an encoding detail of expressing the algorithm imperatively. But you don’t need that when you’ve got laziness on your side! Instead you can just tie the know and do something cool like this:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="ot">lsaTree ::</span> <span class="dt">Ord</span> v <span class="ot">=&gt;</span> <span class="dt">Map</span> v (<span class="dt">Set</span> v) <span class="ot">-&gt;</span> <span class="dt">Map</span> v (<span class="dt">Path</span> v)</span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>lsaTree input <span class="ot">=</span> fix <span class="op">$</span> \result <span class="ot">-&gt;</span> M.fromList <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>  (node, parents) <span class="ot">&lt;-</span> M.toList input</span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">let</span> parentResults <span class="ot">=</span> <span class="fu">fmap</span> (result <span class="op">M.!</span>) parents</span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a>  <span class="op">...</span></span></code></pre></div>
<p>Notice how we use <code>fix</code> to bind the eventual result of the final computation. Then we can chase pointers by looking them up in <code>result</code>—even though it’s not yet “computed.” Who cares what order the computer does it in. Why is that a thing I should need to specify?</p>
<p>Anyway. The exact details of implementing LSA are not particularly important for the remainder of this blog post. If you’re interested, you can peep the PR, which is <a href="https://github.com/ekmett/lca/pull/8">delightfully small</a>.</p>
<h2 id="tying-it-all-back-together">Tying It All Back Together</h2>
<p>Equipped with my LSA tree, I was now ready to go back and solve the original problem of figuring out where to stick let-bindings. It’s easy now. Given the original program graph, find the LSA for each node. The LSA is the place you should insert the let binding.</p>
<p>So given the map of nodes to their LSAs, invert that map and get back a map of nodes to descendents who have this node as an LSA. Now when you go to inline a node, just look up everything in this map and inline it first.</p>
<p>It turns out to be a very elegant solution. It’s one third of the length of my horrible ad-hoc implementations, and it runs in linear time of the number of nodes in the graph. All in all, very good.</p>
<p>More often than I’m comfortable about, people will ask me how I can have so many good ideas. And what I like about this story is that it’s pretty typical of how I actually “have” “good” ideas. I’m reminded of the fact that <a href="https://fs.blog/great-talks/richard-hamming-your-research/">luck favors the prepared mind</a>. Attentive readers will notice that <em>none</em> of this process was due to brilliance on my part. I happened to know Vikrem who’s a genius. Together we pulled at some ancient graph theory strings and remembered a fact that someone else had thought important to teach us. That wasn’t actually the right path, but it lead us to stackoverflow where someone had linked to a relevant paper. I implemented the paper using a library that someone else had done the heavy lifting on, and simplified the implementation using this knot-tying trick I picked up somewhere along the way.</p>
<p>Also, I’m just really pleased that the solution came from trying to reverse engineer the relevant graph-theory search terms. Maybe that’s the actual takeaway here.</p>
        ]]>
      </content>
    </entry>
    <entry>
      <title>Bidirectional Instance Contexts</title>
      <id>blog/bidirectional-instance-contexts/index.html</id>
      <link href='blog/bidirectional-instance-contexts/index.html'/>
      <published>2025-02-15T02:15:00Z</published>
      <updated>2025-02-15T02:15:00Z</updated>

      <content type="html" xml:base="https://reasonablypolymorphic.com">
        <![CDATA[
        <p>Just a quick one today, but I wanted to point out a little trick you can do with Haskell’s typeclass inference.</p>
<p>Imagine we have some little class, the details of which matter not in the least:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">Foo</span><span class="ot"> ::</span> <span class="dt">Type</span> <span class="ot">-&gt;</span> <span class="dt">Constraint</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Foo</span> a <span class="kw">where</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>  <span class="op">...</span></span></code></pre></div>
<p>We can give some instances of this type:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode haskell"><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">Foo</span> <span class="dt">Int</span> <span class="kw">where</span> <span class="op">...</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Foo</span> <span class="dt">Bool</span> <span class="kw">where</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">Foo</span> () <span class="kw">where</span> <span class="op">...</span></span></code></pre></div>
<p>Regular, everyday stuff. But the instances for type constructors are more interesting, because they come with an instance context:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> (<span class="dt">Foo</span> a, <span class="dt">Foo</span> b) <span class="ot">=&gt;</span> <span class="dt">Foo</span> (a, b) <span class="kw">where</span> <span class="op">...</span></span></code></pre></div>
<p>Then, of course, if we know both <code>Foo a</code> and <code>Foo b</code>, we can infer <code>Foo (a, b)</code>. To make this fact overwhelmingly explicit, we can reify the usual constraint-solving logic by using the <code>Dict</code> type, and thus the following program will typecheck:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Constraint</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>forwards</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="ot">  ::</span> <span class="dt">Dict</span> (<span class="dt">Foo</span> a)</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>  <span class="ot">-&gt;</span> <span class="dt">Dict</span> (<span class="dt">Foo</span> b)</span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>  <span class="ot">-&gt;</span> <span class="dt">Dict</span> (<span class="dt">Foo</span> (a, b))</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>forwards <span class="dt">Dict</span> <span class="dt">Dict</span> <span class="ot">=</span> <span class="dt">Dict</span></span></code></pre></div>
<p>Perhaps tipped off by the name here, the gentle reader is asked to notice the asymmetry here, since the converse program will not typecheck:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>backwards</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="ot">  ::</span> <span class="dt">Dict</span> (<span class="dt">Foo</span> (a, b))</span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>  <span class="ot">-&gt;</span> (<span class="dt">Dict</span> (<span class="dt">Foo</span> a), <span class="dt">Dict</span> (<span class="dt">Foo</span> b))</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>backwards <span class="dt">Dict</span> <span class="ot">=</span> (<span class="dt">Dict</span>, <span class="dt">Dict</span>)</span></code></pre></div>
<p>But why should it not typecheck?<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a> Recall from the relevant instance definition that these instances must, in fact, exist:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode haskell"><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">Foo</span> a, <span class="dt">Foo</span> b) <span class="ot">=&gt;</span> <span class="dt">Foo</span> (a, b)</span></code></pre></div>
<p>As a testament to <em>just</em> how good GHC is, we can support this bidirectionality via a minor tweak to the definition of class and its instances.</p>
<p>The trick is to add an associated type family to <code>Foo</code>, and to <em>use it as a superclass constraint:</em></p>
<div class="sourceCode" id="cb7"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">Foo</span><span class="ot"> ::</span> <span class="dt">Type</span> <span class="ot">-&gt;</span> <span class="dt">Constraint</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Evidence</span> a <span class="ot">=&gt;</span> <span class="dt">Foo</span> a <span class="kw">where</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">type</span> <span class="dt">Evidence</span><span class="ot"> a ::</span> <span class="dt">Constraint</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">type</span> <span class="dt">Evidence</span> a <span class="ot">=</span> ()</span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>  <span class="op">...</span></span></code></pre></div>
<p>Because we’ve given a default implementation of the type family, our existing simple instances work as before:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Foo</span> <span class="dt">Int</span> <span class="kw">where</span> <span class="op">...</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Foo</span> <span class="dt">Bool</span> <span class="kw">where</span> <span class="op">...</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Foo</span> () <span class="kw">where</span> <span class="op">...</span></span></code></pre></div>
<p>with the only change required coming from the type constructor instances:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode haskell"><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">Foo</span> a, <span class="dt">Foo</span> b) <span class="ot">=&gt;</span> <span class="dt">Foo</span> (a, b) <span class="kw">where</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">type</span> <span class="dt">Evidence</span> (a, b) <span class="ot">=</span> (<span class="dt">Foo</span> a, <span class="dt">Foo</span> b)</span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>  <span class="op">...</span></span></code></pre></div>
<p>or, if we you want to be cute about it:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Evidence</span> (a, b) <span class="ot">=&gt;</span> <span class="dt">Foo</span> (a, b) <span class="kw">where</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">type</span> <span class="dt">Evidence</span> (a, b) <span class="ot">=</span> (<span class="dt">Foo</span> a, <span class="dt">Foo</span> b)</span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>  <span class="op">...</span></span></code></pre></div>
<p>By sticking <code>Evidence</code> into the superclass constraint, GHC knows that this dictionary is always available when you’ve got a <code>Foo</code> dictionary around. And our earlier <code>backwards</code> program now typechecks as expected.</p>
<p><a href="https://play.haskell.org/saved/YjCfxwNy">This is all available in a play session</a> if you’d like to fool around with it.</p>
<section class="footnotes" role="doc-endnotes">
<hr />
<ol>
<li id="fn1" role="doc-endnote"><p>Rhetorical question. I don’t want to hear about orphans or overlapping instances or whatever.<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
        ]]>
      </content>
    </entry>
    <entry>
      <title>Use Monoids for Construction</title>
      <id>blog/use-monoids/index.html</id>
      <link href='blog/use-monoids/index.html'/>
      <published>2025-01-24T09:35:00Z</published>
      <updated>2025-01-24T09:35:00Z</updated>

      <content type="html" xml:base="https://reasonablypolymorphic.com">
        <![CDATA[
        <p>There’s a common anti-pattern I see in beginner-to-intermediate Haskell programmers that I wanted to discuss today. It’s the tendency to conceptualize the <em>creation</em> of an object by <em>repeated mutation.</em> Often this takes the form of repeated insertion into an empty container, but comes up under many other guises as well.</p>
<p>This anti-pattern isn’t particularly surprising in its prevalence; after all, if you’ve got the usual imperative brainworms, this is just <em>how things get built.</em> The gang of four “builder pattern” is exactly this; you can build an empty object, and setters on such a thing change the state <em>but return the object itself.</em> Thus, you build things by chaning together setter methods:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode java"><code class="sourceCode java"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a>Foo myFoo <span class="op">=</span> <span class="kw">new</span> <span class="fu">Foo</span><span class="op">().</span><span class="fu">setBar</span><span class="op">().</span><span class="fu">setQux</span><span class="op">(</span><span class="dv">17</span><span class="op">).</span><span class="fu">setZap</span><span class="op">(</span><span class="kw">true</span><span class="op">);</span></span></code></pre></div>
<p>Even if you don’t ascribe to the whole OOP design principle thing, you’re still astronomically likely to think about building data structures like this:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode java"><code class="sourceCode java"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a>Doodad doodad <span class="op">=</span> <span class="kw">new</span> Doodad<span class="op">;</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="fu">foreach</span> <span class="op">(</span>Widget widget in widgets<span class="op">)</span> <span class="op">{</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>  doodad<span class="op">.</span><span class="fu">addWidget</span><span class="op">(</span>widget<span class="op">);</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>To be more concrete, maybe instead of doodads and widgets you have <code>BST</code>s and <code>Node</code>s. Or dictionaries and key-value pairs. Or graphs and edges. Anywhere you look, you’ll probably find examples of this sort of code.</p>
<p>Maybe you’re thinking to yourself “I’m a hairy-chested functional programmer and I scoff at patterns like these.” That might be true, but perhaps you too are guilty of writing code that looks like:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="fu">foldr</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>    (\(k, v) m <span class="ot">-&gt;</span> Map.insert k v m)</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>    Map.empty</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">$</span> toKVPairs something</span></code></pre></div>
<p>Just because it’s dressed up with functional combinators <em>doesn’t mean</em> you’re not still writing C code. To my eye, the great promise of functional programming is its potential for conceptual clarity, and repeated mutation will always fall short of the mark.</p>
<p>The complaint, as usual, is that repeated mutation tells you <em>how</em> to build something, rather than focusing on <em>what</em> it is you’re building. An algorithm cannot be correct in the absence of intention—after all, you must know what you’re trying to accomplish in order to know if you succeeded. What these builder patterns, for loops, and <code>foldr</code>s all have in common is that they are algorithms for strategies for building something.</p>
<p>But you’ll notice none of them come with comments. And therefore we can only ever guess at what the original author intended, based on the context of the code we’re looking at.</p>
<p>I’m sure this all sounds like splitting hairs, but that’s because the examples so far have been extremely simple. But what about this one?</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="ot">cgo ::</span> (a <span class="ot">-&gt;</span> (<span class="dt">UInt</span>, <span class="dt">UInt</span>)) <span class="ot">-&gt;</span> [a] <span class="ot">-&gt;</span> [<span class="dt">NonEmpty</span> a]</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>cgo f <span class="ot">=</span> <span class="fu">foldr</span> step []</span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>    step a [] <span class="ot">=</span> [<span class="fu">pure</span> a]</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>    step a bss0<span class="op">@</span>((b <span class="op">:|</span> bs) <span class="op">:</span> bss)</span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>      <span class="op">|</span> <span class="kw">let</span> (al, ac) <span class="ot">=</span> f a</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>      , <span class="kw">let</span> (bl, bc) <span class="ot">=</span> f b</span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>      , al <span class="op">+</span> <span class="dv">1</span> <span class="op">==</span> bl <span class="op">&amp;&amp;</span> ac <span class="op">==</span> bc</span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>            <span class="ot">=</span> (a <span class="op">:|</span> b <span class="op">:</span> bs) <span class="op">:</span> bss</span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a>      <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="fu">pure</span> a <span class="op">:</span> bss0</span></code></pre></div>
<p>which I found by grepping through <code>haskell-language-server</code> for <code>foldr</code>, and then mangled to remove the suggestive variable names. What does this one do? Based solely on the type we can presume it’s using that function to partition the list somehow. But how? And is it correct? We’ll never know—and the function doesn’t even come with any tests!</p>
<h2 id="its-always-monoids">It’s Always Monoids</h2>
<p>The shift in perspective necessary here is to reconceptualize building-by-repeated-mutation as building-by-combining. Rather than chiseling out the object you want, instead find a way of gluing it together from simple, obviously-correct pieces.</p>
<p>The notion of “combining together” should evoke in you a cozy warm fuzzy feeling. Much like being in a secret pillow form. You must come to be one with the monoid. Once you have come to embrace monoids, you will have found inner programming happiness. Monoids are a sacred, safe place, at the fantastic intersection of “overwhelming powerful” and yet “hard to get wrong.”</p>
<p>As an amazingly fast recap, a monoid is a collection of three things: some type <code>m</code>, some value of that type <code>mempty</code>, and binary operation over that type <code>(&lt;&gt;) :: m -&gt; m -&gt; m</code>, subject to a bunch of laws:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>∀a<span class="op">.</span> <span class="fu">mempty</span> <span class="op">&lt;&gt;</span> a <span class="ot">=</span> a <span class="ot">=</span> a <span class="op">&lt;&gt;</span> <span class="fu">mempty</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>∀a b c<span class="op">.</span> (a <span class="op">&lt;&gt;</span> b) <span class="op">&lt;&gt;</span> c <span class="ot">=</span> a <span class="op">&lt;&gt;</span> (b <span class="op">&lt;&gt;</span> c)</span></code></pre></div>
<p>which is to say, <code>mempty</code> does nothing and <code>(&lt;&gt;)</code> doesn’t care where you stick the parentheses.</p>
<p>If you’re going to memorize any two <em>particular</em> examples of monoids, it had better be these two:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode haskell"><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">Monoid</span> [a] <span class="kw">where</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>  <span class="fu">mempty</span> <span class="ot">=</span> []</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>  a <span class="op">&lt;&gt;</span> b <span class="ot">=</span> a <span class="op">++</span> b</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> (<span class="dt">Monoid</span> a, <span class="dt">Monoid</span> b) <span class="ot">=&gt;</span> <span class="dt">Monoid</span> (a, b) <span class="kw">where</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>  <span class="fu">mempty</span> <span class="ot">=</span> (<span class="fu">mempty</span>, <span class="fu">mempty</span>)</span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a>  (a1, b1) <span class="op">&lt;&gt;</span> (a2, b2) <span class="ot">=</span> (a1 <span class="op">&lt;&gt;</span> a2, b1 <span class="op">&lt;&gt;</span> b2)</span></code></pre></div>
<p>The first says that lists form a monoid under the empty list and concatenation. The second says that products preserve monoids.</p>
<p>The list monoid instance is responsible for the semantics of the ordered, “sequency” data structures. That is, if I have some sequential flavor of data structure, its monoid instance should probably satisfy the equation <code>toList a &lt;&gt; toList b = toList (a &lt;&gt; b)</code>. Sequency data structures are things like lists, vectors, queues, deques, that sort of thing. Data structures where, when you combine them, you assume there is no overlap.</p>
<p>The second monoid instance here, over products, is responsible for pretty much all the other data structures. The first thing we can do with it is remember that functions are just really, really big product types, with one “slot” for every value in the domain. We can show an isomorphism between pairs and functions out of booleans, for example:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="ot">from ::</span> (<span class="dt">Bool</span> <span class="ot">-&gt;</span> a) <span class="ot">-&gt;</span> (a, a)</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>from f <span class="ot">=</span> (f <span class="dt">False</span>, f <span class="dt">True</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="ot">to ::</span> (a, a) <span class="ot">-&gt;</span> (<span class="dt">Bool</span> <span class="ot">-&gt;</span> a)</span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>to (a, _) <span class="dt">False</span> <span class="ot">=</span> a</span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>to (_, a) <span class="dt">True</span>  <span class="ot">=</span> a</span></code></pre></div>
<p>and under this isomorphism, we should thereby expect the <code>Monoid a =&gt; Monoid (Bool -&gt; a)</code> instance to agree with <code>Monoid a =&gt; Monoid (a, a)</code>. If you generalize this out, you get the following instance:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Monoid</span> a <span class="ot">=&gt;</span> <span class="dt">Monoid</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="fu">mempty</span> <span class="ot">=</span> \_ <span class="ot">-&gt;</span> <span class="fu">mempty</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>  f <span class="op">&lt;&gt;</span> g <span class="ot">=</span> \x <span class="ot">-&gt;</span> f x <span class="op">&lt;&gt;</span> g x</span></code></pre></div>
<p>which combines values in the codomain monoidally. We can show the equivalence between this monoid instance and our original product preservation:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>  from f <span class="op">&lt;&gt;</span> from g</span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="ot">=</span> (f <span class="dt">False</span>,  f <span class="dt">True</span>) <span class="op">&lt;&gt;</span> (g <span class="dt">False</span>, g <span class="dt">True</span>)</span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a><span class="ot">=</span> (f <span class="dt">False</span> <span class="op">&lt;&gt;</span> g <span class="dt">False</span>, f <span class="dt">True</span> <span class="op">&lt;&gt;</span> g <span class="dt">True</span>)</span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a><span class="ot">=</span> ((f <span class="op">&lt;&gt;</span> g) <span class="dt">False</span>, (f <span class="op">&lt;&gt;</span> g) <span class="dt">True</span>)</span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a><span class="ot">=</span> from (f <span class="op">&lt;&gt;</span> g)</span></code></pre></div>
<p>and</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a>  to (a11, a12) <span class="op">&lt;&gt;</span> to (a21, a22)</span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="ot">=</span> \x <span class="ot">-&gt;</span> to (a11, a12) x <span class="op">&lt;&gt;</span> to (a21, a22) x</span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a><span class="ot">=</span> \x <span class="ot">-&gt;</span> <span class="kw">case</span> x <span class="kw">of</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>    <span class="dt">False</span> <span class="ot">-&gt;</span> to (a11, a12) <span class="dt">False</span> <span class="op">&lt;&gt;</span> to (a21, a22) <span class="dt">False</span></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>    <span class="dt">True</span>  <span class="ot">-&gt;</span> to (a11, a12) <span class="dt">True</span>  <span class="op">&lt;&gt;</span> to (a21, a22) <span class="dt">True</span></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a><span class="ot">=</span> \x <span class="ot">-&gt;</span> <span class="kw">case</span> x <span class="kw">of</span></span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a>    <span class="dt">False</span> <span class="ot">-&gt;</span> a11 <span class="op">&lt;&gt;</span> a21</span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a>    <span class="dt">True</span>  <span class="ot">-&gt;</span> a12 <span class="op">&lt;&gt;</span> a22</span>
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a><span class="ot">=</span> \x <span class="ot">-&gt;</span> to (a11 <span class="op">&lt;&gt;</span> a21, a12 <span class="op">&lt;&gt;</span> a22) x</span>
<span id="cb10-10"><a href="#cb10-10" aria-hidden="true" tabindex="-1"></a><span class="ot">=</span> to (a11 <span class="op">&lt;&gt;</span> a21, a12 <span class="op">&lt;&gt;</span> a22)</span></code></pre></div>
<p>which is a little proof that our function monoid agrees with the preservation-of-products monoid. The same argument works for any type <code>x</code> in the domain of the function, but showing it generically is challenging.</p>
<p>Anyway, I digresss.</p>
<p>The reason to memorize <em>this</em> <code>Monoid</code> instance is that it’s the monoid instance that every data structure is trying to be. Recall that <em>almost all</em> data structures are merely different encodings of functions, designed to make some operations more efficient than they would otherwise be.</p>
<p>Don’t believe me? A <code>Map k v</code> is an encoding of the function <code>k -&gt; Maybe v</code> optimized to efficiently query which <code>k</code> values map to <code>Just</code> something. That is to say, it’s a sparse representation of a function.</p>
<h2 id="from-theory-to-practice">From Theory to Practice</h2>
<p>What does all of this look like in practice? Stuff like worrying about <code>foldr</code> is surely programming-in-the-small, which is worth knowing, but isn’t the sort of thing that turns the tides of a successful application.</p>
<p>The reason I’ve been harping on about the function and product monoids is that they are compositional. The uninformed programmer will be surprised by just far one can get by composing these things.</p>
<p>At work, we need to reduce a tree (+ nonlocal references) into an honest-to-goodness graph. While we’re doing it, we need to collect certain nodes. And the tree has a few constructors which semantically change the scope of their subtrees, so we need to preserve that information as well.</p>
<p>It’s actually quite the exercise to sketch out an algorithm that will accomplish all of these goals when you’re thinking about explicit mutation. Our initial attempts at implementing this were clumsy. We’d fold the tree into a graph, adding fake nodes for the <code>Scope</code> construcotrs. Then we’d filter all the nodes in the graph, trying to find the ones we needed to collect. Then we’d do a graph traversal from the root, trying to find these <code>Scope</code> nodes, and propagating their information downstream.</p>
<p>Rather amazingly, this implementation kinda sorta worked! But it was slow, and took <span class="math inline">\(O(10k)\)</span> SLOC to implement.</p>
<p>The insight here is that everything we needed to collect was monoidal:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode haskell"><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">Solution</span> <span class="ot">=</span> <span class="dt">Solution</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>  {<span class="ot"> graph ::</span> <span class="dt">Graph</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>  ,<span class="ot"> collectedNodes ::</span> <span class="dt">Set</span> <span class="dt">Node</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>  ,<span class="ot"> metadata ::</span> <span class="dt">Map</span> <span class="dt">Node</span> <span class="dt">Metadata</span></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>  }</span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> stock (<span class="dt">Generic</span>)</span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Semigroup</span>, <span class="dt">Monoid</span>) via <span class="dt">Generically</span> <span class="dt">Solution</span></span></code></pre></div>
<p>where the <code>deriving (Semigroup, Monoid) via Generically Solution</code> stanza gives us the semigroup and monoid instances that we’d expect from <code>Solution</code> being the product of a bunch of other monoids.</p>
<p>And now for the <em>coup de grace</em>: we hook everything up with the <code>Writer</code> monad. <code>Writer</code> is a chronically slept-on type, because most people seem to think it’s useful only for logging, and, underwhelming at doing logging compared to a real logger type. But the charm is in the details:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Monoid</span> w <span class="ot">=&gt;</span> <span class="dt">Monad</span> (<span class="dt">Writer</span> w)</span></code></pre></div>
<p><code>Writer w</code> is a <em>monad</em> whenever <code>w</code> is a <em>monoid</em>, which makes it the perfect monad for solving data-structure-creation problems like the one we’ve got in mind. Such a thing gives rise to a few helper functions:</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="ot">collectNode ::</span> <span class="dt">MonadWriter</span> <span class="dt">Solution</span> m <span class="ot">=&gt;</span> <span class="dt">Node</span> <span class="ot">-&gt;</span> m ()</span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>collectNode n <span class="ot">=</span> tell <span class="op">$</span> <span class="fu">mempty</span> { collectedNodes <span class="ot">=</span> Set.singleton n }</span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a><span class="ot">addMetadata ::</span> <span class="dt">MonadWriter</span> <span class="dt">Solution</span> m <span class="ot">=&gt;</span> <span class="dt">Node</span> <span class="ot">-&gt;</span> <span class="dt">Metadata</span> <span class="ot">-&gt;</span> m ()</span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a>addMetadata n m <span class="ot">=</span> tell <span class="op">$</span> <span class="fu">mempty</span> { metadata <span class="ot">=</span> Map.singleton n m }</span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a><span class="ot">emitGraphFragment ::</span> <span class="dt">MonadWriter</span> <span class="dt">Solution</span> m <span class="ot">=&gt;</span> <span class="dt">Graph</span> <span class="ot">-&gt;</span> m ()</span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a>emitGraphFragment g <span class="ot">=</span> tell <span class="op">$</span> <span class="fu">mempty</span> { graph <span class="ot">=</span> g }</span></code></pre></div>
<p>each of which is responsible for adding a little piece to the final solution. Our algorithm is thus a function of the type:</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a>algorithm</span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="ot">  ::</span> <span class="dt">Metadata</span></span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- ^ the current scope</span></span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a>  <span class="ot">-&gt;</span> <span class="dt">Tree</span></span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- ^ the tree we&#39;re reducing</span></span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a>  <span class="ot">-&gt;</span> <span class="dt">Writer</span> <span class="dt">Solution</span> <span class="dt">Node</span></span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- ^ our partial solution, and the node corresponding to the root of the tree</span></span></code></pre></div>
<p>which traverses the <code>Tree</code>, recursing with a different <code>Metadata</code> whenever it comes across a <code>Scope</code> constructor, and calling our helper functions as it goes. At each step of the way, the only thing it needs to return is the root <code>Node</code> of the section of the graph it just built, which recursing calls can use to break up the problem into inductive pieces.</p>
<p>This new implementation is roughly 20x smaller, coming in at <span class="citation" data-cites="O">@O</span>(500)@ SLOC, and was free of all the bugs we’d been dilligently trying to squash under the previous implementation.</p>
<p>Chalk it down to another win for induction!</p>
        ]]>
      </content>
    </entry>
    <entry>
      <title>A New Perspective on Lenses</title>
      <id>blog/code-lenses/index.html</id>
      <link href='blog/code-lenses/index.html'/>
      <published>2025-01-18T09:18:00Z</published>
      <updated>2025-01-18T09:18:00Z</updated>

      <content type="html" xml:base="https://reasonablypolymorphic.com">
        <![CDATA[
        <p>I’ve always considered lenses to be a bit uncomfortable. While they’re occasionally useful for doing deeply nested record updates, they often seem to be more trouble than they’re worth. There’s a temptation in the novice programmer, to <code>^..</code> and <code>folded</code> their way to a solution that is much more naturally written merely as <code>toList</code>. And don’t get me started about the stateful operators like <code>&lt;&lt;+=</code> and their friends. Many programs which can be more naturally written functionally accidentally end up being imperative due to somebody finding a weird lens combinator and trying to use it in anger. Much like a serious drug collection, the tendency is to push it as far as you can.</p>
<p>Thus, my response has usually been one of pushback and moderation. I don’t avoid lenses at all costs, but I do try to limit myself to the prime types (<code>Lens'</code>, <code>Prism'</code>, <code>Iso'</code>), and to the boring combinators (<code>view</code>, <code>set</code>, <code>over</code>). I feel like these give me most of the benefits of lenses, without sending me tumbling down the rabbit hole.</p>
<p>All of this is to say that my grokkage of lenses has always been one of <em>generalized injections and projections</em>, for a rather shallow definition of “generalized”. That is, I’ve grown accustomed to thinking about <em>lenses</em> as getter/setter pairs for data structures—eg, I’ve got a big product type and I want to pull a smaller piece out of it, or modify a smaller piece in a larger structure. I think about prisms as the dual structure over coproducts—“generalized” injecting and pattern matching.</p>
<p>And this is all true; but I’ve been missing the forest for the trees on this one. That’s not to say that I want to write <em>lensier</em> code, but that I should be taking the “generalized” part much more seriously.</p>
<p>The big theme of my intellectual development over the last few years has been thinking about abstractions as <em>shared vocabularies.</em> Monoids are not <em>inherently</em> interesting; they’re interesting because of how they let you quotient seemingly-unrelated problems by their monoidal structure. Applicatives are cool <em>because</em> once you’ve grokked them, you begin to see them everywhere. Anywhere you’ve got conceptually-parallel, data-independent computations, you’ve got an applicative lurking somewhere under the surface (even if it happens to be merely the <code>Identity</code> applicative.)</p>
<p>I’ve had a similar insight about lenses, and that’s what I wanted to write about today.</p>
<h2 id="the-context">The Context</h2>
<p>At work, I’ve been thinking a lot about compilers and memory layout lately. I won’t get into the specifics of why, but we can come up with an inspired example. Imagine we’d like to use Haskell to write a little eDSL that we will use to generate x86 machine code.</p>
<p>The trick of course, is that we’re writing Haskell in order to <em>not</em> write machine code. So the goal is to design high-level combinators in Haskell that express our intent, while simultaneously generating machine code that faithfully implements the intention.</p>
<p>One particularly desirable feature about eDSLs is that they allow us to reuse Haskell’s type system. Thus, imagine we have some type:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">Code</span><span class="ot"> ::</span> <span class="dt">Type</span> <span class="ot">-&gt;</span> <span class="dt">Type</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Code</span> a <span class="ot">=</span> <span class="dt">Code</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>  {<span class="ot"> getMachineCode ::</span> [<span class="dt">X86OpCode</span>]</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>  }</span></code></pre></div>
<p>Notice that the <code>a</code> parameter here is entirely phantom; it serves only to annotate the type of the value produced by executing <code>getMachineCode</code>. For today’s purpose, we’ll ignore all the details about calling conventions and register layout and what not; let’s just assume a <code>Code a</code> corresponds to a computation that leaves a value (or pointer) to something of type <code>a</code> in a well-known place, whether that be the top of the stack, or <code>eax</code> or something. It doesn’t matter!</p>
<p>Since the type parameter to <code>Code</code> is phantom, we need to think about what <a href="https://reasonablypolymorphic.com/blog/roles/index.html">role</a> it should have. Keeping it at <code>phantom</code> would be disastrous, since this type isn’t used by <em>Haskell</em>, but it is certainly used to ensure our program is correct. Similarly, <code>representational</code> seems wrong, since <code>coerce</code> is meaningful only when thinking about Haskell; which this thing decidedly is not. Thus, our only other option is:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> role <span class="dt">Code</span> nominal</span></code></pre></div>
<p>Frustratingly, due to very similar reasoning, <code>Code</code> cannot be a functor, because there’s no way<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a> to lift an arbitrary Haskell function <code>a -&gt; b</code> into a corresponding function <code>Code a -&gt; Code b</code>. If there were, we’d be in the clear! But alas, we are not.</p>
<h2 id="the-problem">The Problem</h2>
<p>All of the above is to say that we are reusing Haskell’s <em>type system</em>, but not its <em>values</em>. An expression of type <code>Code Bool</code> has <em>absolutely no relation</em> to the values <code>True</code> or <code>False</code>—except that we could write, by hand, a function <code>litBool :: Bool -&gt; Code Bool</code> which happened to do the right thing.</p>
<p>It is tempting, however, to make new Haskell types in order to help constrain the assembly code we end up writing. For example, maybe we want to write a DSP for efficiently decoding audio. We can use Haskell’s types to organize our thoughts and prevent ourselves from making any stupid mistakes:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell"><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">Decoder</span> <span class="ot">=</span> <span class="dt">Decoder</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>  {<span class="ot"> format ::</span> <span class="dt">Format</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>  ,<span class="ot"> seekPos ::</span> <span class="dt">Int</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>  ,<span class="ot"> state ::</span> <span class="dt">ParserState</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>  }</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="kw">data</span> <span class="dt">Chunk</span> <span class="ot">=</span> <span class="op">...</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="ot">createDecoder ::</span> <span class="dt">Code</span> <span class="dt">MediaHandle</span> <span class="ot">-&gt;</span> <span class="dt">Code</span> <span class="dt">Decoder</span></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a><span class="ot">decodeChunk ::</span> <span class="dt">Code</span> <span class="dt">Decoder</span> <span class="ot">-&gt;</span> (<span class="dt">Code</span> <span class="dt">Decoder</span>, <span class="dt">Code</span> <span class="dt">Chunk</span>)</span></code></pre></div>
<p>We now have a nice interface in our eDSL to guide end-users along the blessed path of signal decoding. We have documented what we are trying to do, and how it can be used once it’s implemented. But due to our phantom, yet <code>nominal</code>, parameter to <code>Code</code>, this is all just make believe. There is absolutely no correlation between what we’ve written down and how we can use it. The problem arises when we go to implement <code>decodeChunk</code>. We’ll need to know what state we’re in, which means we’ll need some function:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="ot">decoderState ::</span> <span class="dt">Code</span> <span class="dt">Decoder</span> <span class="ot">-&gt;</span> <span class="dt">Code</span> <span class="dt">ParserState</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>decoderState <span class="ot">=</span> <span class="op">???</span></span></code></pre></div>
<p>In a world where <code>Code</code> is a functor, this is implemented trivially as <code>fmap state</code>. <em>But <code>Code</code> is not a functor!</em> Alas! Woe! What ever can we do?</p>
<h2 id="the-solution">The Solution</h2>
<p>Lenses, my guy!</p>
<p>Recall that <code>Code</code> is phantom in its argument, even if we use roles to restrict that fact. This means we can implement a safe-ish version of <code>unsafeCoerce</code>, that only fiddles with the paramater of our phantom type:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="ot">unsafeCoerceCode ::</span> <span class="dt">Code</span> a <span class="ot">-&gt;</span> <span class="dt">Code</span> b</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>unsafeCoerceCode (<span class="dt">Code</span> ops) <span class="ot">=</span> <span class="dt">Code</span> ops</span></code></pre></div>
<p>Judicious use of <code>unsafeCoerceCode</code> allows us to switch between a value’s type and its in-memory representation. For example, given a type:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">Bytes</span><span class="ot"> ::</span> <span class="dt">Nat</span> <span class="ot">-&gt;</span> <span class="dt">Type</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Bytes</span> n</span></code></pre></div>
<p>we can reinterpret a <code>Decode</code> as a sequence of bytes:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="ot">decoderRep ::</span> <span class="dt">Iso&#39;</span> (<span class="dt">Code</span> <span class="dt">Decoder</span>) (<span class="dt">Code</span> (<span class="dt">Bytes</span> (<span class="dv">32</span> <span class="op">+</span> <span class="dv">4</span> <span class="op">+</span> <span class="dv">1</span>)))</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>decoderRep <span class="ot">=</span> iso unsafeCoerceCode unsafeCoerceCode</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="ot">stateRep ::</span> <span class="dt">Iso&#39;</span> (<span class="dt">Code</span> <span class="dt">ParserState</span>) (<span class="dt">Code</span> (<span class="dt">Bytes</span> <span class="dv">1</span>))</span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>stateRep <span class="ot">=</span> iso unsafeCoerceCode unsafeCoerceCode</span></code></pre></div>
<p>which says we are considering our <code>Decoder</code> to be laid out in memory like:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Decoder <span class="op">{</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>  <span class="dt">char</span> format<span class="op">[</span><span class="dv">32</span><span class="op">];</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>  <span class="dt">int32_t</span> seekPos<span class="op">;</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>  <span class="dt">char</span> state<span class="op">;</span></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
<p>Of course, this is a completely unsafe transformation, as far as the Haskell type system is aware. We’re in the wild west out here, well past any type theoretical life buoys. We’d better be right that this coercion is sound. But assuming this <em>is</em> in fact the in-memory representation of a <code>Decoder</code>, we are well justified in this transformation.</p>
<p>Notice the phrasing of our <code>Iso'</code> above. It is not an iso between <code>Decoder</code> and <code>Bytes 37</code>, but between <em><code>Code</code>s</em> of such things. This witnesses the fact that it is not true in the Haskell embedding, merely in our <code>Code</code> domain. Of course, isos are like the least exciting optics, so let’s see what other neat things we can do.</p>
<p>Imagine we have some primitives:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>slice</span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="ot">    ::</span> n <span class="op">&lt;=</span> m</span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>    <span class="ot">=&gt;</span> <span class="dt">Int</span>     <span class="co">-- ^ offset</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>    <span class="ot">-&gt;</span> <span class="dt">Proxy</span> n <span class="co">-- ^ size</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>    <span class="ot">-&gt;</span> <span class="dt">Code</span> (<span class="dt">Bytes</span> m)</span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a>    <span class="ot">-&gt;</span> <span class="dt">Code</span> (<span class="dt">Bytes</span> n)</span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a>overwrite</span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a><span class="ot">    ::</span> n <span class="op">&lt;=</span> m</span>
<span id="cb9-10"><a href="#cb9-10" aria-hidden="true" tabindex="-1"></a>    <span class="ot">=&gt;</span> <span class="dt">Int</span>  <span class="co">-- ^ offset</span></span>
<span id="cb9-11"><a href="#cb9-11" aria-hidden="true" tabindex="-1"></a>    <span class="ot">-&gt;</span> <span class="dt">Bytes</span> n</span>
<span id="cb9-12"><a href="#cb9-12" aria-hidden="true" tabindex="-1"></a>    <span class="ot">-&gt;</span> <span class="dt">Bytes</span> m</span>
<span id="cb9-13"><a href="#cb9-13" aria-hidden="true" tabindex="-1"></a>    <span class="ot">-&gt;</span> <span class="dt">Bytes</span> m</span></code></pre></div>
<p>which we can envision as Haskell bindings to the pseudo-C functions:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="dt">const</span> <span class="dt">char</span><span class="op">[</span>n<span class="op">]</span> slice<span class="op">(</span><span class="dt">size_t</span> offset<span class="op">,</span> <span class="dt">char</span><span class="op">[</span>m<span class="op">]</span> bytes<span class="op">)</span> <span class="op">{</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> <span class="op">&amp;</span>bytes<span class="op">[</span>offset<span class="op">];</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a><span class="dt">char</span><span class="op">[</span>m<span class="op">]</span> overwrite<span class="op">(</span><span class="dt">size_t</span> offset<span class="op">,</span> <span class="dt">char</span><span class="op">[</span>n<span class="op">]</span> value<span class="op">,</span> <span class="dt">char</span><span class="op">[</span>m<span class="op">]</span> bytes<span class="op">)</span> <span class="op">{</span></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a>  <span class="dt">char</span><span class="op">[</span>m<span class="op">]</span> new_bytes <span class="op">=</span> malloc<span class="op">(</span>m<span class="op">);</span></span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a>  memcpy<span class="op">(</span>new_bytes<span class="op">,</span> bytes<span class="op">,</span> m<span class="op">);</span></span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a>  memcpy<span class="op">(&amp;</span>new_bytes<span class="op">[</span>offset<span class="op">],</span> value<span class="op">,</span> n<span class="op">);</span></span>
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> new_bytes<span class="op">;</span></span>
<span id="cb10-10"><a href="#cb10-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>We can use <code>slice</code> and <code>overwrite</code> to give a <code>Lens'</code> into <code>Bytes</code>:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="ot">slicing ::</span> n <span class="op">&lt;=</span> m <span class="ot">=&gt;</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Code</span> (<span class="dt">Bytes</span> m) <span class="ot">-&gt;</span> <span class="dt">Code</span> (<span class="dt">Bytes</span> n)</span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>slicing offset <span class="ot">=</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>  lens</span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>    (slice offset <span class="dt">Proxy</span>)</span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>    (\orig new <span class="ot">-&gt;</span> overwrite offset new orig)</span></code></pre></div>
<p>and finally, we can give an implementation of the desired <code>decoderState</code> above:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="ot">decoderState ::</span> <span class="dt">Lens&#39;</span> (<span class="dt">Code</span> <span class="dt">Decoder</span>) (<span class="dt">Code</span> <span class="dt">ParserState</span>)</span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>decoderState <span class="ot">=</span> decoderRep <span class="op">.</span> slicing <span class="dv">36</span> <span class="op">.</span> from stateRep</span></code></pre></div>
<p>Such a lens acts exactly as a record selector would, in that it allows us to <code>view</code>, <code>set</code>, and <code>over</code> a <code>ParserState</code> inside of a <code>Decoder</code>. But recall that <code>Code</code> is just a list of instructions we eventually want the machine to run. We’re using the shared vocabulary of lenses to <em>emit machine code!</em> What looks like using a data structure to us when viewed through the Haskell perspective, is instead invoking an assembler.</p>
<h2 id="reflections">Reflections</h2>
<p>Once the idea sinks in, you’ll start seeing all sorts of cool things you can do with optics to generate code. <code>Prism</code>s generalize running initializer code. A <code>Traversal</code> over <code>Code</code> can be implemented as a loop. And since all the sizes are known statically, if you’re feeling plucky, you can decide to unroll the loop right there in the lens.</p>
<p>Outside of the context of <code>Code</code>, the realization that optics are <em>this general</em> is still doing my head in. Something I love about working in Haskell is that I’m still regularly having my mind blown, even after a decade.</p>
<section class="footnotes" role="doc-endnotes">
<hr />
<ol>
<li id="fn1" role="doc-endnote"><p>Short of <a href="http://conal.net/papers/compiling-to-categories/compiling-to-categories.pdf">compiling to categories</a> via something like <a href="https://github.com/con-kitty/categorifier">categorifier</a>.<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
        ]]>
      </content>
    </entry>
    <entry>
      <title>Read the Code, Not the Profile</title>
      <id>blog/read-the-code/index.html</id>
      <link href='blog/read-the-code/index.html'/>
      <published>2025-01-12T15:29:00Z</published>
      <updated>2025-01-12T15:29:00Z</updated>

      <content type="html" xml:base="https://reasonablypolymorphic.com">
        <![CDATA[
        <p>At work a few weeks back, I found myself digging into profile reports, trying to determine why our program was running so slowly. Despite having the extremely obvious-in-retrospect data in front of me, I wasted a lot of time speeding up code that turned out to not move the needle at all.</p>
<p>Although perhaps it will be interesting only to future me, I thought it would be a good exercise to write up the experience—if only so I learn the lesson about how to read profiles and not make the same mistake again.</p>
<h2 id="some-context">Some Context</h2>
<p>I’m currently employed to work on a compiler. The performance has never been stellar, in that we were usually seeing about 5s to compile programs, even trivially small ones consisting of less than a hundred instructions. It was painful, but not <em>that</em> painful, since the test suite still finished in a minute or two. It was a good opportunity to get a coffee. I always assumed that the time penalties we were seeing were constant factors; perhaps it took a second or two to connect to Z3 or something like that.</p>
<p>But then we started unrolling loops, which turned <em>trivially</em> small programs into <em>merely</em> small programs, and our performance ballooned. Now we were looking at 45s for some of our tests! Uh oh! That’s no longer in the real of constant factors, and it was clear that something asymptotically was wrong.</p>
<p>So I fired up GHC with the trusty old <code>-prof</code> flag, and ran the test suite in <code>+RTS -p</code> mode, which instruments the program with all sorts of profiling goodies. After a few minutes, the test suite completed, and left a <code>test-suite.prof</code> file laying around in the current directory. You can inspect such things by hand, but tools like <a href="https://github.com/jaspervdj/profiteur">profiteur</a> make the experience much nicer.</p>
<p>Without further ado, here’s what our profile looked like:</p>
<pre><code>MAIN . . . . . . . . . . . . . . . . . . . . . . . . 100%</code></pre>
<p>Well, that’s not very helpful. Of course <code>MAIN</code> takes 100% of the time. So I expanded that, and saw:</p>
<pre><code>MAIN . . . . . . . . . . . . . . . . . . . . . . . . 100%
└ main . . . . . . . . . . . . . . . . . . . . . . . 100%</code></pre>
<p>No clearer. Opening up <code>main</code>:</p>
<pre><code>MAIN . . . . . . . . . . . . . . . . . . . . . . . . 100%
└ main . . . . . . . . . . . . . . . . . . . . . . . 100%
  └ main.\ . . . . . . . . . . . . . . . . . . . . . 100%</code></pre>
<p>Sheesh.</p>
<pre><code>MAIN . . . . . . . . . . . . . . . . . . . . . . . . 100%
└ main . . . . . . . . . . . . . . . . . . . . . . . 100%
  └ main.\ . . . . . . . . . . . . . . . . . . . . . 100%
    └ getTest  . . . . . . . . . . . . . . . . . . . 100%</code></pre>
<p>OH MY GOD. JUST TELL ME SOMETHING ALREADY.</p>
<pre><code>MAIN . . . . . . . . . . . . . . . . . . . . . . . . 100%
└ main . . . . . . . . . . . . . . . . . . . . . . . 100%
  └ main.\ . . . . . . . . . . . . . . . . . . . . . 100%
    └ getTest  . . . . . . . . . . . . . . . . . . . 100%
      └ test . . . . . . . . . . . . . . . . . . . . 100%</code></pre>
<p>Fast forwarding for <em>quite</em> a while, I opened up the entire stack until I got to something that <em>didn’t</em> take 100% of the program’s runtime:</p>
<pre><code>MAIN . . . . . . . . . . . . . . . . . . . . . . . . 100%
└ main . . . . . . . . . . . . . . . . . . . . . . . 100%
  └ main.\ . . . . . . . . . . . . . . . . . . . . . 100%
    └ getTest  . . . . . . . . . . . . . . . . . . . 100%
      └ test . . . . . . . . . . . . . . . . . . . . 100%
        └ makeTest . . . . . . . . . . . . . . . . . 100%
          └ makeTest.\ . . . . . . . . . . . . . . . 100%
            └ compileProgram . . . . . . . . . . . . 100%
              └ evalAppT . . . . . . . . . . . . . . 100%
                └ runAppT  . . . . . . . . . . . . . 100%
                  └ runAppT&#39; . . . . . . . . . . . . 100%
                    └ withLogging  . . . . . . . . . 100%
                      └ transformSSA . . . . . . . . 100%
                        └ &gt;&gt;=  . . . . . . . . . . . 100%
                          └ &gt;&gt;&gt;= . . . . . . . . . . 100%
                            └ ibind  . . . . . . . . 100%
                              └ ibind.\  . . . . . . 100%
                                └ ibind.\.\  . . . . 100%
                                  ├ toSSA  . . . . . 15%
                                  ├ transform1 . . . 15%
                                  ├ transform2 . . . 10%
                                  ├ transform3 . . . 10%
                                  ├ transform4 . . . 20%
                                  └ collectGarbage . 30%</code></pre>
<p>Now we’re in business. I dutifully dug into <code>toSSA</code>, the transforms, and <code>collectGarbage</code>. I cached some things, used better data structures, stopped appending lists, you know, the usual Haskell tricks. My work was rewarded, in that I managed to shave 80% off the runtime of our program.</p>
<p>A few months later, we wrote a bigger program and fed it to the compiler. This one didn’t stop compiling. We left it overnight.</p>
<p>Uh oh. Turns out I hadn’t fixed the problem. I’d only papered over it.</p>
<h2 id="retrospective">Retrospective</h2>
<p>So what went wrong here? Quite a lot, in fact! And worse, I had all of the information all along, but managed to misinterpret it at several steps of the process.</p>
<p>Unwinding the story stack, the most salient aspect of having not solved the problem was reducing the runtime by <em>only</em> 80%. Dramatic percentages <em>feel</em> like amazing improvements, but that’s because human brains are poorly designed for building software. In the real world, big percentages are fantastic. In software, they are <em>linear</em> improvements.</p>
<p>That is to say that a percentage-based improvement is <span class="math inline">\(O(n)\)</span> faster in the best case. My efforts improved our runtime from 45s to 9s. Which feels great, but the <em>real</em> problem is that this program is <em>measured in seconds</em> at all.</p>
<p>It’s more informative to think in terms of orders of magnitude. Taking 45s on a ~3GHz processor is on the order of 10<sup>11</sup> instructions, while 9s is 10<sup>10</sup>. How the <em>hell</em> is it taking us TEN BILLION instructions to compile a dinky little program? That’s the <em>real problem.</em> Improving things from one hundred billion down to ten billion is no longer very impressive at all.</p>
<p>To get a sense of the scale here, even if we spent 1M cycles (which feels conservatively expensive) for each instruction we wanted to compile, we should <em>still</em> be looking at &lt; 0.1s. Somehow we are over 1000x worse than that.</p>
<p>So that’s one mistake I made: being impressed by extremely marginal improvements. Bad Sandy.</p>
<p>The other mistake came from my interpretation of the profile. As a quick pop quiz, scroll back up to the profile and see if you can spot where the problem is.</p>
<p>After expanding a few obviously-not-the-problem call centers that each were 100% of the runtime, I turned my brain off and opened <em>all</em> of the 100% nodes. But in doing so, I accidentally breezed past the real problem. The <em>real</em> problem is either that <code>compileProgram</code> takes 100% of the time of the test, or that <code>transformSSA</code> takes 100% of compiling the program. Why’s that? Because unlike <code>main</code> and co, <code>test</code> does more work than just compiling the program. It also does non-trivial IO to produce debugging outputs, and property checks the resulting programs. Similarly for <code>compileProgram</code>, which does a great deal more than <code>transformSSA</code>.</p>
<p>This is somewhat of a philosophical enlightenment. The program execution hasn’t changed at all, but our perspective has. Rather than micro-optimizing the code that <em>is</em> running, this new perspective suggests we should focus our effort on determining <em>why that code is running in the first place.</em></p>
<p>Digging through <code>transformSSA</code> made it <em>very obvious</em> the problem was an algorithmic one—we were running an unbounded loop that terminated on convergence, where each step it took <span class="citation" data-cites="O">@O</span>(n^2)@ work to make a single step. When I stopped to actually <em>read</em> the code, the problem was immediate, and the solution obvious.</p>
<p>The lesson? Don’t read the profile. Read the code. Use the profile to focus your attention.</p>
        ]]>
      </content>
    </entry>
</feed>

