<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
    <channel>
        <title>Smaller Infinity</title>
        <link>https://blog.smaller-infinity.com/</link>
        <description>This is my cool site</description>
        <generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Mon, 19 May 2025 00:00:00 -0400</lastBuildDate>
            <atom:link href="https://blog.smaller-infinity.com/index.xml" rel="self" type="application/rss+xml" />
        <item>
    <title>Lazy Combinations in Elixir</title>
    <link>https://blog.smaller-infinity.com/posts/lazy-combinations-in-elixir/</link>
    <pubDate>Mon, 19 May 2025 00:00:00 -0400</pubDate>
    <author>Paul Ricks</author>
    <guid>https://blog.smaller-infinity.com/posts/lazy-combinations-in-elixir/</guid>
    <description><![CDATA[<p>When building <a href="https://gitlab.com/smaller-infinity/guesswork" target="_blank" rel="noopener noreffer ">Guesswork</a>, a logic programming library for <a href="https://elixir-lang.org/" target="_blank" rel="noopener noreffer ">Elixir</a>, I ran into an
interesting problem: supporting both logical <code>And</code> as well as infinite streams
of possibilities.
To give an example, the statement &lsquo;Let <code>A</code> be some positive number, and let <code>B</code> be
some factorial of <code>A</code>&rsquo;, has both an infinite stream of values (<code>A</code> could be 1, 2,
3, etc.) and a logical conjunction; it cannot be represented without both.</p>
<h2 id="background">Background</h2>
<p>At a basic level, Guesswork is pretty simple.
Each logical statement produces a stream of possible answers (which may be lazy
and could be infinite), and statements that take other statements as inputs (such
as <code>And</code>, <code>Or</code>, and <code>Not</code>) don&rsquo;t know anything about their inputs, aside from
the fact that they are <a href="https://hexdocs.pm/elixir/Enumerable.html" target="_blank" rel="noopener noreffer ">Enumerable</a>.
Furthermore, the calculations behind that <code>Enumerable</code> can be pretty expensive.
For <code>Or</code> and <code>Not</code>, this isn&rsquo;t much of an issue.
<code>Not</code> is very simple, it uses <a href="https://hexdocs.pm/elixir/Stream.html#map/2" target="_blank" rel="noopener noreffer ">Stream.map/2</a> to turn each answer into it&rsquo;s logical
negation, and <code>Or</code> uses <a href="https://hexdocs.pm/elixir/Stream.html#concat/1" target="_blank" rel="noopener noreffer ">Stream.concat/1</a><sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>.</p>
<p><code>And</code>, however, is more complicated.
For <code>And</code> to produce a single answer it takes a single answer from each of its
inputs, and uses <a href="https://hexdocs.pm/guesswork/Guesswork.Answer.html#union/2" target="_blank" rel="noopener noreffer ">Guesswork.Answer.union/2</a> to combine them.
But to build the next answer, only a single answer is pulled from a single input,
and then combined with the already pulled answers from the other streams.
So not only must <code>And</code> hold all the previously pulled answers in some form of
state, but it must then produce the new answers in a lazy fashion.</p>
<h2 id="an-eager-attempt">An Eager Attempt</h2>
<p>Before doing the hard work of building a lazy version, we&rsquo;ll build a simpler,
eager version<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>.
The answer sets are just maps of terms<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>, and two answer sets can be combined with
<code>union/2</code>, provided that they have the same terms for all values.</p>
<div class="code-block code-line-numbers" style="counter-reset: code-block 0">
    <div class="code-header language-elixir">
        <span class="code-title"><i class="arrow fas fa-angle-right fa-fw" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h fa-fw" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy fa-fw" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-elixir" data-lang="elixir"><span class="line"><span class="cl"><span class="kd">defmodule</span> <span class="nc">LazyCombinations.Answer</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">  <span class="na">@type</span> <span class="n">t</span><span class="p">()</span> <span class="o">::</span> <span class="p">%{</span><span class="n">atom</span><span class="p">()</span> <span class="o">=&gt;</span> <span class="n">term</span><span class="p">()}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="na">@spec</span> <span class="n">new</span><span class="p">()</span> <span class="o">::</span> <span class="n">t</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="kd">def</span> <span class="n">new</span><span class="p">()</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="p">%{}</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="na">@spec</span> <span class="n">union</span><span class="p">(</span><span class="n">t</span><span class="p">(),</span> <span class="n">t</span><span class="p">())</span> <span class="o">::</span> <span class="n">t</span><span class="p">()</span> <span class="o">|</span> <span class="no">nil</span>
</span></span><span class="line"><span class="cl">  <span class="kd">def</span> <span class="n">union</span><span class="p">(</span><span class="n">a1</span><span class="p">,</span> <span class="n">a2</span><span class="p">)</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="n">new</span> <span class="o">=</span>
</span></span><span class="line"><span class="cl">      <span class="nc">Map</span><span class="o">.</span><span class="n">merge</span><span class="p">(</span><span class="n">a1</span><span class="p">,</span> <span class="n">a2</span><span class="p">,</span> <span class="k">fn</span>
</span></span><span class="line"><span class="cl">        <span class="n">_</span><span class="p">,</span> <span class="n">t</span><span class="p">,</span> <span class="n">t</span> <span class="o">-&gt;</span> <span class="n">t</span>
</span></span><span class="line"><span class="cl">        <span class="n">_</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span> <span class="o">-&gt;</span> <span class="no">nil</span>
</span></span><span class="line"><span class="cl">      <span class="k">end</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="nc">Enum</span><span class="o">.</span><span class="n">any?</span><span class="p">(</span><span class="n">new</span><span class="p">,</span> <span class="k">fn</span> <span class="p">{</span><span class="n">_</span><span class="p">,</span> <span class="n">t</span><span class="p">}</span> <span class="o">-&gt;</span> <span class="n">t</span> <span class="o">==</span> <span class="no">nil</span> <span class="k">end</span><span class="p">)</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">      <span class="no">nil</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span>
</span></span><span class="line"><span class="cl">      <span class="n">new</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div>
<p>Building on the answer set, anding sets together is surprisingly<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>
straightforward.
<a href="https://hexdocs.pm/elixir/Enum.html#reduce/2" target="_blank" rel="noopener noreffer ">Enum.reduce/2</a> allows us to walk through the <code>args</code>, unioning all possible pairs
together, and removing all invalid combinations.</p>
<div class="code-block code-line-numbers" style="counter-reset: code-block 0">
    <div class="code-header language-elixir">
        <span class="code-title"><i class="arrow fas fa-angle-right fa-fw" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h fa-fw" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy fa-fw" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-elixir" data-lang="elixir"><span class="line"><span class="cl"><span class="kd">defmodule</span> <span class="nc">LazyCombinations.EagerAnd</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">  <span class="kd">defstruct</span> <span class="p">[</span><span class="ss">:args</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kn">alias</span> <span class="nc">LazyCombinations.Answer</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="na">@type</span> <span class="n">t</span><span class="p">()</span> <span class="o">::</span> <span class="err">%</span><span class="n">__MODULE__</span><span class="p">{</span><span class="ss">args</span><span class="p">:</span> <span class="nc">Enumerable</span><span class="o">.</span><span class="n">t</span><span class="p">(</span><span class="nc">Answer</span><span class="o">.</span><span class="n">t</span><span class="p">())}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="na">@spec</span> <span class="n">new</span><span class="p">([</span><span class="nc">Enumerable</span><span class="o">.</span><span class="n">t</span><span class="p">(</span><span class="nc">Answer</span><span class="o">.</span><span class="n">t</span><span class="p">())])</span> <span class="o">::</span> <span class="n">t</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="kd">def</span> <span class="n">new</span><span class="p">(</span><span class="n">args</span><span class="p">)</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="err">%</span><span class="n">__MODULE__</span><span class="p">{</span><span class="ss">args</span><span class="p">:</span> <span class="n">args</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="na">@spec</span> <span class="n">resolve</span><span class="p">(</span><span class="n">t</span><span class="p">())</span> <span class="o">::</span> <span class="p">[</span><span class="nc">Answer</span><span class="o">.</span><span class="n">t</span><span class="p">()]</span>
</span></span><span class="line"><span class="cl">  <span class="kd">def</span> <span class="n">resolve</span><span class="p">(</span><span class="err">%</span><span class="n">__MODULE__</span><span class="p">{</span><span class="ss">args</span><span class="p">:</span> <span class="n">args</span><span class="p">})</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="nc">Enum</span><span class="o">.</span><span class="n">reduce</span><span class="p">(</span><span class="n">args</span><span class="p">,</span> <span class="k">fn</span> <span class="n">val</span><span class="p">,</span> <span class="n">acc</span> <span class="o">-&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="nc">Enum</span><span class="o">.</span><span class="n">flat_map</span><span class="p">(</span><span class="n">val</span><span class="p">,</span> <span class="k">fn</span> <span class="n">val_item</span> <span class="o">-&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="n">acc</span>
</span></span><span class="line"><span class="cl">        <span class="o">|&gt;</span> <span class="nc">Enum</span><span class="o">.</span><span class="n">map</span><span class="p">(</span><span class="o">&amp;</span><span class="nc">Answer</span><span class="o">.</span><span class="n">union</span><span class="p">(</span><span class="ni">&amp;1</span><span class="p">,</span> <span class="n">val_item</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="o">|&gt;</span> <span class="nc">Enum</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="o">&amp;</span><span class="nc">Kernel</span><span class="o">.!=</span><span class="p">(</span><span class="ni">&amp;1</span><span class="p">,</span> <span class="no">nil</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">      <span class="k">end</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div>
<p>Finally, we can confirm that everything works.</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-elixir">
        <span class="code-title"><i class="arrow fas fa-angle-right fa-fw" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h fa-fw" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy fa-fw" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-elixir" data-lang="elixir"><span class="line"><span class="cl"><span class="n">arg1</span> <span class="o">=</span> <span class="p">[%{</span><span class="ss">a</span><span class="p">:</span> <span class="mi">1</span><span class="p">},</span> <span class="p">%{</span><span class="ss">a</span><span class="p">:</span> <span class="mi">2</span><span class="p">}]</span>
</span></span><span class="line"><span class="cl"><span class="n">arg2</span> <span class="o">=</span> <span class="p">[%{</span><span class="ss">b</span><span class="p">:</span> <span class="mi">1</span><span class="p">},</span> <span class="p">%{</span><span class="ss">b</span><span class="p">:</span> <span class="mi">2</span><span class="p">}]</span>
</span></span><span class="line"><span class="cl"><span class="n">arg3</span> <span class="o">=</span> <span class="p">[%{</span><span class="ss">c</span><span class="p">:</span> <span class="mi">1</span><span class="p">},</span> <span class="p">%{</span><span class="ss">c</span><span class="p">:</span> <span class="mi">2</span><span class="p">}]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nc">LazyCombinations.EagerAnd</span><span class="o">.</span><span class="n">new</span><span class="p">([</span><span class="n">arg1</span><span class="p">,</span> <span class="n">arg2</span><span class="p">,</span> <span class="n">arg3</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="o">|&gt;</span> <span class="nc">LazyCombinations.EagerAnd</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span></span></span></code></pre></div></div>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-text">
        <span class="code-title"><i class="arrow fas fa-angle-right fa-fw" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h fa-fw" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy fa-fw" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">[
</span></span><span class="line"><span class="cl">  %{c: 1, a: 1, b: 1},
</span></span><span class="line"><span class="cl">  %{c: 1, a: 2, b: 1},
</span></span><span class="line"><span class="cl">  %{c: 1, a: 1, b: 2},
</span></span><span class="line"><span class="cl">  %{c: 1, a: 2, b: 2},
</span></span><span class="line"><span class="cl">  %{c: 2, a: 1, b: 1},
</span></span><span class="line"><span class="cl">  %{c: 2, a: 2, b: 1},
</span></span><span class="line"><span class="cl">  %{c: 2, a: 1, b: 2},
</span></span><span class="line"><span class="cl">  %{c: 2, a: 2, b: 2}
</span></span><span class="line"><span class="cl">]</span></span></code></pre></div></div>
<h2 id="laziness">Laziness</h2>
<p>The above example is a good starting point, but it is obviously not exactly what
we want, because if we tried to represent &lsquo;Let <code>A</code> be some positive number&rsquo;<sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup>
and passed that stream of answer sets to the above <code>And</code>, the <code>resolve/1</code> function
would never return.</p>
<h3 id="iterating-over-streams">Iterating over Streams</h3>
<p>Before getting into the meat of this problem, we have to resolve the issue of
pulling items from our <code>Enumerable</code> inputs one at a time<sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup>.
As there is no way to do this directly in the standard library, we&rsquo;ll have to
use <a href="https://elixirforum.com/t/best-way-to-iterate-a-stream/24382" target="_blank" rel="noopener noreffer ">Enumerable.reduce/3</a>.
This is actually how many of the functions in the standard library are
implemented, and it provides very fine-grained control over how we iterate over
the data.</p>
<p>The <code>stream</code> here is another infinite list of numbers, built with
<a href="https://hexdocs.pm/elixir/Stream.html#iterate/2" target="_blank" rel="noopener noreffer ">Stream.iterate/2</a>.
To pull items one at a time we need to use a <code>reducer/0</code> function that always
returns <code>:suspend</code>, which in turn instructs <code>reduce/3</code> to pause the stream and
return the next value and a continuation.</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-elixir">
        <span class="code-title"><i class="arrow fas fa-angle-right fa-fw" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h fa-fw" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy fa-fw" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-elixir" data-lang="elixir"><span class="line"><span class="cl"><span class="n">stream</span> <span class="o">=</span> <span class="nc">Stream</span><span class="o">.</span><span class="n">iterate</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="o">&amp;</span><span class="nc">Kernel</span><span class="o">.+</span><span class="p">(</span><span class="ni">&amp;1</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="n">reduce_fun</span> <span class="o">=</span> <span class="k">fn</span> <span class="n">item</span><span class="p">,</span> <span class="n">_acc</span> <span class="o">-&gt;</span> <span class="p">{</span><span class="ss">:suspend</span><span class="p">,</span> <span class="n">item</span><span class="p">}</span> <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span><span class="ss">:suspended</span><span class="p">,</span> <span class="no">nil</span><span class="p">,</span> <span class="n">continuation</span><span class="p">}</span> <span class="o">=</span> <span class="nc">Enumerable</span><span class="o">.</span><span class="n">reduce</span><span class="p">(</span><span class="n">stream</span><span class="p">,</span> <span class="p">{</span><span class="ss">:suspend</span><span class="p">,</span> <span class="no">nil</span><span class="p">},</span> <span class="n">reduce_fun</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span><span class="ss">:suspended</span><span class="p">,</span> <span class="n">val</span><span class="p">,</span> <span class="n">continuation</span><span class="p">}</span> <span class="o">=</span> <span class="n">continuation</span><span class="o">.</span><span class="p">({</span><span class="ss">:cont</span><span class="p">,</span> <span class="no">nil</span><span class="p">})</span>
</span></span><span class="line"><span class="cl"><span class="n">val</span></span></span></code></pre></div></div>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-text">
        <span class="code-title"><i class="arrow fas fa-angle-right fa-fw" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h fa-fw" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy fa-fw" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">1</span></span></code></pre></div></div>
<p>Once we have the continuation we can just keep calling it with <code>{:cont, nil}</code>,
which instructs the closure to move the stream forward once, before the <code>reducer/0</code>
function suspends it again.</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-elixir">
        <span class="code-title"><i class="arrow fas fa-angle-right fa-fw" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h fa-fw" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy fa-fw" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-elixir" data-lang="elixir"><span class="line"><span class="cl"><span class="p">{</span><span class="ss">:suspended</span><span class="p">,</span> <span class="n">val</span><span class="p">,</span> <span class="n">continuation</span><span class="p">}</span> <span class="o">=</span> <span class="n">continuation</span><span class="o">.</span><span class="p">({</span><span class="ss">:cont</span><span class="p">,</span> <span class="no">nil</span><span class="p">})</span>
</span></span><span class="line"><span class="cl"><span class="n">val</span></span></span></code></pre></div></div>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-text">
        <span class="code-title"><i class="arrow fas fa-angle-right fa-fw" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h fa-fw" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy fa-fw" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">2</span></span></code></pre></div></div>
<h3 id="lazy-and">Lazy And</h3>
<p>To actually build a stream of values we are going to use <a href="https://hexdocs.pm/elixir/Stream.html#unfold/2" target="_blank" rel="noopener noreffer ">Stream.unfold/2</a>.
This function works for our purposes because it allows us to store state in an
accumulator.
We can then generate our sequence from that state, updating it as we go.
The exact details of that &lsquo;state&rsquo; are abstracted away here using a behavior<sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup>
where the important callback is <code>next_unions/1</code>.
<code>next_unions/1</code> just takes a list of converted streams and either indicates that
there is nothing left to calculate (<code>:empty</code> or <code>:done</code>) or returns a list of
&lsquo;unioned&rsquo; answer sets and the next version of the streams to keep in the accumulator.</p>
<div class="code-block code-line-numbers" style="counter-reset: code-block 0">
    <div class="code-header language-elixir">
        <span class="code-title"><i class="arrow fas fa-angle-right fa-fw" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h fa-fw" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy fa-fw" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-elixir" data-lang="elixir"><span class="line"><span class="cl"><span class="kd">defmodule</span> <span class="nc">LazyCombinations.LazyAnd</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">  <span class="kd">defstruct</span> <span class="p">[</span><span class="ss">:partial_module</span><span class="p">,</span> <span class="ss">:args</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kn">alias</span> <span class="nc">LazyCombinations.Answer</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="na">@callback</span> <span class="n">new</span><span class="p">(</span><span class="nc">Enumerable</span><span class="o">.</span><span class="n">t</span><span class="p">(</span><span class="nc">Answer</span><span class="o">.</span><span class="n">t</span><span class="p">()))</span> <span class="o">::</span> <span class="n">term</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="na">@doc</span> <span class="sh">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="sh">  Takes a list of partial evaluations and attempts to calculate the next set of
</span></span></span><span class="line"><span class="cl"><span class="sh">  unioned answer sets, based on the next evaluated answer set unioned with the
</span></span></span><span class="line"><span class="cl"><span class="sh">  previously evaluated answer sets.
</span></span></span><span class="line"><span class="cl"><span class="sh">  &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="na">@callback</span> <span class="n">next_unions</span><span class="p">([</span><span class="n">term</span><span class="p">()])</span> <span class="o">::</span> <span class="ss">:empty</span> <span class="o">|</span> <span class="ss">:done</span> <span class="o">|</span> <span class="p">{</span><span class="ss">:ok</span><span class="p">,</span> <span class="p">[</span><span class="n">term</span><span class="p">()],</span> <span class="p">[</span><span class="nc">Answer</span><span class="o">.</span><span class="n">t</span><span class="p">()]}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="na">@type</span> <span class="n">t</span><span class="p">()</span> <span class="o">::</span> <span class="err">%</span><span class="n">__MODULE__</span><span class="p">{</span><span class="ss">args</span><span class="p">:</span> <span class="nc">Enumerable</span><span class="o">.</span><span class="n">t</span><span class="p">(</span><span class="nc">Answer</span><span class="o">.</span><span class="n">t</span><span class="p">())}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="na">@spec</span> <span class="n">new</span><span class="p">(</span><span class="n">module</span><span class="p">(),</span> <span class="p">[</span><span class="nc">Enumerable</span><span class="o">.</span><span class="n">t</span><span class="p">(</span><span class="nc">Answer</span><span class="o">.</span><span class="n">t</span><span class="p">())])</span> <span class="o">::</span> <span class="n">t</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="kd">def</span> <span class="n">new</span><span class="p">(</span><span class="n">partial_module</span><span class="p">,</span> <span class="n">args</span><span class="p">)</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="err">%</span><span class="n">__MODULE__</span><span class="p">{</span><span class="ss">partial_module</span><span class="p">:</span> <span class="n">partial_module</span><span class="p">,</span> <span class="ss">args</span><span class="p">:</span> <span class="n">args</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="na">@spec</span> <span class="n">resolve</span><span class="p">(</span><span class="n">t</span><span class="p">())</span> <span class="o">::</span> <span class="nc">Enumerable</span><span class="o">.</span><span class="n">t</span><span class="p">(</span><span class="nc">Answer</span><span class="o">.</span><span class="n">t</span><span class="p">())</span>
</span></span><span class="line"><span class="cl">  <span class="kd">def</span> <span class="n">resolve</span><span class="p">(</span><span class="err">%</span><span class="n">__MODULE__</span><span class="p">{</span><span class="ss">args</span><span class="p">:</span> <span class="n">args</span><span class="p">,</span> <span class="ss">partial_module</span><span class="p">:</span> <span class="n">partial_module</span><span class="p">})</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="n">streams</span> <span class="o">=</span> <span class="nc">Enum</span><span class="o">.</span><span class="n">map</span><span class="p">(</span><span class="n">args</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">partial_module</span><span class="o">.</span><span class="n">new</span><span class="o">/</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="nc">Stream</span><span class="o">.</span><span class="n">unfold</span><span class="p">({</span><span class="n">streams</span><span class="p">,</span> <span class="p">[]},</span> <span class="o">&amp;</span><span class="n">unfold_streams</span><span class="p">(</span><span class="ni">&amp;1</span><span class="p">,</span> <span class="n">partial_module</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">def</span> <span class="n">unfold_streams</span><span class="p">({</span><span class="n">streams</span><span class="p">,</span> <span class="p">[]},</span> <span class="n">partial_module</span><span class="p">)</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="k">case</span> <span class="n">partial_module</span><span class="o">.</span><span class="n">next_unions</span><span class="p">(</span><span class="n">streams</span><span class="p">)</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">      <span class="ss">:empty</span> <span class="o">-&gt;</span> <span class="no">nil</span>
</span></span><span class="line"><span class="cl">      <span class="ss">:done</span> <span class="o">-&gt;</span> <span class="no">nil</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span><span class="ss">:ok</span><span class="p">,</span> <span class="n">new_streams</span><span class="p">,</span> <span class="n">unions</span><span class="p">}</span> <span class="o">-&gt;</span> <span class="n">unfold_streams</span><span class="p">({</span><span class="n">new_streams</span><span class="p">,</span> <span class="n">unions</span><span class="p">},</span> <span class="n">partial_module</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">def</span> <span class="n">unfold_streams</span><span class="p">({</span><span class="n">streams</span><span class="p">,</span> <span class="p">[</span><span class="n">head</span> <span class="o">|</span> <span class="n">rest</span><span class="p">]},</span> <span class="n">_</span><span class="p">),</span> <span class="ss">do</span><span class="p">:</span> <span class="p">{</span><span class="n">head</span><span class="p">,</span> <span class="p">{</span><span class="n">streams</span><span class="p">,</span> <span class="n">rest</span><span class="p">}}</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div>
<p>There is a lot of code in the state below, but that is mostly handling all the
edge cases.
The first bit, <code>new/1</code> and <code>head/1</code> are just modified versions of the iterated
stream we saw above.
The only noticeable difference is that a <code>defstruct</code> is used to hold the
<code>continuation</code> (stream) and the previously <code>evaluated</code> answer sets.</p>
<p>The rest of the module is spent implementing <code>next_unions/1</code>, which simply
works through the streams, pulling an answer set if nothing has been evaluated,
and &lsquo;unioning&rsquo; everything together as it works.</p>
<div class="code-block code-line-numbers" style="counter-reset: code-block 0">
    <div class="code-header language-elixir">
        <span class="code-title"><i class="arrow fas fa-angle-right fa-fw" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h fa-fw" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy fa-fw" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-elixir" data-lang="elixir"><span class="line"><span class="cl"><span class="kd">defmodule</span> <span class="nc">LazyCombinations.LazyAnd.SimplePartiallyEvaluated</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">  <span class="na">@behaviour</span> <span class="nc">LazyCombinations.LazyAnd</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">defstruct</span> <span class="p">[</span><span class="ss">:continuation</span><span class="p">,</span> <span class="ss">evaluated</span><span class="p">:</span> <span class="p">[]]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kn">alias</span> <span class="nc">LazyCombinations.Answer</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="na">@type</span> <span class="n">t</span><span class="p">()</span> <span class="o">::</span> <span class="err">%</span><span class="n">__MODULE__</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="ss">continuation</span><span class="p">:</span> <span class="nc">Enumerable</span><span class="o">.</span><span class="n">continuation</span><span class="p">()</span> <span class="o">|</span> <span class="no">nil</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="ss">evaluated</span><span class="p">:</span> <span class="p">[</span><span class="nc">Answer</span><span class="o">.</span><span class="n">t</span><span class="p">()]</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="na">@impl</span> <span class="no">true</span>
</span></span><span class="line"><span class="cl">  <span class="na">@spec</span> <span class="n">new</span><span class="p">(</span><span class="nc">Enumerable</span><span class="o">.</span><span class="n">t</span><span class="p">(</span><span class="nc">Answer</span><span class="o">.</span><span class="n">t</span><span class="p">()))</span> <span class="o">::</span> <span class="n">t</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="kd">def</span> <span class="n">new</span><span class="p">(</span><span class="n">stream</span><span class="p">)</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="n">reduce_fun</span> <span class="o">=</span> <span class="k">fn</span> <span class="n">item</span><span class="p">,</span> <span class="n">_acc</span> <span class="o">-&gt;</span> <span class="p">{</span><span class="ss">:suspend</span><span class="p">,</span> <span class="n">item</span><span class="p">}</span> <span class="k">end</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="ss">:suspended</span><span class="p">,</span> <span class="no">nil</span><span class="p">,</span> <span class="n">continuation</span><span class="p">}</span> <span class="o">=</span> <span class="nc">Enumerable</span><span class="o">.</span><span class="n">reduce</span><span class="p">(</span><span class="n">stream</span><span class="p">,</span> <span class="p">{</span><span class="ss">:suspend</span><span class="p">,</span> <span class="no">nil</span><span class="p">},</span> <span class="n">reduce_fun</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="err">%</span><span class="n">__MODULE__</span><span class="p">{</span><span class="ss">continuation</span><span class="p">:</span> <span class="n">continuation</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="na">@spec</span> <span class="n">head</span><span class="p">(</span><span class="n">t</span><span class="p">())</span> <span class="o">::</span> <span class="n">t</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="kd">def</span> <span class="n">head</span><span class="p">(</span><span class="err">%</span><span class="n">__MODULE__</span><span class="p">{</span><span class="ss">continuation</span><span class="p">:</span> <span class="no">nil</span><span class="p">}</span> <span class="o">=</span> <span class="n">stream</span><span class="p">),</span> <span class="ss">do</span><span class="p">:</span> <span class="n">stream</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">def</span> <span class="n">head</span><span class="p">(</span><span class="err">%</span><span class="n">__MODULE__</span><span class="p">{</span><span class="ss">continuation</span><span class="p">:</span> <span class="n">continuation</span><span class="p">,</span> <span class="ss">evaluated</span><span class="p">:</span> <span class="n">evaluated</span><span class="p">})</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="k">case</span> <span class="n">continuation</span><span class="o">.</span><span class="p">({</span><span class="ss">:cont</span><span class="p">,</span> <span class="no">nil</span><span class="p">})</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span><span class="ss">:suspended</span><span class="p">,</span> <span class="n">item</span><span class="p">,</span> <span class="n">continuation</span><span class="p">}</span> <span class="o">-&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="err">%</span><span class="n">__MODULE__</span><span class="p">{</span><span class="ss">continuation</span><span class="p">:</span> <span class="n">continuation</span><span class="p">,</span> <span class="ss">evaluated</span><span class="p">:</span> <span class="p">[</span><span class="n">item</span> <span class="o">|</span> <span class="n">evaluated</span><span class="p">]}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="p">{</span><span class="ss">:halted</span><span class="p">,</span> <span class="n">item</span><span class="p">}</span> <span class="o">-&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="err">%</span><span class="n">__MODULE__</span><span class="p">{</span><span class="ss">continuation</span><span class="p">:</span> <span class="no">nil</span><span class="p">,</span> <span class="ss">evaluated</span><span class="p">:</span> <span class="p">[</span><span class="n">item</span> <span class="o">|</span> <span class="n">evaluated</span><span class="p">]}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="p">{</span><span class="ss">:done</span><span class="p">,</span> <span class="no">nil</span><span class="p">}</span> <span class="o">-&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="err">%</span><span class="n">__MODULE__</span><span class="p">{</span><span class="ss">continuation</span><span class="p">:</span> <span class="no">nil</span><span class="p">,</span> <span class="ss">evaluated</span><span class="p">:</span> <span class="n">evaluated</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="na">@spec</span> <span class="n">done?</span><span class="p">(</span><span class="n">t</span><span class="p">())</span> <span class="o">::</span> <span class="n">boolean</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="kd">def</span> <span class="n">done?</span><span class="p">(</span><span class="err">%</span><span class="n">__MODULE__</span><span class="p">{</span><span class="ss">continuation</span><span class="p">:</span> <span class="n">continuation</span><span class="p">})</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="n">continuation</span> <span class="o">==</span> <span class="no">nil</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="na">@impl</span> <span class="no">true</span>
</span></span><span class="line"><span class="cl">  <span class="na">@spec</span> <span class="n">next_unions</span><span class="p">([</span><span class="n">t</span><span class="p">()])</span> <span class="o">::</span> <span class="ss">:empty</span> <span class="o">|</span> <span class="ss">:done</span> <span class="o">|</span> <span class="p">{</span><span class="ss">:ok</span><span class="p">,</span> <span class="p">[</span><span class="n">t</span><span class="p">()],</span> <span class="p">[</span><span class="nc">Answer</span><span class="o">.</span><span class="n">t</span><span class="p">()]}</span>
</span></span><span class="line"><span class="cl">  <span class="kd">def</span> <span class="n">next_unions</span><span class="p">(</span><span class="n">streams</span><span class="p">)</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="k">case</span> <span class="nc">Enum</span><span class="o">.</span><span class="n">reduce_while</span><span class="p">(</span><span class="n">streams</span><span class="p">,</span> <span class="p">{</span><span class="no">false</span><span class="p">,</span> <span class="p">[],</span> <span class="p">[</span><span class="nc">Answer</span><span class="o">.</span><span class="n">new</span><span class="p">()]},</span> <span class="o">&amp;</span><span class="n">collect_next_head</span><span class="o">/</span><span class="mi">2</span><span class="p">)</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">      <span class="ss">:empty</span> <span class="o">-&gt;</span> <span class="ss">:empty</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span><span class="no">false</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span><span class="p">}</span> <span class="o">-&gt;</span> <span class="ss">:done</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span><span class="no">true</span><span class="p">,</span> <span class="n">new_streams</span><span class="p">,</span> <span class="n">unions</span><span class="p">}</span> <span class="o">-&gt;</span> <span class="p">{</span><span class="ss">:ok</span><span class="p">,</span> <span class="n">new_streams</span><span class="p">,</span> <span class="n">unions</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">defp</span> <span class="n">collect_next_head</span><span class="p">(</span><span class="err">%</span><span class="n">__MODULE__</span><span class="p">{</span><span class="ss">continuation</span><span class="p">:</span> <span class="no">nil</span><span class="p">,</span> <span class="ss">evaluated</span><span class="p">:</span> <span class="p">[]},</span> <span class="n">_</span><span class="p">),</span> <span class="ss">do</span><span class="p">:</span> <span class="p">{</span><span class="ss">:halt</span><span class="p">,</span> <span class="ss">:empty</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">defp</span> <span class="n">collect_next_head</span><span class="p">(</span><span class="err">%</span><span class="n">__MODULE__</span><span class="p">{</span><span class="ss">evaluated</span><span class="p">:</span> <span class="p">[]}</span> <span class="o">=</span> <span class="n">stream</span><span class="p">,</span> <span class="p">{</span><span class="n">_</span><span class="p">,</span> <span class="n">streams</span><span class="p">,</span> <span class="n">acc</span><span class="p">})</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="n">next</span> <span class="o">=</span> <span class="n">head</span><span class="p">(</span><span class="n">stream</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">done?</span><span class="p">(</span><span class="n">next</span><span class="p">)</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span><span class="ss">:halt</span><span class="p">,</span> <span class="ss">:empty</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span><span class="ss">:cont</span><span class="p">,</span> <span class="p">{</span><span class="no">true</span><span class="p">,</span> <span class="p">[</span><span class="n">next</span> <span class="o">|</span> <span class="n">streams</span><span class="p">],</span> <span class="n">union_pulled_value</span><span class="p">(</span><span class="n">next</span><span class="p">,</span> <span class="n">acc</span><span class="p">)}}</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">defp</span> <span class="n">collect_next_head</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">         <span class="err">%</span><span class="n">__MODULE__</span><span class="p">{</span><span class="ss">continuation</span><span class="p">:</span> <span class="n">continuation</span><span class="p">}</span> <span class="o">=</span> <span class="n">stream</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">         <span class="p">{</span><span class="no">false</span><span class="p">,</span> <span class="n">streams</span><span class="p">,</span> <span class="n">acc</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">       <span class="p">)</span>
</span></span><span class="line"><span class="cl">       <span class="ow">when</span> <span class="ow">not</span> <span class="n">is_nil</span><span class="p">(</span><span class="n">continuation</span><span class="p">)</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="n">next</span> <span class="o">=</span> <span class="n">head</span><span class="p">(</span><span class="n">stream</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">done?</span><span class="p">(</span><span class="n">next</span><span class="p">)</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span><span class="ss">:cont</span><span class="p">,</span> <span class="p">{</span><span class="no">false</span><span class="p">,</span> <span class="p">[</span><span class="n">next</span> <span class="o">|</span> <span class="n">streams</span><span class="p">],</span> <span class="n">union_unpulled_value</span><span class="p">(</span><span class="n">next</span><span class="p">,</span> <span class="n">acc</span><span class="p">)}}</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span><span class="ss">:cont</span><span class="p">,</span> <span class="p">{</span><span class="no">true</span><span class="p">,</span> <span class="p">[</span><span class="n">next</span> <span class="o">|</span> <span class="n">streams</span><span class="p">],</span> <span class="n">union_pulled_value</span><span class="p">(</span><span class="n">next</span><span class="p">,</span> <span class="n">acc</span><span class="p">)}}</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">defp</span> <span class="n">collect_next_head</span><span class="p">(</span><span class="err">%</span><span class="n">__MODULE__</span><span class="p">{}</span> <span class="o">=</span> <span class="n">stream</span><span class="p">,</span> <span class="p">{</span><span class="n">pulled</span><span class="p">,</span> <span class="n">streams</span><span class="p">,</span> <span class="n">acc</span><span class="p">}),</span>
</span></span><span class="line"><span class="cl">    <span class="ss">do</span><span class="p">:</span> <span class="p">{</span><span class="ss">:cont</span><span class="p">,</span> <span class="p">{</span><span class="n">pulled</span><span class="p">,</span> <span class="p">[</span><span class="n">stream</span> <span class="o">|</span> <span class="n">streams</span><span class="p">],</span> <span class="n">union_unpulled_value</span><span class="p">(</span><span class="n">stream</span><span class="p">,</span> <span class="n">acc</span><span class="p">)}}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">defp</span> <span class="n">union_pulled_value</span><span class="p">(</span><span class="err">%</span><span class="n">__MODULE__</span><span class="p">{</span><span class="ss">evaluated</span><span class="p">:</span> <span class="p">[</span><span class="n">head</span> <span class="o">|</span> <span class="n">_</span><span class="p">]},</span> <span class="n">acc</span><span class="p">)</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="n">acc</span>
</span></span><span class="line"><span class="cl">    <span class="o">|&gt;</span> <span class="nc">Enum</span><span class="o">.</span><span class="n">map</span><span class="p">(</span><span class="o">&amp;</span><span class="nc">Answer</span><span class="o">.</span><span class="n">union</span><span class="p">(</span><span class="ni">&amp;1</span><span class="p">,</span> <span class="n">head</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="o">|&gt;</span> <span class="nc">Enum</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="o">&amp;</span><span class="nc">Kernel</span><span class="o">.!=</span><span class="p">(</span><span class="ni">&amp;1</span><span class="p">,</span> <span class="no">nil</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">defp</span> <span class="n">union_unpulled_value</span><span class="p">(</span><span class="err">%</span><span class="n">__MODULE__</span><span class="p">{</span><span class="ss">evaluated</span><span class="p">:</span> <span class="n">evaluated</span><span class="p">},</span> <span class="n">acc</span><span class="p">)</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="nc">Enum</span><span class="o">.</span><span class="n">flat_map</span><span class="p">(</span><span class="n">evaluated</span><span class="p">,</span> <span class="k">fn</span> <span class="n">eval_item</span> <span class="o">-&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="n">acc</span>
</span></span><span class="line"><span class="cl">      <span class="o">|&gt;</span> <span class="nc">Enum</span><span class="o">.</span><span class="n">map</span><span class="p">(</span><span class="o">&amp;</span><span class="nc">Answer</span><span class="o">.</span><span class="n">union</span><span class="p">(</span><span class="ni">&amp;1</span><span class="p">,</span> <span class="n">eval_item</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">      <span class="o">|&gt;</span> <span class="nc">Enum</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="o">&amp;</span><span class="nc">Kernel</span><span class="o">.!=</span><span class="p">(</span><span class="ni">&amp;1</span><span class="p">,</span> <span class="no">nil</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div>
<p>Now we can confirm that everything works!
The only difference is that, because our new and is lazy, we need to use
<code>Enum.to_list/0</code> to force evaluation.</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-elixir">
        <span class="code-title"><i class="arrow fas fa-angle-right fa-fw" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h fa-fw" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy fa-fw" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-elixir" data-lang="elixir"><span class="line"><span class="cl"><span class="n">arg1</span> <span class="o">=</span> <span class="p">[%{</span><span class="ss">a</span><span class="p">:</span> <span class="mi">1</span><span class="p">},</span> <span class="p">%{</span><span class="ss">a</span><span class="p">:</span> <span class="mi">2</span><span class="p">}]</span>
</span></span><span class="line"><span class="cl"><span class="n">arg2</span> <span class="o">=</span> <span class="p">[%{</span><span class="ss">b</span><span class="p">:</span> <span class="mi">1</span><span class="p">},</span> <span class="p">%{</span><span class="ss">b</span><span class="p">:</span> <span class="mi">2</span><span class="p">}]</span>
</span></span><span class="line"><span class="cl"><span class="n">arg3</span> <span class="o">=</span> <span class="p">[%{</span><span class="ss">c</span><span class="p">:</span> <span class="mi">1</span><span class="p">},</span> <span class="p">%{</span><span class="ss">c</span><span class="p">:</span> <span class="mi">2</span><span class="p">}]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nc">LazyCombinations.LazyAnd</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="nc">LazyCombinations.LazyAnd.SimplePartiallyEvaluated</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="p">[</span><span class="n">arg1</span><span class="p">,</span> <span class="n">arg2</span><span class="p">,</span> <span class="n">arg3</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="o">|&gt;</span> <span class="nc">LazyCombinations.LazyAnd</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="o">|&gt;</span> <span class="nc">Enum</span><span class="o">.</span><span class="n">to_list</span><span class="p">()</span></span></span></code></pre></div></div>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-text">
        <span class="code-title"><i class="arrow fas fa-angle-right fa-fw" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h fa-fw" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy fa-fw" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">[
</span></span><span class="line"><span class="cl">  %{c: 1, a: 1, b: 1},
</span></span><span class="line"><span class="cl">  %{c: 2, a: 1, b: 1},
</span></span><span class="line"><span class="cl">  %{c: 2, a: 2, b: 1},
</span></span><span class="line"><span class="cl">  %{c: 1, a: 2, b: 1},
</span></span><span class="line"><span class="cl">  %{c: 2, a: 2, b: 2},
</span></span><span class="line"><span class="cl">  %{c: 1, a: 2, b: 2},
</span></span><span class="line"><span class="cl">  %{c: 2, a: 1, b: 2},
</span></span><span class="line"><span class="cl">  %{c: 1, a: 1, b: 2}
</span></span><span class="line"><span class="cl">]</span></span></code></pre></div></div>
<h3 id="ensuring-equal-evaluation">Ensuring Equal Evaluation</h3>
<p>Now we&rsquo;ll test some infinite streams with a helper function that, again, builds
a stream of positive numbers.</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-elixir">
        <span class="code-title"><i class="arrow fas fa-angle-right fa-fw" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h fa-fw" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy fa-fw" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-elixir" data-lang="elixir"><span class="line"><span class="cl"><span class="kd">defmodule</span> <span class="nc">Test</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">  <span class="kd">def</span> <span class="n">build_answer_stream</span><span class="p">(</span><span class="n">var</span><span class="p">)</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="nc">Stream</span><span class="o">.</span><span class="n">iterate</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="o">&amp;</span><span class="nc">Kernel</span><span class="o">.+</span><span class="p">(</span><span class="ni">&amp;1</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="o">|&gt;</span> <span class="nc">Stream</span><span class="o">.</span><span class="n">map</span><span class="p">(</span><span class="o">&amp;</span><span class="p">%{</span><span class="n">var</span> <span class="o">=&gt;</span> <span class="ni">&amp;1</span><span class="p">})</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div>
<p>But, sadly, there is a subtle issue with this implementation.
If you take a look at the result below, you&rsquo;ll see that our <code>:b</code> stream never
gets past <code>1</code>.
This can be a bigger problem than it might first appear.
Consider the <a href="https://hexdocs.pm/guesswork/pythagorean_triples.html" target="_blank" rel="noopener noreffer ">Pythagorean triples example</a> and imagine our current setup.
If you request at least one answer, the function will never return because there
is no valid answer where <code>B</code> is <code>1</code>.</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-elixir">
        <span class="code-title"><i class="arrow fas fa-angle-right fa-fw" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h fa-fw" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy fa-fw" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-elixir" data-lang="elixir"><span class="line"><span class="cl"><span class="n">arg1</span> <span class="o">=</span> <span class="nc">Test</span><span class="o">.</span><span class="n">build_answer_stream</span><span class="p">(</span><span class="ss">:a</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">arg2</span> <span class="o">=</span> <span class="p">[%{</span><span class="ss">b</span><span class="p">:</span> <span class="mi">1</span><span class="p">},</span> <span class="p">%{</span><span class="ss">b</span><span class="p">:</span> <span class="mi">2</span><span class="p">}]</span>
</span></span><span class="line"><span class="cl"><span class="n">arg3</span> <span class="o">=</span> <span class="nc">Test</span><span class="o">.</span><span class="n">build_answer_stream</span><span class="p">(</span><span class="ss">:c</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nc">LazyCombinations.LazyAnd</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="nc">LazyCombinations.LazyAnd.SimplePartiallyEvaluated</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="p">[</span><span class="n">arg1</span><span class="p">,</span> <span class="n">arg2</span><span class="p">,</span> <span class="n">arg3</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="o">|&gt;</span> <span class="nc">LazyCombinations.LazyAnd</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="o">|&gt;</span> <span class="nc">Enum</span><span class="o">.</span><span class="n">take</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span></span></span></code></pre></div></div>
<div class="code-block code-line-numbers" style="counter-reset: code-block 0">
    <div class="code-header language-text">
        <span class="code-title"><i class="arrow fas fa-angle-right fa-fw" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h fa-fw" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy fa-fw" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">[
</span></span><span class="line"><span class="cl">  %{c: 1, a: 1, b: 1},
</span></span><span class="line"><span class="cl">  %{c: 2, a: 1, b: 1},
</span></span><span class="line"><span class="cl">  %{c: 2, a: 2, b: 1},
</span></span><span class="line"><span class="cl">  %{c: 1, a: 2, b: 1},
</span></span><span class="line"><span class="cl">  %{c: 3, a: 2, b: 1},
</span></span><span class="line"><span class="cl">  %{c: 3, a: 1, b: 1},
</span></span><span class="line"><span class="cl">  %{c: 3, a: 3, b: 1},
</span></span><span class="line"><span class="cl">  %{c: 2, a: 3, b: 1},
</span></span><span class="line"><span class="cl">  %{c: 1, a: 3, b: 1},
</span></span><span class="line"><span class="cl">  %{c: 4, a: 3, b: 1}
</span></span><span class="line"><span class="cl">]</span></span></code></pre></div></div>
<p>The above bug is a result of the order in which the streams are evaluated.
The first incomplete stream seen in the list will have a new value calculated.
In the above example, that first stream is <strong>always</strong> one of the infinite streams.
An answer is to ensure that the smaller streams are always seen first.</p>
<p>The module below achieves this by tracking the count (so we do not have to count
through every item of the <code>evaluated</code> list each time we order the streams) and
then sorting the streams on each call of <code>next_unions/1</code><sup id="fnref:8"><a href="#fn:8" class="footnote-ref" role="doc-noteref">8</a></sup> in lines 51-53.</p>
<div class="code-block code-line-numbers" style="counter-reset: code-block 0">
    <div class="code-header language-elixir">
        <span class="code-title"><i class="arrow fas fa-angle-right fa-fw" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h fa-fw" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy fa-fw" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-elixir" data-lang="elixir"><span class="line"><span class="cl"><span class="kd">defmodule</span> <span class="nc">LazyCombinations.LazyAnd.OrderedPartiallyEvaluated</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">  <span class="na">@behaviour</span> <span class="nc">LazyCombinations.LazyAnd</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">defstruct</span> <span class="p">[</span><span class="ss">:continuation</span><span class="p">,</span> <span class="ss">evaluated</span><span class="p">:</span> <span class="p">[],</span> <span class="ss">count</span><span class="p">:</span> <span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kn">alias</span> <span class="nc">LazyCombinations.Answer</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="na">@type</span> <span class="n">t</span><span class="p">()</span> <span class="o">::</span> <span class="err">%</span><span class="n">__MODULE__</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="ss">continuation</span><span class="p">:</span> <span class="nc">Enumerable</span><span class="o">.</span><span class="n">continuation</span><span class="p">()</span> <span class="o">|</span> <span class="no">nil</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="ss">evaluated</span><span class="p">:</span> <span class="p">[</span><span class="nc">Answer</span><span class="o">.</span><span class="n">t</span><span class="p">()],</span>
</span></span><span class="line"><span class="cl">          <span class="ss">count</span><span class="p">:</span> <span class="n">integer</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="na">@impl</span> <span class="no">true</span>
</span></span><span class="line"><span class="cl">  <span class="na">@spec</span> <span class="n">new</span><span class="p">(</span><span class="nc">Enumerable</span><span class="o">.</span><span class="n">t</span><span class="p">(</span><span class="nc">Answer</span><span class="o">.</span><span class="n">t</span><span class="p">()))</span> <span class="o">::</span> <span class="n">t</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="kd">def</span> <span class="n">new</span><span class="p">(</span><span class="n">stream</span><span class="p">)</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="n">reduce_fun</span> <span class="o">=</span> <span class="k">fn</span> <span class="n">item</span><span class="p">,</span> <span class="n">_acc</span> <span class="o">-&gt;</span> <span class="p">{</span><span class="ss">:suspend</span><span class="p">,</span> <span class="n">item</span><span class="p">}</span> <span class="k">end</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="ss">:suspended</span><span class="p">,</span> <span class="no">nil</span><span class="p">,</span> <span class="n">continuation</span><span class="p">}</span> <span class="o">=</span> <span class="nc">Enumerable</span><span class="o">.</span><span class="n">reduce</span><span class="p">(</span><span class="n">stream</span><span class="p">,</span> <span class="p">{</span><span class="ss">:suspend</span><span class="p">,</span> <span class="no">nil</span><span class="p">},</span> <span class="n">reduce_fun</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="err">%</span><span class="n">__MODULE__</span><span class="p">{</span><span class="ss">continuation</span><span class="p">:</span> <span class="n">continuation</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="na">@spec</span> <span class="n">head</span><span class="p">(</span><span class="n">t</span><span class="p">())</span> <span class="o">::</span> <span class="n">t</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="kd">def</span> <span class="n">head</span><span class="p">(</span><span class="err">%</span><span class="n">__MODULE__</span><span class="p">{</span><span class="ss">continuation</span><span class="p">:</span> <span class="no">nil</span><span class="p">}</span> <span class="o">=</span> <span class="n">stream</span><span class="p">),</span> <span class="ss">do</span><span class="p">:</span> <span class="n">stream</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">def</span> <span class="n">head</span><span class="p">(</span><span class="err">%</span><span class="n">__MODULE__</span><span class="p">{</span><span class="ss">continuation</span><span class="p">:</span> <span class="n">continuation</span><span class="p">,</span> <span class="ss">evaluated</span><span class="p">:</span> <span class="n">evaluated</span><span class="p">,</span> <span class="ss">count</span><span class="p">:</span> <span class="n">count</span><span class="p">}</span> <span class="o">=</span> <span class="n">partial</span><span class="p">)</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="k">case</span> <span class="n">continuation</span><span class="o">.</span><span class="p">({</span><span class="ss">:cont</span><span class="p">,</span> <span class="no">nil</span><span class="p">})</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span><span class="ss">:suspended</span><span class="p">,</span> <span class="n">item</span><span class="p">,</span> <span class="n">continuation</span><span class="p">}</span> <span class="o">-&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="err">%</span><span class="n">__MODULE__</span><span class="p">{</span><span class="ss">continuation</span><span class="p">:</span> <span class="n">continuation</span><span class="p">,</span> <span class="ss">evaluated</span><span class="p">:</span> <span class="p">[</span><span class="n">item</span> <span class="o">|</span> <span class="n">evaluated</span><span class="p">],</span> <span class="ss">count</span><span class="p">:</span> <span class="n">count</span> <span class="o">+</span> <span class="mi">1</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="p">{</span><span class="ss">:halted</span><span class="p">,</span> <span class="n">item</span><span class="p">}</span> <span class="o">-&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="err">%</span><span class="n">__MODULE__</span><span class="p">{</span><span class="n">partial</span> <span class="o">|</span> <span class="ss">continuation</span><span class="p">:</span> <span class="no">nil</span><span class="p">,</span> <span class="ss">evaluated</span><span class="p">:</span> <span class="p">[</span><span class="n">item</span> <span class="o">|</span> <span class="n">evaluated</span><span class="p">]}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="p">{</span><span class="ss">:done</span><span class="p">,</span> <span class="no">nil</span><span class="p">}</span> <span class="o">-&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="err">%</span><span class="n">__MODULE__</span><span class="p">{</span><span class="n">partial</span> <span class="o">|</span> <span class="ss">continuation</span><span class="p">:</span> <span class="no">nil</span><span class="p">,</span> <span class="ss">evaluated</span><span class="p">:</span> <span class="n">evaluated</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="na">@spec</span> <span class="n">done?</span><span class="p">(</span><span class="n">t</span><span class="p">())</span> <span class="o">::</span> <span class="n">boolean</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="kd">def</span> <span class="n">done?</span><span class="p">(</span><span class="err">%</span><span class="n">__MODULE__</span><span class="p">{</span><span class="ss">continuation</span><span class="p">:</span> <span class="n">continuation</span><span class="p">})</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="n">continuation</span> <span class="o">==</span> <span class="no">nil</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="na">@spec</span> <span class="n">count</span><span class="p">(</span><span class="n">t</span><span class="p">())</span> <span class="o">::</span> <span class="n">integer</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="kd">def</span> <span class="n">count</span><span class="p">(</span><span class="err">%</span><span class="n">__MODULE__</span><span class="p">{</span><span class="ss">count</span><span class="p">:</span> <span class="n">count</span><span class="p">})</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="n">count</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="na">@impl</span> <span class="no">true</span>
</span></span><span class="line"><span class="cl">  <span class="na">@spec</span> <span class="n">next_unions</span><span class="p">([</span><span class="n">t</span><span class="p">()])</span> <span class="o">::</span> <span class="ss">:empty</span> <span class="o">|</span> <span class="ss">:done</span> <span class="o">|</span> <span class="p">{</span><span class="ss">:ok</span><span class="p">,</span> <span class="p">[</span><span class="n">t</span><span class="p">()],</span> <span class="p">[</span><span class="nc">Answer</span><span class="o">.</span><span class="n">t</span><span class="p">()]}</span>
</span></span><span class="line"><span class="cl">  <span class="kd">def</span> <span class="n">next_unions</span><span class="p">(</span><span class="n">streams</span><span class="p">)</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="k">case</span> <span class="n">streams</span>
</span></span><span class="line"><span class="cl">         <span class="o">|&gt;</span> <span class="nc">Enum</span><span class="o">.</span><span class="n">sort_by</span><span class="p">(</span><span class="o">&amp;</span><span class="n">count</span><span class="o">/</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">         <span class="o">|&gt;</span> <span class="nc">Enum</span><span class="o">.</span><span class="n">reduce_while</span><span class="p">({</span><span class="no">false</span><span class="p">,</span> <span class="p">[],</span> <span class="p">[</span><span class="nc">Answer</span><span class="o">.</span><span class="n">new</span><span class="p">()]},</span> <span class="o">&amp;</span><span class="n">collect_next_head</span><span class="o">/</span><span class="mi">2</span><span class="p">)</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">      <span class="ss">:empty</span> <span class="o">-&gt;</span> <span class="ss">:empty</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span><span class="no">false</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span><span class="p">}</span> <span class="o">-&gt;</span> <span class="ss">:done</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span><span class="no">true</span><span class="p">,</span> <span class="n">new_streams</span><span class="p">,</span> <span class="n">unions</span><span class="p">}</span> <span class="o">-&gt;</span> <span class="p">{</span><span class="ss">:ok</span><span class="p">,</span> <span class="n">new_streams</span><span class="p">,</span> <span class="n">unions</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">defp</span> <span class="n">collect_next_head</span><span class="p">(</span><span class="err">%</span><span class="n">__MODULE__</span><span class="p">{</span><span class="ss">continuation</span><span class="p">:</span> <span class="no">nil</span><span class="p">,</span> <span class="ss">evaluated</span><span class="p">:</span> <span class="p">[]},</span> <span class="n">_</span><span class="p">),</span> <span class="ss">do</span><span class="p">:</span> <span class="p">{</span><span class="ss">:halt</span><span class="p">,</span> <span class="ss">:empty</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">defp</span> <span class="n">collect_next_head</span><span class="p">(</span><span class="err">%</span><span class="n">__MODULE__</span><span class="p">{</span><span class="ss">evaluated</span><span class="p">:</span> <span class="p">[]}</span> <span class="o">=</span> <span class="n">stream</span><span class="p">,</span> <span class="p">{</span><span class="n">_</span><span class="p">,</span> <span class="n">streams</span><span class="p">,</span> <span class="n">acc</span><span class="p">})</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="n">next</span> <span class="o">=</span> <span class="n">head</span><span class="p">(</span><span class="n">stream</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">done?</span><span class="p">(</span><span class="n">next</span><span class="p">)</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span><span class="ss">:halt</span><span class="p">,</span> <span class="ss">:empty</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span><span class="ss">:cont</span><span class="p">,</span> <span class="p">{</span><span class="no">true</span><span class="p">,</span> <span class="p">[</span><span class="n">next</span> <span class="o">|</span> <span class="n">streams</span><span class="p">],</span> <span class="n">union_pulled_value</span><span class="p">(</span><span class="n">next</span><span class="p">,</span> <span class="n">acc</span><span class="p">)}}</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">defp</span> <span class="n">collect_next_head</span><span class="p">(</span><span class="err">%</span><span class="n">__MODULE__</span><span class="p">{</span><span class="ss">continuation</span><span class="p">:</span> <span class="n">continuation</span><span class="p">}</span> <span class="o">=</span> <span class="n">stream</span><span class="p">,</span> <span class="p">{</span><span class="no">false</span><span class="p">,</span> <span class="n">streams</span><span class="p">,</span> <span class="n">acc</span><span class="p">})</span>
</span></span><span class="line"><span class="cl">       <span class="ow">when</span> <span class="ow">not</span> <span class="n">is_nil</span><span class="p">(</span><span class="n">continuation</span><span class="p">)</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="n">next</span> <span class="o">=</span> <span class="n">head</span><span class="p">(</span><span class="n">stream</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">done?</span><span class="p">(</span><span class="n">next</span><span class="p">)</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span><span class="ss">:cont</span><span class="p">,</span> <span class="p">{</span><span class="no">false</span><span class="p">,</span> <span class="p">[</span><span class="n">next</span> <span class="o">|</span> <span class="n">streams</span><span class="p">],</span> <span class="n">union_unpulled_value</span><span class="p">(</span><span class="n">next</span><span class="p">,</span> <span class="n">acc</span><span class="p">)}}</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span><span class="ss">:cont</span><span class="p">,</span> <span class="p">{</span><span class="no">true</span><span class="p">,</span> <span class="p">[</span><span class="n">next</span> <span class="o">|</span> <span class="n">streams</span><span class="p">],</span> <span class="n">union_pulled_value</span><span class="p">(</span><span class="n">next</span><span class="p">,</span> <span class="n">acc</span><span class="p">)}}</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">defp</span> <span class="n">collect_next_head</span><span class="p">(</span><span class="err">%</span><span class="n">__MODULE__</span><span class="p">{}</span> <span class="o">=</span> <span class="n">stream</span><span class="p">,</span> <span class="p">{</span><span class="n">pulled</span><span class="p">,</span> <span class="n">streams</span><span class="p">,</span> <span class="n">acc</span><span class="p">}),</span>
</span></span><span class="line"><span class="cl">    <span class="ss">do</span><span class="p">:</span> <span class="p">{</span><span class="ss">:cont</span><span class="p">,</span> <span class="p">{</span><span class="n">pulled</span><span class="p">,</span> <span class="p">[</span><span class="n">stream</span> <span class="o">|</span> <span class="n">streams</span><span class="p">],</span> <span class="n">union_unpulled_value</span><span class="p">(</span><span class="n">stream</span><span class="p">,</span> <span class="n">acc</span><span class="p">)}}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">defp</span> <span class="n">union_pulled_value</span><span class="p">(</span><span class="err">%</span><span class="n">__MODULE__</span><span class="p">{</span><span class="ss">evaluated</span><span class="p">:</span> <span class="p">[</span><span class="n">head</span> <span class="o">|</span> <span class="n">_</span><span class="p">]},</span> <span class="n">acc</span><span class="p">)</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="n">acc</span>
</span></span><span class="line"><span class="cl">    <span class="o">|&gt;</span> <span class="nc">Enum</span><span class="o">.</span><span class="n">map</span><span class="p">(</span><span class="o">&amp;</span><span class="nc">Answer</span><span class="o">.</span><span class="n">union</span><span class="p">(</span><span class="ni">&amp;1</span><span class="p">,</span> <span class="n">head</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="o">|&gt;</span> <span class="nc">Enum</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="o">&amp;</span><span class="nc">Kernel</span><span class="o">.!=</span><span class="p">(</span><span class="ni">&amp;1</span><span class="p">,</span> <span class="no">nil</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">defp</span> <span class="n">union_unpulled_value</span><span class="p">(</span><span class="err">%</span><span class="n">__MODULE__</span><span class="p">{</span><span class="ss">evaluated</span><span class="p">:</span> <span class="n">evaluated</span><span class="p">},</span> <span class="n">acc</span><span class="p">)</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="nc">Enum</span><span class="o">.</span><span class="n">flat_map</span><span class="p">(</span><span class="n">evaluated</span><span class="p">,</span> <span class="k">fn</span> <span class="n">eval_item</span> <span class="o">-&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="n">acc</span>
</span></span><span class="line"><span class="cl">      <span class="o">|&gt;</span> <span class="nc">Enum</span><span class="o">.</span><span class="n">map</span><span class="p">(</span><span class="o">&amp;</span><span class="nc">Answer</span><span class="o">.</span><span class="n">union</span><span class="p">(</span><span class="ni">&amp;1</span><span class="p">,</span> <span class="n">eval_item</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">      <span class="o">|&gt;</span> <span class="nc">Enum</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="o">&amp;</span><span class="nc">Kernel</span><span class="o">.!=</span><span class="p">(</span><span class="ni">&amp;1</span><span class="p">,</span> <span class="no">nil</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div>
<p>Finally, we&rsquo;ll check that this change works.
And, low and behold, <code>:b</code> makes it to <code>2</code>!
Everything is being evaluated, and while we might have to check a lot of
possibilities, we won&rsquo;t ever get stuck because an answer set is never created.</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-elixir">
        <span class="code-title"><i class="arrow fas fa-angle-right fa-fw" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h fa-fw" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy fa-fw" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-elixir" data-lang="elixir"><span class="line"><span class="cl"><span class="n">arg1</span> <span class="o">=</span> <span class="nc">Test</span><span class="o">.</span><span class="n">build_answer_stream</span><span class="p">(</span><span class="ss">:a</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">arg2</span> <span class="o">=</span> <span class="p">[%{</span><span class="ss">b</span><span class="p">:</span> <span class="mi">1</span><span class="p">},</span> <span class="p">%{</span><span class="ss">b</span><span class="p">:</span> <span class="mi">2</span><span class="p">}]</span>
</span></span><span class="line"><span class="cl"><span class="n">arg3</span> <span class="o">=</span> <span class="nc">Test</span><span class="o">.</span><span class="n">build_answer_stream</span><span class="p">(</span><span class="ss">:c</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nc">LazyCombinations.LazyAnd</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="nc">LazyCombinations.LazyAnd.OrderedPartiallyEvaluated</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="p">[</span><span class="n">arg1</span><span class="p">,</span> <span class="n">arg2</span><span class="p">,</span> <span class="n">arg3</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="o">|&gt;</span> <span class="nc">LazyCombinations.LazyAnd</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="o">|&gt;</span> <span class="nc">Enum</span><span class="o">.</span><span class="n">take</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span></span></span></code></pre></div></div>
<div class="code-block code-line-numbers" style="counter-reset: code-block 0">
    <div class="code-header language-text">
        <span class="code-title"><i class="arrow fas fa-angle-right fa-fw" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h fa-fw" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy fa-fw" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">[
</span></span><span class="line"><span class="cl">  %{c: 1, a: 1, b: 1},
</span></span><span class="line"><span class="cl">  %{c: 2, a: 1, b: 1},
</span></span><span class="line"><span class="cl">  %{c: 2, a: 2, b: 1},
</span></span><span class="line"><span class="cl">  %{c: 1, a: 2, b: 1},
</span></span><span class="line"><span class="cl">  %{c: 2, a: 2, b: 2},
</span></span><span class="line"><span class="cl">  %{c: 1, a: 2, b: 2},
</span></span><span class="line"><span class="cl">  %{c: 2, a: 1, b: 2},
</span></span><span class="line"><span class="cl">  %{c: 1, a: 1, b: 2},
</span></span><span class="line"><span class="cl">  %{c: 2, a: 3, b: 2},
</span></span><span class="line"><span class="cl">  %{c: 1, a: 3, b: 2}
</span></span><span class="line"><span class="cl">]</span></span></code></pre></div></div>
<h2 id="conclusion">Conclusion</h2>
<p>Elixir&rsquo;s standard library is very comprehensive (especially the <code>Enum</code> and
<code>Stream</code> modules), but not every use case is, or should be, implemented in it.
However, the abstractions that those modules are built on, like the <code>Enumerable</code>
protocol, provide a lot of leverage and let one build pretty complex behavior
with surprisingly little work.</p>
<h2 id="edits">Edits</h2>
<h3 id="2025-07-03">2025-07-03</h3>
<ul>
<li>Fix pythagorean triples link</li>
</ul>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>This can create issues when <code>Or</code> takes an infinite stream, but in
practice <code>Or</code> has been rarely used (<code>And</code> is far more common), so it hasn&rsquo;t
yet been a problem and other solutions would add a lot of complexity.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>All code can be found at
<a href="https://gitlab.com/smaller_infinity/lazy_combinations" target="_blank" rel="noopener noreffer ">https://gitlab.com/smaller_infinity/lazy_combinations</a>, and all the examples
here have been run on <code>elixir 1.17.3</code> and <code>erlang 26.2.5</code>.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>This is only possible because we don&rsquo;t need to support <code>Not</code>.
In Guesswork, answer sets are more complex.
But that would distract from our core problem.&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>So surprising that when I first pulled this code from Guesswork&rsquo;s
commit history I didn&rsquo;t believe it worked &ndash; despite the fact that I had written
(and tested) this code myself, some ten or eleven months ago.
I&rsquo;ve experienced a lot of imposter syndrome in my time, but I don&rsquo;t think I&rsquo;ve ever
given it to myself so directly.&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p>A good example of this is in the <a href="https://hexdocs.pm/guesswork/pythagorean_triples.html" target="_blank" rel="noopener noreffer ">Pythagorean triples example</a> for Guesswork.&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p>This is, as of writing, done by a library in Guesswork.
However, I want to have as few dependencies as possible when explaining this issue,
and I was able to find this <a href="https://elixirforum.com/t/best-way-to-iterate-a-stream/24382" target="_blank" rel="noopener noreffer ">thread on elixirforum</a> that goes through, not just how
to do this, but why the standard library doesn&rsquo;t supply a way.&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7">
<p>This is obviously not how Guesswork does it.
We will need to try out (slightly) different versions of our state but only need
one version in the real implementation.&#160;<a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:8">
<p>My apologies for having to show so much code with so little change.
I think it is important that the examples be real, in that they are actually run
when building this page.&#160;<a href="#fnref:8" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></description>
</item>
<item>
    <title>Baseball Talk</title>
    <link>https://blog.smaller-infinity.com/posts/baseball-talk/</link>
    <pubDate>Fri, 28 May 2021 00:00:00 -0400</pubDate>
    <author>Paul Ricks</author>
    <guid>https://blog.smaller-infinity.com/posts/baseball-talk/</guid>
    <description><![CDATA[<p>Baseball broadcasters spend surprisingly little time talking about the game in
front of them.
This is not to say they are doing the same thing as Liebling who would start with
the boxing and then wander out into the city; they are very focused on the topic of
&rsquo;the game&rsquo;.
Just not necessarily <em>this</em> game.
They talk about stats: percentage of fastballs, bases stolen, how many beards
on the field.
They tell old baseball stories: who stole whose bat or how someone ended up at
this or that club.
Then they slip in jokes about their families when they are certain no one could
call them on it (at least in real time).</p>
<p>It is a perfect style because this is how people not only watch but play baseball.
It is, at the core, a very conversational game.
The most important conversation is between the pitcher and batter.
It is often not especially loud and highly intimate.
First the pitcher hides everything but his eyes, and looks at the batter.
He sees how tall the batter stands, the way he holds the bat, and then he says
something.</p>
<p>All pitchers talk differently.
Some only talk in short, sharp, cutting statements.
Some are less direct.
They take their time getting to the point and their path there is less than
direct.
After all, what is a curve-ball but proof that the longest way round is the
shortest way home.</p>
<p>It is then up to the batter to respond.
Batters have a rather obvious time limit and so are forced to speak without
fully thinking through their response.
As a result, they speak when they should be silent or talk loudly
when silence was called for.
They frequently miss the mark and find themselves talking past the pitcher.
But in this conversation the batter has to only say one thing to put the pitcher
on their heels and while they all want to say it loud, a well placed point said
just at the right volume will also work.</p>
<p>They are not the only ones talking.
They are the ones everyone at the table is listening too, but infielders are
all whispering about possible responses to the batter.
At the ends of the tables, the managers discus who might be most eloquent.</p>
<p>And in the stands the fans talk too.
The fans are not at the table, and so not required to follow every word.
Sometimes they cannot help themselves, they follow every utterance either speechless
or so full of things to say it comes out only as wordless sound.
But baseball is a full, nine course meal at a very long table.</p>
<p>So the fans talk to each other.
They get a beer.
They discus the season.
They talk about last night&rsquo;s game.
They take cheap shots at someone who stayed home.
Which means that the broadcasters are doing the same thing as the fans, and they
are both emulating the players.
It&rsquo;s baseball&mdash; lean back, think, lean in, then say something.
And don&rsquo;t worry too much about what you say.
It&rsquo;s a pastime and the wordsmiths are on the field.</p>
]]></description>
</item>
<item>
    <title>A Better Pork Chop</title>
    <link>https://blog.smaller-infinity.com/posts/porkchop/</link>
    <pubDate>Thu, 14 Jan 2021 00:00:00 -0500</pubDate>
    <author>Paul Ricks</author>
    <guid>https://blog.smaller-infinity.com/posts/porkchop/</guid>
    <description><![CDATA[<p>Recently, I came up with a new way to cook pork chops.
I like simple food.
There is indulgence in the flavor of the meat and the beauty of the vegetables.
Ever since I first learned to cook my favorite meal has been steak with
mushrooms and onions.
Don&rsquo;t let the simplicity fool you, it is hard to get right.
The steak alone can be difficult.
Despite all the rules and tables, there is no cut-and-dry rule for how long
or how hot to cook steak.
All you really have is the moment you push the fork into the meat and either it
is done, or it is not, or the meat is ruined.</p>
<p>I am not yet very good at this, but luckily pork chops are easier.
The first time I remember making pork chops was with my mother.
We used the bacon fat my father kept in the freezer and cooked them in a cast
iron frying pan.
For a long time, this is how I made pork chops.
I didn&rsquo;t always have bacon fat, but other things worked: olive oil especially,
sometimes butter.
But it wasn&rsquo;t quite right; the olive oil was too greasy and the butter too rich.</p>
<p>More than anything pork&rsquo;s flavor is straightforward.
Chicken actually has a great deal of flavor, but it is easily swayed, easily
convinced to pick up others.
Steak is loud.
That is why you can marinate it so many ways and it still screams above the crowd.
But pork, pork is at its best when smoked and with maybe two other flavors.
It is just too honest for the richness of butter and not light enough for olive
oil.</p>
<p>The next recipe I learned was from my grandfather.
He liked the chops thinner.
He would score the sides with a pairing knife, and then season them with salt and
pepper.
He used one of his mother&rsquo;s cast iron pans, but instead of any fat or grease he
would use coarse salt, and at a much higher heat.</p>
<p>I really liked that recipe, but it was hard to get the chops I needed.
The little grocery stores in Waltham and Sewanee just never had them in stock,
and the apartments I lived in were so small they would fill up with smoke and
set off the alarm.
Often I could either let the alarm scream or let the chops burn.
So I went back to the first recipe.
I cooked them a little hotter so they weren&rsquo;t as greasy and still scored the sides,
but largely the process was the same.</p>
<p>Then my mother got my father a cast iron ridge grill for his birthday.
If there is any evidence against progress it is this: despite all our metallurgy,
our chemical non-sticks, our pressure cookers, and our ovens of various heat
sources, the best way to cook a slab of meat since the invention of a hot slab
of iron, is a hot slab of iron with raised ridges.
The iron just captures more heat, and the ridges function a lot like my grandfather&rsquo;s
coarse salt; lifting the meat just enough that the flesh does not burn and does
not adhere, but is still as close to the heat as possible.</p>
<p>And so it goes, bacon grease to oil, oil to salt, salt to iron ridges.
The underlying recipe never really changed: pork, salt, pepper, heat, and it was
always cast iron above the flame.
After all, I am in many ways a traditionalist.
I cook like my mother and like my grandfather and I trust that slab of iron to do
for me what it did for my great grandmother.
And yet, my traditions demand a better pork chop and so I cycle: grease to oil,
oil to salt, salt to iron.</p>
]]></description>
</item>
<item>
    <title>Chushingura</title>
    <link>https://blog.smaller-infinity.com/posts/chushingura/</link>
    <pubDate>Tue, 29 Sep 2020 00:00:00 -0400</pubDate>
    <author>Paul Ricks</author>
    <guid>https://blog.smaller-infinity.com/posts/chushingura/</guid>
    <description><![CDATA[<p>&lsquo;Chushingura&rsquo; is on Jefferson Airplane&rsquo;s fourth studio album, <em>Crown of Creation</em>.
It has no words and is only a minute and seventeen seconds long.
The song is also supposed to make your skin crawl.</p>
<p>The work of freaking out the listener, or at least putting them off balance, starts
in the proceeding song.
&lsquo;Share a Little Joke&rsquo; starts slow and for most of the song stays slow, but right at
the end, after lyrics the are done, it speeds up.
When music speeds up, your body can&rsquo;t help it, your heart rate speeds up.
When your heart rate speeds up, you can&rsquo;t help it, you feel just a little rush
of that flight or fight response&mdash; your lizard brain reaches up into that mammal
gray matter and demands to be heard.
And this is the state of mind Jefferson Airplane seems to want you in when
&lsquo;Chusingura&rsquo; begins&mdash;just a little bit primal.</p>
<p>The song itself starts with a high pitch.
Not a whine or a bell or anything describable, just a tone.
An echo rises out of the tone followed by the almost anxious tapping of drum-sticks.
The tapping isn&rsquo;t fast so much as hurried, like the clacking of of a woman&rsquo;s heels
when she thinks she is being followed late at night.
Then the tone is joined by more, but they are irregular.
They come and go with no rhyme and no rhythm and the echo is back, it is back and it
is louder.
The tapping now occasionally speeds up and you can hear the woman grabbing her skirt
and running, turning, slowing down, doing it again, and again.
The tapping gets louder.
A few out-of-tune guitar strings are plucked one at a time and then, after a pause,
a few of them all at once.
The tapping gets louder.
The tones all go away.
And then the tapping fades.</p>
<p>And this is the end of the LP&rsquo;s A side so now, all you should hear is first silence,
and then the sound of the headshell hitting the spindle <em>clack</em>&hellip; <em>clack</em>&hellip; <em>clack</em>&hellip;
before you get out of the chair, raise the arm, and flip the record.</p>
<p>Jefferson Airplane does make up for it.
The next song, &lsquo;If You Feel&rsquo;, is calming and downright jovial.
It has all the rhythm and all the order &lsquo;Chushingura&rsquo; does not.
<em>Break china laughing, laughing, laughing</em>, they sing.
It&rsquo;s a relief.</p>
<p>But is that why they did it?
Did Jefferson Airplane just raise your heart rate and instill anxiety in you
just so that the next feel-good tune could really land?
I doubt that.
For one, <em>Crown of Creation</em> is always circling and always anxious.
The center of the album may be the height of this anxiety, but worry, concern,
and fear are always around the corner.
It is, after all, an album that finds peace only after nuclear oblivion.</p>
<p>And Jefferson Airplane is not the only psychedelic rock band to play this game.
The first song on the first album by King Crimson, <em>21st Century Schizoid Man</em> on
<em>In the Court of the Crimson King</em> tells you right in the title what effect it
is going for.
It succeeds through lyrics shouted through static and the overwhelming, constant,
but unreliable instruments.
King Crimson does it again fifteen years later in a later incarnation on a pair of
songs on <em>Three of a Perfect Pair</em>, &lsquo;Industry&rsquo; and &lsquo;Dig Me&rsquo;.
&lsquo;Industry&rsquo; is even somewhat reminiscent of &lsquo;Chushingura&rsquo;.
It also uses higher-pitched tones and an off-putting beat to place the listener
in an anxious state.
The next song goes even farther with the singer talking from the perspective of
a car in a junkyard.</p>
<div class="verse">
<p>It&rsquo;s here I sit and rust amid this ruin and rancor<br />
Like tire irons, toothy grills and car parts before me<br />
The acid rain floods my floorboard<br />
Burns my pores and rots my upholstery<br />
Once I was worshipped, polished magnificently<br />
Now I lay in decay by the dirty angry bay<br /></p>
</div>
<p>His voice is just slightly distorted so that you know he <em>is</em> the car and he <em>is</em>
rotting and <em>is</em> decaying.
There can be no doubting it.</p>
<p>You do not need these songs to make your skin crawl.
Spin around in your room and pick something, a newspaper headline, a letter from the city,
an app on your phone, the neighbors fighting through the wall; where can
you turn that is not a source of fear?
Even the cures are tinged by their enemy exactly because they are offered in
opposition.
We are told to exercise because it will calm us, to drink less because it cannot fix us,
meditate because it will center us.</p>
<p>But psychedelic rock does not meditate.
Instead it indulges: sound, emotions, genres, and stories.
True rockstars can be gluttons for anything and everything.
These albums are as much orgies as anything else; twisting vats of sensation and
sound that explode out from the speakers.
That anxiety, then, is just another aspect of the world to be indulged
in&mdash;just another sensation in which to exult.
&ldquo;So drink deep,&rdquo; says psychedelic rock.
&ldquo;What is there to fear in a little indulgence?&rdquo;</p>
]]></description>
</item>
<item>
    <title>Considering a Martini</title>
    <link>https://blog.smaller-infinity.com/posts/martini/</link>
    <pubDate>Tue, 22 Sep 2020 00:00:00 -0400</pubDate>
    <author>Paul Ricks</author>
    <guid>https://blog.smaller-infinity.com/posts/martini/</guid>
    <description><![CDATA[<p>The martini is a precision drink.
Making a martini is not an art, it is a science.
The ratios need to be exact, the pieces carefully selected, and the way in which
everything is combined repeatedly tested.</p>
<p>I know this because for a very long time I did not appreciate it.
I have always been fond of gin.
At first it tasted like summer to me, because growing up, my parents had
gin and tonics when it was warm and they could sit out on the porch.
But this is not the true essence of gin and instead I have learned to recognize in it
the smell of pine trees.
This is why the liquor taste should be so strong&mdash;like fresh air, that
first sip of strong alcohol pulls us into the present and reminds us that we are
in the here and now.</p>
<p>And at first I thought of martinis as only a large glass of booze.
I would wave the vermouth over the glass as if the essence of it could somehow
travel through the air in to the liquid.
A few drops would fall, the texture of the drink would change, I would add bitters,
and then would call it a martini.
I am afraid to say that there were some negative results from this behavior; the
average person is not well prepared to drink a actual glass of largely uncut gin,
much less a parade of them.</p>
<p>Since then I have learned that mysticism does not create a good cocktail.
I bought a jigger and accepted the fact that a bottle of vermouth does not last
six months.
Then learned about ratios.
There isn&rsquo;t just a big difference between a martini that is seven or eight parts
gin with one part vermouth compared to a martini that is three or four parts gin
with one part vermouth; there is a big difference between a martini that is six
parts gin and a martini that is four parts gin.</p>
<p>In retrospect, this is not surprising.
When I made pizza dough with too much yeast, it rose too fast.
I once added too much oregano to my eggs and found them inedible.
So why shouldn&rsquo;t any change in the amount of vermouth have an effect on the resulting
martini?
There is, after all, a reason why a martini with more gin is dry.
Like cold air and dust, gin makes you reach for water and leaves the skin feeling dry.</p>
<p>Vermouth is more moderating.
It smells like wine and even dry vermouth has a sweetness to it.
Combine the dryness of the gin and the sweetness of the vermouth and you create
these undercurrents, like the air at the edge of a storm.
They mix and tumble, falling in and out of each other as the bitters tumble
between the fronts.
Dry martinis, then, are like a high pressure system, lots of cool, dry air that bring
good weather and light winds.
In comparison a martini with lots of vermouth is a low pressure system.
That circling warm, sweet air brings storms and strong winds.
All of which speaks to the versatility of the drink.
You want rain, you add vermouth.
And if you want a cool fall day, I would use a ratio of eight to one.</p>
]]></description>
</item>
<item>
    <title>Origin Stories</title>
    <link>https://blog.smaller-infinity.com/posts/super-heroes/</link>
    <pubDate>Tue, 15 Sep 2020 00:00:00 -0400</pubDate>
    <author>Paul Ricks</author>
    <guid>https://blog.smaller-infinity.com/posts/super-heroes/</guid>
    <description><![CDATA[<p>I have always been fascinated by superheroes, not just the heroes themselves (though
I love them too, Doctor Strange is clearly the best), but the way in which they
are created and how they are written.
There is always an uncomfortable custody agreement between writers and readers.
The writer may give birth to the character, but they only continue to live because
the reader provides a mental space for the character to live and thrive.</p>
<p>Not all of these agreements are the same; especially not for novelists.
Amor Towles (the author of <em>A Gentleman in Moscow</em>) does not give the reader much
by way of latitude.
He writes with a prose that could only be produced by someone who had spent decades
within east coast upper society.
The former investment banker notes the display of every fork, just how close each
couple is, how many times someone looks away from the movie.
The world he creates is the result of painstaking detail and he traps both you and
his main character in it.
It is not that there is not a cast, but in both of his books there is only one character
Towles really, truly loves.
He dotes on his main characters; indulges them and then exposes them to the reader.
But he is a very jealous writer, that character is his and no one else&rsquo;s.
In legal language the reader only really has visitation rights.</p>
<p>But Yuri Herrera gives the reader nothing but latitude.
In his book <em>Kingdom Cons</em> the characters do not even have names.
Instead they have roles: King, Artist, Commoner.
His prose is fluid and filled with rough images.
It reads like the first version of a fairy tale or a ballet with his King and his
Artist dancing through set pieces.
This is not to say that the work is not deathly serious; the king is a drug lord and
if nothing else is, the blood on the floor is very real.
But the Herrera requires the reader to work through the haze he creates.
As a result he and the reader work alongside to tell his story.
This a far more equitable relationship where the writer and the reader gain joint
custody and joint responsibility in the raising of their love child.
This can be exhausting (a few pages of Herrera&rsquo;s novels have made me want to just
lie down and close my eyes while I devoured Towles&rsquo; much longer books in days) but
can also be very rewarding.
Who doesn&rsquo;t want to watch their love child grow up?</p>
<p>But the dynamics between the reader and the writers of superheroes are far more
complex.
For one, there are writers, plural.
While in novels different writers can re-imagine previously existing characters,
this is less transformation than it is a newly conceived character.
There are countless Odysseuses experiencing very similar plots in different ways.</p>
<p>The rules for superheroes are in many ways the reverse.
There is only one hero and many plots.
When I pick up a Spider-Man comic I expect certain things: I want the web shooters
he uses to go <em>thwip</em>-<em>thwip</em>, I would be taken aback if there wasn&rsquo;t enough guilt
to fuel a thousand confessionals, and I hope for at least one doomed romantic interest
(I want Peter to be happy, even if it is only fleeting).
There is a commercial aspect to this.
Readers probably would not respond well to a calm, confident, guilt-free Peter Parker
because they come for the chaos, but there is more going on than economics.</p>
<p>The custody agreement is not just flipped here.
When it comes to superheroes the readers, the mass, have full ownership of the character.
The writers can shift things, make the story darker or refocus on aspects of the character
previously ignored, but they can never subvert the readers&rsquo; demands because the
connection is so much stronger.</p>
<p>The character in a novel, however real, is the creation of a single person.
They are a piece in a larger story, birthed to play their role alongside others.
But in a comic the superhero is the only thing that matters; the plots, the villains,
the love stories only exist to further strengthen the hero.
This is because we don&rsquo;t believe in those things, but we believe in the hero.
I believe in Captain America.
And I believe in him because I believe in the virtues of dignity and basic decency.
And I believe that these are not just ends but means.
And when he says to a little girl, &ldquo;I know you&rsquo;re scared.
I don&rsquo;t blame you.
But if you really feel like you can&rsquo;t face him alone let me help you,&rdquo; I feel relief.</p>
<p>But maybe the problem is the superheroes are not characters at all.
They&rsquo;re thin wrappings of origin stories and spandex around something that was already
present and already compelling.
In this version superheroes are not born and they cannot be owned.
Instead they must be collected&mdash; found on street corners and in alleyways before they
are pieced together.
In a novel characters are still real people, or at least as close to real people as the
skill of the author will allow.
They have hopes and dreams and feel a little shame when they have a dirty thought
about the girl behind the counter.</p>
<p>Superheroes may have flaws, but they are not real people.
We do not believe in real people, we believe in ideals.
And sometimes we dress those ideals up in a suit and have them fly over Manhattan
and save us.</p>
]]></description>
</item>
<item>
    <title>La Vache Enragee</title>
    <link>https://blog.smaller-infinity.com/posts/bull/</link>
    <pubDate>Tue, 08 Sep 2020 00:00:00 -0400</pubDate>
    <author>Paul Ricks</author>
    <guid>https://blog.smaller-infinity.com/posts/bull/</guid>
    <description><![CDATA[<p>I grew up in a house filled with art.
Not like a museum filled with priceless masterpieces and not like a mansion with its
history staring down from the walls&mdash; instead it was prints mostly, small images
behind the dinner table or hanging in the living room.
Everything exactly in its place.
I hardly noticed them when I was growing up; it was just there like the table, and the
chairs, and the cats.</p>
<p>I noticed when they were gone though.
Not at first, since my dorm rooms were small, cluttered, and I covered the walls with
posters in a way that I had never done at home.
The transience of dorm rooms means that they resist becoming yours; you do not so much
reside in them as stay, like an extended visit at a half star hotel.
The rules remind you of this, they say what tape you can use, what kind of hooks can be
attached to what walls.
The allowed supplies are never good enough.
Posters peel and hooks holding up picture frames fail in the middle of the night.
I still owe Sewanee fees for damage some tape did to the walls of my senior year dorm.</p>
<p>But at least you are allowed, briefly, to try to own the space.
This is not always true.
I spent a summer working in Lincoln, Nebraska, a place I have little fondness for.
The worst part was not the sweltering heat, the dull work, or even the endless,
rolling boredom, it was the walls of the apartment building I lived in.
They were gray, and we were not allowed to cover them.</p>
<p>This gray was a very special gray.
It was completely non-committal, not especially dark, not light.
In fact, it seemed to suck in the light and it was everywhere.
Every hallway, every room, it would seep into my dreams fading the other
colors like paint remover.
And I could not cover it.</p>
<p>It has been a while since I lived in Lincoln.
I haven&rsquo;t stepped in a dorm room since I left my senior year.
In grad school I lived with roommates, and could only cover the walls of own room,
but I did that much.
The posters went away, and I put up prints.
Gifts mostly, but I found money to fill any holes so everything could have a proper place.</p>
<p>Prints are the most democratic form of visual art.
A single plate or set of wood blocks can become numerous works, each numbered and marked.
In some cases after the original run new reprintings can be run so that the next
generation can partake.
Art for everyone.</p>
<p>There has always been something attractively democratic about printing in general;
in many ways it is the mirror image of the democratic process.
In an election many voters come together to create a single government.
In printing a single design, plate, or screen is used create many copies.
And while museums house incredible exhibits of breathtaking work, they stop at their
own doors and cannot and should not fill my apartment with beauty.
You will probably never have a Van Gogh hanging in your bedroom, but you can have a
Toulouse Lautrec reprint.
Trust me, I do.</p>
<figure><figcaption>
      <h4>La Vache Enragee</h4>
    </figcaption>
</figure>

<p>It is one of my favorites, <em>La Vache Enragee</em>, it was a gift from my father.
It is genuinely funny.
Every time I look at it I always see the same thing first; a balding man with
skin the color of the street fleeing down the avenue, checkered pants clashing
with the cobblestones, long green coat billowing behind him, and his hands,
raised up in surrender, holding a distinctly feminine umbrella.
Behind him is a bull.
He is red, his head is down, and his horns are up.
Around them there are others, a policeman, a baker, a dog, a clown and a monkey
riding the bike, but they are probably bystanders.</p>
<p>Not that they have to be.
A challenge of visual art is that nothing says you can&rsquo;t tell a story, only that
you have a single frame.
But if you only have a single frame you can provide infinite possibilities.
Sometimes I look at that print and see the obvious, the angry bull and the fleeing,
rich fool.
But sometimes I am more interested in the baker.
Is he really just a bystander?
Does he know more than his happy smile would suggest?
Sometimes I see the dog, maybe about to pounce on the fool.
Or maybe just running along side because what <em>fun</em> this is.</p>
<p>I love that print.
And I love that it hangs from a nail that no one could tell me not put there.
And I love that every time I look at it and tell a new story that story sinks
down that nail into the wall.
And then that story, my story, seeps into the wood, the bones of the apartment,
and this place becomes a little more mine.</p>
]]></description>
</item>
<item>
    <title>The Value of Uncertainty</title>
    <link>https://blog.smaller-infinity.com/posts/the-value-of-uncertainty/</link>
    <pubDate>Tue, 01 Sep 2020 00:00:00 -0400</pubDate>
    <author>Paul Ricks</author>
    <guid>https://blog.smaller-infinity.com/posts/the-value-of-uncertainty/</guid>
    <description><![CDATA[<p>I once tried to explain the argument behind Schrodinger&rsquo;s cat to my mother.
She was trying to write a poem and hoped that the metaphor would work, but disliked
the idea that something could be both true and untrue.
I flipped a coin and as it spun through the air I asked if it was heads or tails.
Sadly, even that careful exhibition of probabilities failed to hit the mark;
my mother believes that things are or are not.
The coin is not heads till it hits the ground.</p>
<p>I found this interesting because (though she claims to hate it) in another life she
could have been a mathematician.
There are more similarities between mathematics and theology than mathematics
and science; we have all learned that nothing is ever true in science.
Today a virus is airborne, tomorrow passed only by touch.
Yesterday immunity lasted three months, tomorrow it might last six.
In a world of p-values there cannot be truth, only things that are acceptably possible,
and one day the apple that has fallen from its tree, time and time again, will float up into
the sky, or explode into a thousand cherry blossoms.
The fact that these things almost certainly will not happen means that there is the
smallest of possibilities that they could.</p>
<p>But math&mdash; math will offer a level of certainty (provided various assumed things
actually are true).
If \(x = 4 - 1\), then in that situation \(x\) always was three.
It was three the moment the equation was written.
It will be three when you die.
It will be three when the sun falls into itself.
Sadly this is not usually as satisfying as theology.
Socrates may have considered death the next intellectual horizon, but I am afraid
the rest of us might gain some comfort from knowing, if not what the destination is,
at least that there is one.</p>
<p>But this is why mathematics and science are in bed together (despite their differences),
not mathematics and theology.
Imagine, for only a moment, that there was an ultimate formula for everything: want to
know the position and velocity of a particle (use the formula), want to know if the
patient has cancer (use the formula), want to know if your mother-in-law would prefer
that your wife had married the boy down the street (use the formula).</p>
<p>What a dull world.
Certainty would become an everyday phenomenon.
We would all know the ideal path to work, the exact number of minutes to cook a steak,
how many drinks you should have to be charming.
No one would ever fall off a bar stool, tell their crush the truth, or play a video game.
Not unless the formula told them to.</p>
<p>But you go to a bar because it is funny when your friends fall off bar stools and you
blurt out the truth because it is worth saying.
Just like mathematicians thrive on the undiscovered portions of their fields and scientists
live on a need to understand a fundamentally unknowable universe, it is not worth getting
out of bed for a preordained day.
Somewhere, there is a woman staring at a chalkboard filled with symbols trying to build some
new form of topology.
She does not know if it is even possible, just like the man in an observatory trying,
once again, to see something that cannot be seen.
They have failed a thousand times, but still look.</p>
<p>Which is to say, it is not that the coin can not work that way, it has too.
It must be heads, and tails, and every one of an uncountable supply of supposedly
impossible options, because otherwise there would be no reason to flip it.</p>
]]></description>
</item>
<item>
    <title>An Examination of Stove Tops</title>
    <link>https://blog.smaller-infinity.com/posts/stovetops/</link>
    <pubDate>Tue, 03 Mar 2020 00:00:00 -0500</pubDate>
    <author>Paul Ricks</author>
    <guid>https://blog.smaller-infinity.com/posts/stovetops/</guid>
    <description><![CDATA[<p>After over two years with a gas stove I found myself using an electric stove
and the first thing I did was burn a piece of chicken.
We understand fire.
It lashes out of its hearth violently with vivid colors saying to everything
around it, &ldquo;Don&rsquo;t touch me, I&rsquo;m bad.&rdquo;
But electric stoves are, like many things powered by lines and towers, harder
to read.
They wait, but also radiate heat and refuse to turn off.</p>
<p>Part of what is odd about this is that, in many cases, that electric stove is
itself powered by natural gas.
Electricity is not magic.
It is not conjured out of the air but comes from movement.
A magnet must move, turning electrons in the surrounding wires, creating a flow of
energy, which is itself expressed as heat.</p>
<p>But to move a magnet, we often turn to the oldest of discoveries, fire.
In the country I live in we largely burn coal and natural gas, the heat boils
water, the water creates steam, the steam turns a turbine, and so a magnet
turns and, after a great many steps, my stove heats.
And so heat becomes movement, movement becomes electricity, electricity moves
and then becomes movement, which finally becomes heat.</p>
<p>I thought about all of this as my chicken burned.
To be fair, it was probably not the stove&rsquo;s fault that my chicken turned out
charred; electric stoves require far more patience than gas stoves that are,
on the whole, quite eager to please.
But it still seemed to me that this was a lot of intermediary steps to further
remove me from a gas fire.</p>
<p>But then, even the gas stove has more steps than are immediately visible.
I have cooked on an open flame.
It is far more work than turning a knob: wood must be gathered, a fire started
and then stoked to the point where it is hot enough to do its job, the coals then
moved to get a desired heat.
But to turn that knob the natural gas must be extracted from the earth: first
the bedrock fractured, then those fractures held open as the gas is collected.
The collected gas then transported to the gas company who then pipes it into our
homes via gas lines.
But even this can be further examined, given that burning gas is really burning
ancient sunlight, which is itself a product of a massive fusion reactor that
was, itself, born of gas.</p>
<p>None of this, of course, much mattered.
The chicken was still charred.
The knob was still too high and the stove top too hot.
I had still been too impatient.</p>
]]></description>
</item>
</channel>
</rss>
