
<feed xmlns="http://www.w3.org/2005/Atom">
    <generator>Hugo -- gohugo.io</generator>
    <title>
                recursion on
            
        
        The Neo-Babbage Files</title>
        <link href="https://babbagefiles.xyz/tags/recursion/atom.xml" rel="self" type="application/atom+xml" /><link href="https://babbagefiles.xyz/tags/recursion/"/>
    <updated>2025-12-29T11:00:32+00:00</updated>
    <author>
            <name>Benjamin Slade</name>
            
                <email>slade@lambda-y.net</email>
            </author>
    <id>https://babbagefiles.xyz/tags/recursion/</id>
        
        <entry>
            <title type="html"><![CDATA[C-c-c-conjecturing, and dealing with recursion in Emacs (more excursus)]]></title>
            <link href="https://babbagefiles.xyz/c-conjecturing-and-practical-considerations-of-recursion-in-emacs/"/>
            <id>https://babbagefiles.xyz/c-conjecturing-and-practical-considerations-of-recursion-in-emacs/</id>
            
                    <author>
                        <name>Benjamin Slade</name>
                    </author>
            <published>2025-02-24T04:10:00-06:00</published>
            <updated>2025-02-24T12:13:13-06:00</updated>
            
            
            <content type="html"><![CDATA[<p>I&rsquo;m not putting this in the <a href="https://babbagefiles.xyz/categories/lambdacalculus/">lambda-calculus</a> series, though it touches
on issues from the <a href="https://babbagefiles.xyz/lambda-calculus-and-lisp-02-recursion/">last post</a> in the series, but specifically issues of
recursion. I was curious to go back and recall how <em><a href="https://web.archive.org/web/20150426092105/http://www.ccs.neu.edu/home/matthias/BTLS/">The Little Schemer</a></em>
dealt with problems of recursion (and the Y Combinator (which we still
haven&rsquo;t got properly to yet, but we will, I promise)).</p>
<p>In Chapter 9 of <em>The Little Schemer</em> (&ldquo;and Again, and Again, and
Again,&hellip;&quot;), it starts off by querying the reader if they want caviar
and how to find it in a list, and then essentially gets (from caviar
and grits) into issues around the halting problem.</p>



<figure>
    
        <img src="https://babbagefiles.xyz/ox-hugo/bibby-again-again-again-little-schemer-ch9.png" alt="Figure 1: Duane Bibby illustration heading Chapter 9 of &ldquo;The Little Schemer&rdquo;"/> <figcaption>
                
                <p>
                    <span class="figure-number">Figure 1: </span><a href="https://wiki.c2.com/?DuaneBibby">Duane Bibby</a> illustration heading Chapter 9 of &ldquo;The Little Schemer&rdquo;
                    
                        
                        </p>
                
            </figcaption></figure>

<p>But a number of pages into this chapter the book queries of a
particular function: &ldquo;Is this function total?&rdquo;  and presents the
following:</p>
<div class="highlight"><pre class="chroma"><code class="language-scheme" data-lang="scheme"><span class="p">(</span><span class="k">define </span><span class="nv">C</span>
  <span class="p">(</span><span class="k">lambda </span><span class="p">(</span><span class="nf">n</span><span class="p">)</span>
    <span class="p">(</span><span class="nf">cond</span>
     <span class="p">((</span><span class="nf">one?</span> <span class="nv">n</span><span class="p">)</span> <span class="mi">1</span><span class="p">)</span>
     <span class="p">(</span><span class="nf">else</span>
      <span class="p">(</span><span class="nf">cond</span>
       <span class="p">((</span><span class="nb">even? </span><span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nf">C</span> <span class="p">(</span><span class="err">÷</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span>
       <span class="p">(</span><span class="k">else </span><span class="p">(</span><span class="nf">C</span> <span class="p">(</span><span class="nf">add1</span> <span class="p">(</span><span class="err">×</span> <span class="mi">3</span> <span class="nv">n</span><span class="p">)))))))))</span>
</code></pre></div><div class="src-block-caption">
  <span class="src-block-number">Code Snippet 1:</span>
  a function puzzle from "The Little Schemer" (p.155)
</div>
<p>I didn&rsquo;t know what <em>C</em> was (a number of readers probably have recognised
it already, but please don&rsquo;t spoil it for the others just yet).</p>
<p>But whether we get the point of the function or not,we can implement
it in Emacs Lisp, translating from the Scheme into Emacs Lisp (defining an
equivalent of <code>even?</code> as an Emacs Lisp <code>evenp</code> first) as:</p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="c1">;; -*- lexical-binding: t; -*-</span>
<span class="p">(</span><span class="nb">defun</span> <span class="nv">evenp</span> <span class="p">(</span><span class="nv">n</span><span class="p">)</span>
  <span class="s">&#34;Returns </span><span class="ss">`t&#39;</span><span class="s"> if </span><span class="ss">`n&#39;</span><span class="s"> is even.&#34;</span>
  <span class="p">(</span><span class="nb">if</span> <span class="p">(</span><span class="nf">=</span> <span class="p">(</span><span class="nf">%</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)</span> <span class="mi">0</span><span class="p">)</span>
      <span class="no">t</span>
    <span class="no">nil</span><span class="p">))</span>

<span class="p">(</span><span class="nb">defun</span> <span class="nv">C</span> <span class="p">(</span><span class="nv">n</span><span class="p">)</span>
  <span class="s">&#34;Function C from Little Schemer p.155.&#34;</span>
  <span class="p">(</span><span class="nb">cond</span>
   <span class="p">((</span><span class="nf">=</span> <span class="nv">n</span> <span class="mi">1</span><span class="p">)</span>
    <span class="mi">1</span><span class="p">)</span>
   <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span>
    <span class="p">(</span><span class="nv">C</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span>
   <span class="p">(</span><span class="no">t</span>
    <span class="p">(</span><span class="nv">C</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="mi">3</span> <span class="nv">n</span><span class="p">))))))</span>
</code></pre></div><div class="src-block-caption">
  <span class="src-block-number">Code Snippet 2:</span>
  translation of the The Little Schemer 'C' function into Elisp
</div>
<p>And we can try running this on various numbers:</p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="p">(</span><span class="nv">C</span> <span class="mi">1</span><span class="p">)</span> <span class="c1">; 1</span>
<span class="p">(</span><span class="nv">C</span> <span class="mi">9</span><span class="p">)</span> <span class="c1">; 1</span>
<span class="p">(</span><span class="nv">C</span> <span class="mi">108</span><span class="p">)</span> <span class="c1">; 1</span>
<span class="p">(</span><span class="nv">C</span> <span class="mi">837799</span><span class="p">)</span> <span class="c1">; 1</span>
<span class="p">(</span><span class="nv">C</span> <span class="mi">8400511</span><span class="p">)</span> <span class="c1">; 1</span>
<span class="p">(</span><span class="nv">C</span> <span class="mi">63728126</span><span class="p">)</span> <span class="c1">; 1</span>
</code></pre></div><p>That is, for all of these numbers it just outputs <code>1</code>. Well, we can try
a couple of other values:</p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="p">(</span><span class="nv">C</span> <span class="mi">0</span><span class="p">)</span> <span class="c1">; cl-prin1: (error &#34;Lisp nesting exceeds ‘max-lisp-eval-depth’&#34;)</span>
<span class="p">(</span><span class="nv">C</span> <span class="mi">63728127</span><span class="p">)</span> <span class="c1">; cl-prin1: (error &#34;Lisp nesting exceeds ‘max-lisp-eval-depth’&#34;)</span>
</code></pre></div><p>So <code>C</code> fails for <code>0</code> and numbers above <code>63728126</code>, with a &ldquo;excessive lisp
nesting&rdquo;-type issue.</p>
<p>But since the only non-error result we&rsquo;re getting is <code>1</code>, we could write
a much simpler function.<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="c1">;; -*- lexical-binding: t; -*-</span>
<span class="p">(</span><span class="nb">defun</span> <span class="nv">ersatz-C</span> <span class="p">(</span><span class="nv">n</span><span class="p">)</span>
  <span class="s">&#34;Returns 1 if </span><span class="ss">`n&#39;</span><span class="s"> is 1;
</span><span class="s">enter an infinite nesting loop
</span><span class="s">if </span><span class="ss">`n&#39;</span><span class="s"> is 0 or above 63728126;
</span><span class="s">for any other integer value,
</span><span class="s">pause briefly for sake of plausibly,
</span><span class="s">and then return 1.&#34;</span>
  <span class="p">(</span><span class="nb">cond</span>
   <span class="p">((</span><span class="nf">=</span> <span class="nv">n</span> <span class="mi">1</span><span class="p">)</span>
    <span class="mi">1</span><span class="p">)</span>
   <span class="p">((</span><span class="nf">=</span> <span class="nv">n</span> <span class="mi">0</span><span class="p">)</span>
    <span class="p">(</span><span class="nv">ersatz-C</span> <span class="nv">n</span><span class="p">))</span>
   <span class="p">((</span><span class="nf">&gt;</span> <span class="nv">n</span> <span class="mi">63728126</span><span class="p">)</span>
    <span class="p">(</span><span class="nv">ersatz-C</span> <span class="nv">n</span><span class="p">))</span>
   <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nb">progn</span>
        <span class="p">(</span><span class="nf">sleep-for</span> <span class="mf">0.005</span><span class="p">)</span>
        <span class="mi">1</span><span class="p">))))</span>
</code></pre></div><div class="src-block-caption">
  <span class="src-block-number">Code Snippet 3:</span>
  A simpler function to return "1"
</div>
<p>But obviously function <code>C</code> is doing something more interesting. So, let&rsquo;s make it
actually show us what it&rsquo;s doing:</p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="c1">;; -*- lexical-binding: t; -*-</span>
<span class="p">(</span><span class="nb">defun</span> <span class="nv">C-verbose</span> <span class="p">(</span><span class="nv">n</span> <span class="kp">&amp;optional</span> <span class="nv">count</span><span class="p">)</span>
  <span class="s">&#34;For a number </span><span class="ss">`n&#39;</span><span class="s">, return </span><span class="ss">`1&#39;</span><span class="s"> if it&#39;s </span><span class="ss">`1&#39;</span><span class="s">; otherwise,
</span><span class="s">if it&#39;s even, run the same function on half of </span><span class="ss">`n&#39;</span><span class="s">;
</span><span class="s">else, run the same function on one more than three times
</span><span class="s"></span><span class="ss">`n&#39;</span><span class="s">.&#34;</span>
  <span class="p">(</span><span class="nb">let</span> <span class="p">((</span><span class="nv">count</span> <span class="p">(</span><span class="nb">or</span> <span class="nv">count</span> <span class="mi">0</span><span class="p">)))</span>
    <span class="p">(</span><span class="nf">print</span> <span class="p">(</span><span class="nf">format</span> <span class="s">&#34;Step %s: %s&#34;</span> <span class="nv">count</span> <span class="nv">n</span><span class="p">))</span>
    <span class="p">(</span><span class="nb">setq</span> <span class="nv">count</span> <span class="p">(</span><span class="nf">1+</span> <span class="nv">count</span><span class="p">))</span>
    <span class="p">(</span><span class="nb">cond</span>
     <span class="p">((</span><span class="nf">=</span> <span class="nv">n</span> <span class="mi">1</span><span class="p">)</span>
      <span class="mi">1</span><span class="p">)</span>
     <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span>
      <span class="p">(</span><span class="nv">C-verbose</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)</span> <span class="nv">count</span><span class="p">))</span>
     <span class="p">(</span><span class="no">t</span>
      <span class="p">(</span><span class="nv">C-verbose</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="mi">3</span> <span class="nv">n</span><span class="p">))</span> <span class="nv">count</span><span class="p">)))))</span>

<span class="p">(</span><span class="nv">C-verbose</span> <span class="mi">7</span><span class="p">)</span> <span class="c1">; =</span>
<span class="c1">;; &#34;Step 0: 7&#34;</span>
<span class="c1">;; &#34;Step 1: 22&#34;</span>
<span class="c1">;; &#34;Step 2: 11&#34;</span>
<span class="c1">;; &#34;Step 3: 34&#34;</span>
<span class="c1">;; &#34;Step 4: 17&#34;</span>
<span class="c1">;; &#34;Step 5: 52&#34;</span>
<span class="c1">;; &#34;Step 6: 26&#34;</span>
<span class="c1">;; &#34;Step 7: 13&#34;</span>
<span class="c1">;; &#34;Step 8: 40&#34;</span>
<span class="c1">;; &#34;Step 9: 20&#34;</span>
<span class="c1">;; &#34;Step 10: 10&#34;</span>
<span class="c1">;; &#34;Step 11: 5&#34;</span>
<span class="c1">;; &#34;Step 12: 16&#34;</span>
<span class="c1">;; &#34;Step 13: 8&#34;</span>
<span class="c1">;; &#34;Step 14: 4&#34;</span>
<span class="c1">;; &#34;Step 15: 2&#34;</span>
<span class="c1">;; &#34;Step 16: 1&#34;</span>

<span class="p">(</span><span class="nv">C-verbose</span> <span class="mi">9</span><span class="p">)</span> <span class="c1">; =</span>
<span class="c1">;; &#34;Step 0: 9&#34;</span>
<span class="c1">;; &#34;Step 1: 28&#34;</span>
<span class="c1">;; &#34;Step 2: 14&#34;</span>
<span class="c1">;; &#34;Step 3: 7&#34;</span>
<span class="c1">;; &#34;Step 4: 22&#34;</span>
<span class="c1">;; &#34;Step 5: 11&#34;</span>
<span class="c1">;; &#34;Step 6: 34&#34;</span>
<span class="c1">;; &#34;Step 7: 17&#34;</span>
<span class="c1">;; &#34;Step 8: 52&#34;</span>
<span class="c1">;; &#34;Step 9: 26&#34;</span>
<span class="c1">;; &#34;Step 10: 13&#34;</span>
<span class="c1">;; &#34;Step 11: 40&#34;</span>
<span class="c1">;; &#34;Step 12: 20&#34;</span>
<span class="c1">;; &#34;Step 13: 10&#34;</span>
<span class="c1">;; &#34;Step 14: 5&#34;</span>
<span class="c1">;; &#34;Step 15: 16&#34;</span>
<span class="c1">;; &#34;Step 16: 8&#34;</span>
<span class="c1">;; &#34;Step 17: 4&#34;</span>
<span class="c1">;; &#34;Step 18: 2&#34;</span>
<span class="c1">;; &#34;Step 19: 1&#34;</span>
</code></pre></div><div class="src-block-caption">
  <span class="src-block-number">Code Snippet 4:</span>
  Write `C' to make it show us what it's doing; with some examples of use
</div>
<p>Perhaps not surprisingly, we see that setting <code>n=9</code> makes the function
take more steps to reach 1 than setting <code>n=7</code>. But it&rsquo;s not actually a
direct linear relation, because if we set <code>n=10</code>, it&rsquo;s a much shorter
path:</p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="p">(</span><span class="nv">C-verbose</span> <span class="mi">10</span><span class="p">)</span> <span class="c1">; =</span>
<span class="c1">;; &#34;Step 0: 10&#34;</span>
<span class="c1">;; &#34;Step 1: 5&#34;</span>
<span class="c1">;; &#34;Step 2: 16&#34;</span>
<span class="c1">;; &#34;Step 3: 8&#34;</span>
<span class="c1">;; &#34;Step 4: 4&#34;</span>
<span class="c1">;; &#34;Step 5: 2&#34;</span>
<span class="c1">;; &#34;Step 6: 1&#34;</span>
</code></pre></div><p>So we might still wonder about exactly what&rsquo;s going on with function
<code>C</code>, how it works, and what&rsquo;s the point of it anyway.</p>
<h2 id="conjectures-about-simple-arithmetic-operations-and-integer-pathways">Conjectures about simple arithmetic operations and integer pathways</h2>
<p><em>The Little Schemer</em> does give a clue about what <code>C</code> is, referring to the
question of whether it&rsquo;s a total function or not:</p>
<blockquote>
<p>It doesn&rsquo;t yield a value for 0, but otherwise nobody knows. Thank you,
Lothar Collatz (1910–1990).</p>
</blockquote>
<p>A bit of research and we can find quite a bit about <code>C</code>: it turns out to
be the <strong>Collatz conjecture</strong>: one of the most famous unsolved problems in
mathematics.</p>
<p>The <a href="https://en.wikipedia.org/wiki/Collatz_conjecture">Wikipedia page on the Collatz conjecture</a> is useful here in laying
out basics. As well, <a href="http://www.ericr.nl">Eric Roosendaal</a>&lsquo;s <a href="http://www.ericr.nl/wondrous/index.html">&ldquo;On the 3x + 1 problem&rdquo;</a>. And
Quantamagazine&rsquo;s <a href="https://www.quantamagazine.org/why-mathematicians-still-cant-solve-the-collatz-conjecture-20200922/">&ldquo;The Simple Math Problem We Still Can’t Solve&rdquo;</a>
presents a fairly accessible overview, including recent developments.</p>
<p>There&rsquo;s some very interesting visualisations of the Collatz Functions
paths as a Collatz tree, which is a rather aesthetically-appealling
visual object. Here&rsquo;s Algoritmarte&rsquo;s 3D live render, based on a
discussion from the <a href="https://www.youtube.com/@numberphile">Numberphile channel</a> (for Numberphile&rsquo;s original video, done by hand, see the fn):<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></p>
<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/4Z1MqCvMskI?si=tWIPRsVnYOwt2AuB" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
<center/><a href="https://www.algoritmarte.com/the-collatz-tree/"</>Algoritmarte's Collatz Tree visualisation</a></center><br/>
<p>But Collatz conjecture is an unsolved problem that looks like it
should certainly be solvable. It seems quite trivial in some sense:
inductive logic would seem to suggest that the same basic patterns
would repeat, even if there are more of them, or they are longer,
given that every number that&rsquo;s been tested has converged to 1 (or,
more precisely, fallen into the &ldquo;4-2-1&rdquo; loop) and so this tempts
people in trying to solve it. But Paul Erdős said of it &ldquo;Mathematics
may not be ready for such problems&rdquo;.<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup></p>



<figure>
    
        
            <img src="https://imgs.xkcd.com/comics/collatz_conjecture.png" alt="Figure 2: https://xkcd.com/710/ [see: https://www.explainxkcd.com/wiki/index.php/710:_Collatz_Conjecture ]"/> <figcaption>
                
                <p>
                    <span class="figure-number">Figure 2: </span><a href="https://xkcd.com/710/">https://xkcd.com/710/</a> [see: <a href="https://www.explainxkcd.com/wiki/index.php/710:_Collatz_Conjecture">https://www.explainxkcd.com/wiki/index.php/710:_Collatz_Conjecture</a> ]
                    
                        
                        </p>
                
            </figcaption></figure>

<p>Well, we&rsquo;ll not try to solve it, but rather use it for thinking about
issues of recursion and long calculations in Emacs Lisp, and doing
some practical engineering-type testing of different methods of
dealing with such functions.</p>
<p>One thing we might note, as a sort of aside, is that <em>The Little
Schemer</em>&lsquo;s <code>C</code> isn&rsquo;t properly the Collatz function. The conjecture is
really about whether the process will ever reach the repeating &ldquo;4-2-1&rdquo;
loop, because the process of dividing even numbers by 2 and multiple
odd numbers and adding 1 to them would actually mean that once we&rsquo;ve
reached 1, we need to multiple it by 3 and add 1, which means we&rsquo;re
back at 4, which is even, so we&rsquo;ll divide by 2 and get 2, which is
even, so we divide by 2 and get 1, which is odd, so we&hellip;. And so on.</p>
<p>We can write this &ldquo;real Collatz&rdquo; function:</p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="c1">;; -*- lexical-binding: t; -*-</span>
<span class="p">(</span><span class="nb">defun</span> <span class="nv">real-collatz</span> <span class="p">(</span><span class="nv">n</span><span class="p">)</span>
  <span class="s">&#34;For an integer </span><span class="ss">`n&#39;</span><span class="s">, if it&#39;s evan, divide it by 2;
</span><span class="s">if it&#39;s odd, multiple it by 3 and add 1.&#34;</span>
  <span class="p">(</span><span class="nb">cond</span>
   <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span>
    <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span>
   <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">))))))</span>
</code></pre></div><div class="src-block-caption">
  <span class="src-block-number">Code Snippet 5:</span>
  the real basic Collatz operations
</div>
<p>If we now try to feed it 9, we&rsquo;ll hit the lisp-nesting error, but if we turn on
<code>toggle-debug-on-error</code>, we can inspect what&rsquo;s going on, and it&rsquo;s
exactly the &ldquo;4-2-1&rdquo; loop we predicted:</p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="p">(</span><span class="nv">real-collatz</span> <span class="mi">9</span><span class="p">)</span> <span class="c1">; cl-prin1: (error &#34;Lisp nesting exceeds ‘max-lisp-eval-depth’&#34;)</span>

<span class="c1">;; DEBUG:</span>
<span class="o">....</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span> <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">)))))</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span> <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">)))))</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span> <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">)))))</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span> <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">)))))</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span> <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">)))))</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span> <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">)))))</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span> <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">)))))</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span> <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">)))))</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span> <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">)))))</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span> <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">)))))</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span> <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">)))))</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span> <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">)))))</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span> <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">)))))</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span> <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">)))))</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span> <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">)))))</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span> <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">)))))</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span> <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">)))))</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span> <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">)))))</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span> <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">)))))</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span> <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">)))))</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span> <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">)))))</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span> <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">)))))</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">16</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span> <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">)))))</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span> <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">)))))</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span> <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">)))))</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">20</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span> <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">)))))</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">40</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span> <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">)))))</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">13</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span> <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">)))))</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">26</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span> <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">)))))</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">52</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span> <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">)))))</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">17</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span> <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">)))))</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">34</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span> <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">)))))</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">11</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span> <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">)))))</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">22</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span> <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">)))))</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">7</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span> <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">)))))</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">14</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span> <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">)))))</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">28</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nv">evenp</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span> <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">real-collatz</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">n</span> <span class="mi">3</span><span class="p">)))))</span>
  <span class="nv">real-collatz</span><span class="p">(</span><span class="mi">9</span><span class="p">)</span>
  <span class="nf">eval</span><span class="p">((</span><span class="nv">real-collatz</span> <span class="mi">9</span><span class="p">)</span> <span class="no">nil</span><span class="p">)</span>
  <span class="nv">elisp--eval-last-sexp</span><span class="p">(</span><span class="no">nil</span><span class="p">)</span>
<span class="o">.....</span>
</code></pre></div><p>We&rsquo;ll make use of it later on though, somewhat (essentially with the
<code>n=1</code> condition displaced.)</p>
<h2 id="dealing-with-long-winding-paths-through-hailstorms">Dealing with long winding paths, through hailstorms</h2>
<p>Ok, so two things. One, let&rsquo;s not just print things (longer paths are
going to make his quite messy), but return a list of the steps our
function goes through and a count of them. We do still want to be able
to inspect the path patterns. (Wikipedia notes on this &ldquo;[t]he sequence
of numbers involved [in the paths] is sometimes referred to as the
hailstone sequence, hailstone numbers or hailstone numerals (because
the values are usually subject to multiple descents and ascents like
hailstones in a cloud)&quot;.)</p>
<p>And, two, let&rsquo;s use the <code>cl-labels</code> trick from last time to get
tail-call optimisation in Emacs.</p>
<p>(And a minor thing: not bother with a separate <code>evenp</code> function; just
use the calculation directly.)</p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="c1">;; -*- lexical-binding: t; -*-</span>
<span class="p">(</span><span class="nb">defun</span> <span class="nv">collatz-cllabels-tco</span> <span class="p">(</span><span class="nv">n</span><span class="p">)</span>
  <span class="s">&#34;Calculates the &#39;Collatz path&#39; for </span><span class="ss">`n&#39;</span><span class="s">,
</span><span class="s">return a list of all of the steps cons&#39;ed
</span><span class="s">with count of the steps in the path.
</span><span class="s">
</span><span class="s">[Uses </span><span class="ss">`cl-labels&#39;</span><span class="s"> to get tail-call optimisation.]&#34;</span>
  <span class="p">(</span><span class="nb">cl-labels</span> <span class="p">((</span><span class="nv">collatz*</span> <span class="p">(</span><span class="nv">n</span> <span class="nv">r</span><span class="p">)</span>
                  <span class="p">(</span><span class="nb">setq</span> <span class="nv">r</span> <span class="p">(</span><span class="nf">cons</span> <span class="nv">n</span> <span class="nv">r</span><span class="p">))</span>
                  <span class="p">(</span><span class="nb">cond</span>
                     <span class="p">((</span><span class="nf">=</span> <span class="nv">n</span> <span class="mi">1</span><span class="p">)</span>
                      <span class="nv">r</span><span class="p">)</span>
                     <span class="p">((</span><span class="nf">=</span> <span class="p">(</span><span class="nf">%</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)</span> <span class="mi">0</span><span class="p">)</span>
                        <span class="p">(</span><span class="nv">collatz*</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)</span> <span class="nv">r</span><span class="p">))</span>
                     <span class="p">(</span><span class="no">t</span>
                        <span class="p">(</span><span class="nv">collatz*</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="mi">3</span> <span class="nv">n</span><span class="p">))</span> <span class="nv">r</span><span class="p">)))))</span>
    <span class="p">(</span><span class="nb">let*</span> <span class="p">((</span><span class="nv">clst</span> <span class="p">(</span><span class="nv">collatz*</span> <span class="nv">n</span> <span class="no">nil</span><span class="p">))</span>
          <span class="p">(</span><span class="nv">clngth</span> <span class="p">(</span><span class="nf">1-</span> <span class="p">(</span><span class="nf">length</span> <span class="nv">clst</span><span class="p">))))</span>
      <span class="p">(</span><span class="nf">cons</span> <span class="p">(</span><span class="nf">nreverse</span> <span class="nv">clst</span><span class="p">)</span> <span class="nv">clngth</span><span class="p">))))</span>
</code></pre></div><div class="src-block-caption">
  <span class="src-block-number">Code Snippet 6:</span>
  A tail-call optimising implementation of a recursive Collatz function
</div>
<p>Here you will note that we&rsquo;ve got our <code>collatz*</code> function (defined in
<code>cl-labels</code>) being self-recursive only properly in tail positions, so it
can be tail-call optimised. We start by calling <code>collatz*</code> with
arguments <code>n</code> (whatever value we passed for <code>n</code>) and <code>nil</code>, with <code>collatz*</code>
taking two arguments, <code>n</code> and <code>r</code> and setting <code>r</code> to the <code>cons</code> of <code>n</code> with <code>r</code>
(we&rsquo;ll pass this value on, collecting the steps), and then
implementing the rest of the Collatz function in the same way as
previously, except passing along the <code>r</code> value as our collector. At the
end, we&rsquo;ll count the steps and <code>cons</code> the list of the steps themselves,
using <code>nreverse</code> to flip the list over (because it&rsquo;ll have the last
results on the &ldquo;outer&rdquo; left and the first results on the &ldquo;inner&rdquo;
right), with the step count.</p>
<p>Some examples:</p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="p">(</span><span class="nv">collatz-cllabels-tco</span> <span class="mi">9</span><span class="p">)</span> <span class="c1">; ((9 28 14 7 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1) . 20)</span>
                <span class="c1">; path from 9 to 1; 20 steps</span>

<span class="p">(</span><span class="nv">collatz-cllabels-tco</span> <span class="mi">21</span><span class="p">)</span> <span class="c1">; ((21 64 32 16 8 4 2 1) . 8)</span>
                 <span class="c1">; path from 21 to 1; 8 steps</span>
</code></pre></div><p>Excellent, but what about &ldquo;63728127&rdquo;?:— the number that tripped us up
before:</p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="c1">;; -*- lexical-binding: t; -*-</span>

<span class="p">(</span><span class="nv">collatz-cllabels-tco</span> <span class="mi">63728127</span><span class="p">)</span> <span class="c1">; it works!</span>

<span class="c1">;; ...but the result is quite long, you can try it yourself;</span>
<span class="c1">;; use setq to be able to see all of it, e.g.,</span>
<span class="c1">;; (setq c-result (collatz-cllabels-tco 63728127)).</span>

<span class="c1">;; for, let&#39;s just see how many steps it is:</span>
<span class="p">(</span><span class="nb">defun</span> <span class="nv">collatz-return-steps</span> <span class="p">(</span><span class="nv">n</span><span class="p">)</span>
  <span class="s">&#34;Output just the number of steps that
</span><span class="s"></span><span class="ss">`n&#39;</span><span class="s"> takes to reach 1.&#34;</span>
  <span class="p">(</span><span class="nf">format</span> <span class="s">&#34;%s takes %s steps to reach 1&#34;</span>
          <span class="nv">n</span>
          <span class="p">(</span><span class="nf">cdr</span>
           <span class="p">(</span><span class="nv">collatz-cllabels-tco</span> <span class="nv">n</span><span class="p">))))</span>


<span class="p">(</span><span class="nv">collatz-return-steps</span> <span class="mi">63728127</span><span class="p">)</span> <span class="c1">; =</span>
<span class="s">&#34;63728127 takes 949 steps to reach 1&#34;</span>
</code></pre></div><div class="src-block-caption">
  <span class="src-block-number">Code Snippet 7:</span>
  simple counting of Collatz steps on the path
</div>
<p>&ldquo;Let&rsquo;s try it with a bigger number!&quot;, you say. Well, we can try it on
<code>most-positive-fixnum</code> (which is I think probably set to
2305843009213693951 by default) — but remember the size of the number
and the number of steps is not a direct linear relation, so you might
be disappointed:</p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="p">(</span><span class="nv">collatz-return-steps</span> <span class="nv">most-positive-fixnum</span><span class="p">)</span> <span class="c1">; =</span>
<span class="s">&#34;2305843009213693951 takes 860 steps to reach 1&#34;</span>
</code></pre></div><p>This is less than for 63728127.</p>
<p>Ok, so let&rsquo;s make something really big then. <code>2^1000 + 1</code>.</p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="p">(</span><span class="nv">collatz-return-steps</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">expt</span> <span class="mi">2</span> <span class="mi">1000</span><span class="p">)))</span> <span class="c1">; =</span>
<span class="s">&#34;10715086071862673209484250490600018105614048117055336074437503883703510511249361224931983788156958581275946729175531468251871452856923140435984577574698574803934567774824230985421074605062371141877954182153046474983581941267398767559165543946077062914571196477686542167660429831652624386837205668069377 takes 7248 steps to reach 1&#34;</span>
</code></pre></div><p>It takes 7,248 steps. What about <code>2^10000 + 1</code>?</p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="p">(</span><span class="nv">collatz-return-steps</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">expt</span> <span class="mi">2</span> <span class="mi">10000</span><span class="p">)))</span> <span class="c1">; =</span>
<span class="s">&#34;19950631168807583848837421626835850838234968318861924548520089498529438830221946631919961684036194597899331129423209124271556491349413781117593785932096323957855730046793794526765246551266059895520550086918193311542508608460618104685509074866089624888090489894838009253941633257850621568309473902556912388065225096643874441046759871626985453222868538161694315775629640762836880760732228535091641476183956381458969463899410840960536267821064621427333394036525565649530603142680234969400335934316651459297773279665775606172582031407994198179607378245683762280037302885487251900834464581454650557929601414833921615734588139257095379769119277800826957735674444123062018757836325502728323789270710373802866393031428133241401624195671690574061419654342324638801248856147305207431992259611796250130992860241708340807605932320161268492288496255841312844061536738951487114256315111089745514203313820202931640957596464756010405845841566072044962867016515061920631004186422275908670900574606417856951911456055068251250406007519842261898059237118054444788072906395242548339221982707404473162376760846613033778706039803413197133493654622700563169937455508241780972810983291314403571877524768509857276937926433221599399876886660808368837838027643282775172273657572744784112294389733810861607423253291974813120197604178281965697475898164531258434135959862784130128185406283476649088690521047580882615823961985770122407044330583075869039319604603404973156583208672105913300903752823415539745394397715257455290510212310947321610753474825740775273986348298498340756937955646638621874569499279016572103701364433135817214311791398222983845847334440270964182851005072927748364550578634501100852987812389473928699540834346158807043959118985815145779177143619698728131459483783202081474982171858011389071228250905826817436220577475921417653715687725614904582904992461028630081535583308130101987675856234343538955409175623400844887526162643568648833519463720377293240094456246923254350400678027273837755376406726898636241037491410966718557050759098100246789880178271925953381282421954028302759408448955014676668389697996886241636313376393903373455801407636741877711055384225739499110186468219696581651485130494222369947714763069155468217682876200362777257723781365331611196811280792669481887201298643660768551639860534602297871557517947385246369446923087894265948217008051120322365496288169035739121368338393591756418733850510970271613915439590991598154654417336311656936031122249937969999226781732358023111862644575299135758175008199839236284615249881088960232244362173771618086357015468484058622329792853875623486556440536962622018963571028812361567512543338303270029097668650568557157505516727518899194129711337690149916181315171544007728650573189557450920330185304847113818315407324053319038462084036421763703911550639789000742853672196280903477974533320468368795868580237952218629120080742819551317948157624448298518461509704888027274721574688131594750409732115080498190455803416826949787141316063210686391511681774304792596709377 takes 72378 steps to reach 1&#34;</span>
</code></pre></div><p>72,378 steps.</p>
<p>Can we go one bigger?</p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="p">(</span><span class="nv">collatz-return-steps</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">expt</span> <span class="mi">2</span> <span class="mi">100000</span><span class="p">)))</span>
<span class="c1">;; Debugger entered--Lisp error: (overflow-error)</span>
</code></pre></div><p>No. But it&rsquo;s because Emacs has <code>maximum-integer-width</code> set to 65536 (so
a number can only be 65,536 digits long). We can set it to something
bigger, and it&rsquo;ll work.</p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="p">(</span><span class="nb">let</span> <span class="p">((</span><span class="nv">integer-width</span> <span class="mi">99999999</span><span class="p">))</span>
  <span class="p">(</span><span class="nv">collatz-return-steps</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">expt</span> <span class="mi">2</span> <span class="mi">100000</span><span class="p">))))</span> <span class="c1">; =</span>

<span class="c1">;; I&#39;ll spare you the number `n&#39; itself as it&#39;s realy quite long,</span>
<span class="c1">;; but that number takes 717,858 steps to reach 1.</span>
</code></pre></div><p>You&rsquo;ll note, if you&rsquo;ve been evaluating along in your own Emacs that
these results have been nearly instantaneous so far. This one takes a
bit longer.</p>
<p>(I subsequently tried doing <code>collatz-cllabels-tco</code> on <code>2^1000000 + 1</code>, but with only
16Gb in my machine, Linux&rsquo;s <a href="https://docs.kernel.org/admin-guide/mm/concepts.html#id9">OOM-killer</a> killed Emacs before it reached
the end. I should probably try setting up some sort of swap better.)</p>
<h2 id="streaming-though-the-hail">Streaming though the hail</h2>
<p>We can also try the <a href="https://elpa.gnu.org/packages/stream.html"><code>stream</code></a> package <a href="https://babbagefiles.xyz/lambda-calculus-and-lisp-02-recursion/#stream-of-conses-ness">we looked at before</a>, which
creates &ldquo;lazy&rdquo; conses, of potentially infinite sequences, which can be
evaluated one piece at a time, as needed.</p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="p">(</span><span class="nb">defun</span> <span class="nv">collatz-stream</span> <span class="p">(</span><span class="nv">n</span><span class="p">)</span>
  <span class="s">&#34;For a number </span><span class="ss">`n&#39;</span><span class="s">, return </span><span class="ss">`1&#39;</span><span class="s"> if it&#39;s </span><span class="ss">`1&#39;</span><span class="s">; otherwise,
</span><span class="s">if it&#39;s even, run the same function on half of </span><span class="ss">`n&#39;</span><span class="s">;
</span><span class="s">else, run the same function on one more than three times
</span><span class="s"></span><span class="ss">`n&#39;</span><span class="s">.
</span><span class="s">(Also, collect each step into a list and, when </span><span class="ss">`n&#39;</span><span class="s"> is </span><span class="ss">`1&#39;</span><span class="s">,
</span><span class="s">print the list.)
</span><span class="s">[Uses the </span><span class="ss">`stream&#39;</span><span class="s"> package for lazy-evaluated conses.]&#34;</span>
  <span class="p">(</span><span class="nb">cl-labels</span> <span class="p">((</span><span class="nv">collatz*</span> <span class="p">(</span><span class="nv">n</span><span class="p">)</span>
                <span class="p">(</span><span class="nv">stream-cons</span> <span class="nv">n</span>
                             <span class="c1">;; note that this is the `real&#39; collatz func</span>
                             <span class="c1">;; no checking for 1 here; we do it below</span>
                              <span class="p">(</span><span class="nb">cond</span>
                               <span class="p">((</span><span class="nf">=</span> <span class="p">(</span><span class="nf">%</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)</span> <span class="mi">0</span><span class="p">)</span>
                                <span class="p">(</span><span class="nv">collatz*</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span>
                               <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nv">collatz*</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="mi">3</span> <span class="nv">n</span><span class="p">))))))))</span>
    <span class="p">(</span><span class="nb">let</span> <span class="p">((</span><span class="nv">clst</span> <span class="p">(</span><span class="nv">collatz*</span> <span class="nv">n</span><span class="p">))</span>
          <span class="p">(</span><span class="nv">last</span> <span class="mi">0</span><span class="p">)</span>
          <span class="p">(</span><span class="nv">out</span> <span class="no">nil</span><span class="p">))</span>
      <span class="p">(</span><span class="nb">while</span> <span class="p">(</span><span class="nv">not</span> <span class="p">(</span><span class="nf">=</span> <span class="nv">last</span> <span class="mi">1</span><span class="p">))</span> <span class="c1">;; stop when we reach 1</span>
        <span class="p">(</span><span class="nb">setq</span> <span class="nv">last</span> <span class="p">(</span><span class="nv">stream-pop</span> <span class="nv">clst</span><span class="p">))</span>
        <span class="p">(</span><span class="nb">setq</span> <span class="nv">out</span> <span class="p">(</span><span class="nf">cons</span> <span class="nv">last</span> <span class="nv">out</span><span class="p">)))</span>
      <span class="p">(</span><span class="nb">let*</span> <span class="p">((</span><span class="nv">steps</span> <span class="p">(</span><span class="nf">1-</span> <span class="p">(</span><span class="nf">length</span> <span class="nv">out</span><span class="p">)))</span>
            <span class="p">(</span><span class="nv">rlist</span> <span class="p">(</span><span class="nf">nreverse</span> <span class="nv">out</span><span class="p">)))</span>
        <span class="p">(</span><span class="nf">cons</span> <span class="nv">rlist</span> <span class="nv">steps</span><span class="p">)))))</span>
</code></pre></div><div class="src-block-caption">
  <span class="src-block-number">Code Snippet 8:</span>
  Using lazy cons sequences in "stream" for Collatz calculations
</div>
<p>This, however, turns out to in fact be much slower than our <code>cl-labels</code>
tco recursion.</p>
<p>In fact, we can quantify this a bit further using <a href="https://github.com/alphapapa/">Adam Porter</a>&lsquo;s
<a href="https://github.com/alphapapa/emacs-package-dev-handbook?tab=readme-ov-file#benchmarking"><code>bench-multi</code> macro</a>:</p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="p">(</span><span class="nv">bench-multi</span>
  <span class="nb">:times</span> <span class="mi">5</span>
  <span class="nb">:forms</span> <span class="p">((</span><span class="s">&#34;collatz-stream&#34;</span> <span class="p">(</span><span class="nb">let</span> <span class="p">((</span><span class="nv">integer-width</span> <span class="mi">99999999</span><span class="p">))</span>
            <span class="p">(</span><span class="nv">collatz-stream</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">expt</span> <span class="mi">2</span> <span class="mi">10000</span><span class="p">)))))</span>
          <span class="p">(</span><span class="s">&#34;collatz-cllabels-tco&#34;</span> <span class="p">(</span><span class="nb">let</span> <span class="p">((</span><span class="nv">integer-width</span> <span class="mi">99999999</span><span class="p">))</span>
            <span class="p">(</span><span class="nv">collatz-cllabels-tco</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">expt</span> <span class="mi">2</span> <span class="mi">10000</span><span class="p">)))))))</span>
</code></pre></div><div class="src-block-caption">
  <span class="src-block-number">Code Snippet 9:</span>
  bench-marking cl-labels vs stream collatz functions
</div>
<p>Here the forms are ranked in order by fastest first; the second column
says how much slower the form is compared against the fastest; then
there are total runtime (for all iterations; we did here 5 for each);
and total <a href="https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)">garbage collections</a> performed by Emacs during those tests;
and the total amount of time the garbage collection tasks themselves took.</p>
<table>
<thead>
<tr>
<th>Form</th>
<th>x fastest</th>
<th>Total runtime</th>
<th># of GCs</th>
<th>Total GC runtime</th>
</tr>
</thead>
<tbody>
<tr>
<td>collatz-cllabels-tco</td>
<td>fastest</td>
<td>1.310546</td>
<td>2</td>
<td>0.484381</td>
</tr>
<tr>
<td>collatz-stream</td>
<td>12.72</td>
<td>16.665472</td>
<td>45</td>
<td>11.808777</td>
</tr>
</tbody>
</table>
<p>I&rsquo;m not quite sure why <code>collatz-stream</code> is this much slower than
<code>collatz-cllabels-tco</code> is the case. My guess is that because of the delayed/lazy
evaluation, we aren&rsquo;t able to get real reduction of <a href="https://en.wikipedia.org/wiki/Call_stack#STACK-FRAME">stack frames</a>
because we&rsquo;re only evaluating one piece/instance of the Collatz
function on each <code>stream-pop</code>, and there&rsquo;s no advantage to using <code>cl-labels</code>
here really.</p>
<p>The <code>stream</code> method certainly triggers more garbage collection, which is
part of it, though I&rsquo;m not entirely sure why it should involve
triggering more garbage collection. (I suppose we could play with
garbage collection settings in emacs and see if we can deal garbage
collection and make the <code>stream</code> method better.)</p>
<h2 id="caught-in-loops-still">Caught in loops still?</h2>
<p>But what about a plain looping method for the Collatz function. We
generally saw with the Fibonacci series that <a href="/lambda-calculus-and-lisp-02-recursion/#back-to-loops">loops seemed more
efficient</a>.</p>
<p>We can try with both plain <code>while</code> loops and also <code>cl-loops</code>:</p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="p">(</span><span class="nb">defun</span> <span class="nv">collatz-while-loop</span> <span class="p">(</span><span class="nv">n</span><span class="p">)</span>
  <span class="s">&#34;Collatz function using emacs </span><span class="ss">`while&#39;</span><span class="s"> loop.&#34;</span>
  <span class="p">(</span><span class="nb">let</span> <span class="p">((</span><span class="nv">m</span> <span class="nv">n</span><span class="p">)</span>
        <span class="p">(</span><span class="nv">clst</span> <span class="p">(</span><span class="nf">list</span> <span class="nv">n</span><span class="p">)))</span>
    <span class="p">(</span><span class="nb">while</span> <span class="p">(</span><span class="nv">not</span> <span class="p">(</span><span class="nf">=</span> <span class="nv">m</span> <span class="mi">1</span><span class="p">))</span>
      <span class="p">(</span><span class="nb">setq</span> <span class="nv">m</span>
            <span class="p">(</span><span class="nb">cond</span>
             <span class="p">((</span><span class="nf">=</span> <span class="p">(</span><span class="nf">%</span> <span class="nv">m</span> <span class="mi">2</span><span class="p">)</span> <span class="mi">0</span><span class="p">)</span>
              <span class="p">(</span><span class="nf">/</span> <span class="nv">m</span> <span class="mi">2</span><span class="p">))</span>
             <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="mi">3</span> <span class="nv">m</span><span class="p">)))))</span>
      <span class="p">(</span><span class="nb">setq</span> <span class="nv">clst</span> <span class="p">(</span><span class="nf">cons</span> <span class="nv">m</span> <span class="nv">clst</span><span class="p">)))</span>
          <span class="p">(</span><span class="nb">let*</span> <span class="p">((</span><span class="nv">steps</span> <span class="p">(</span><span class="nf">1-</span> <span class="p">(</span><span class="nf">length</span> <span class="nv">clst</span><span class="p">)))</span>
            <span class="p">(</span><span class="nv">rlist</span> <span class="p">(</span><span class="nf">nreverse</span> <span class="nv">clst</span><span class="p">)))</span>
            <span class="p">(</span><span class="nf">cons</span> <span class="nv">rlist</span> <span class="nv">steps</span><span class="p">))))</span>

<span class="p">(</span><span class="nb">defun</span> <span class="nv">collatz-cl-loop</span> <span class="p">(</span><span class="nv">n</span><span class="p">)</span>
  <span class="s">&#34;Collatz function using </span><span class="ss">`cl-loop&#39;</span><span class="s"> with
</span><span class="s"></span><span class="ss">`while&#39;</span><span class="s"> clause condition.&#34;</span>
  <span class="p">(</span><span class="nb">let</span> <span class="p">((</span><span class="nv">m</span> <span class="nv">n</span><span class="p">)</span>
        <span class="p">(</span><span class="nv">clst</span> <span class="p">(</span><span class="nf">list</span> <span class="nv">n</span><span class="p">)))</span>
    <span class="p">(</span><span class="nb">cl-loop</span> <span class="nb">while</span> <span class="p">(</span><span class="nv">not</span> <span class="p">(</span><span class="nf">=</span> <span class="nv">m</span> <span class="mi">1</span><span class="p">))</span>
             <span class="nb">do</span> <span class="p">(</span><span class="nb">progn</span>
                  <span class="p">(</span><span class="nb">setq</span> <span class="nv">m</span>
                        <span class="p">(</span><span class="nb">cond</span>
                         <span class="p">((</span><span class="nf">=</span> <span class="p">(</span><span class="nf">%</span> <span class="nv">m</span> <span class="mi">2</span><span class="p">)</span> <span class="mi">0</span><span class="p">)</span>
                          <span class="p">(</span><span class="nf">/</span> <span class="nv">m</span> <span class="mi">2</span><span class="p">))</span>
                         <span class="p">(</span><span class="no">t</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="mi">3</span> <span class="nv">m</span><span class="p">)))))</span>
                  <span class="p">(</span><span class="nb">setq</span> <span class="nv">clst</span> <span class="p">(</span><span class="nf">cons</span> <span class="nv">m</span> <span class="nv">clst</span><span class="p">)))</span>
             <span class="p">(</span><span class="nb">let*</span> <span class="p">((</span><span class="nv">steps</span> <span class="p">(</span><span class="nf">1-</span> <span class="p">(</span><span class="nf">length</span> <span class="nv">clst</span><span class="p">)))</span>
                    <span class="p">(</span><span class="nv">rlist</span> <span class="p">(</span><span class="nf">nreverse</span> <span class="nv">clst</span><span class="p">)))</span>
               <span class="p">(</span><span class="nf">cons</span> <span class="nv">rlist</span> <span class="nv">steps</span><span class="p">))))</span>
</code></pre></div><div class="src-block-caption">
  <span class="src-block-number">Code Snippet 10:</span>
  looping methods for the Collatz function
</div>
<p>And now comparing all of the methods:</p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="p">(</span><span class="nv">bench-multi</span>
  <span class="nb">:times</span> <span class="mi">5</span>
  <span class="nb">:forms</span> <span class="p">((</span><span class="s">&#34;collatz-stream&#34;</span>
           <span class="p">(</span><span class="nb">let</span> <span class="p">((</span><span class="nv">integer-width</span> <span class="mi">99999999</span><span class="p">))</span>
             <span class="p">(</span><span class="nv">collatz-stream</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">expt</span> <span class="mi">2</span> <span class="mi">10000</span><span class="p">)))))</span>
          <span class="p">(</span><span class="s">&#34;collatz-cllabels-tco&#34;</span>
           <span class="p">(</span><span class="nb">let</span> <span class="p">((</span><span class="nv">integer-width</span> <span class="mi">99999999</span><span class="p">))</span>
             <span class="p">(</span><span class="nv">collatz-cllabels-tco</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">expt</span> <span class="mi">2</span> <span class="mi">10000</span><span class="p">)))))</span>
          <span class="p">(</span><span class="s">&#34;collatz-while-loop&#34;</span>
           <span class="p">(</span><span class="nb">let</span> <span class="p">((</span><span class="nv">integer-width</span> <span class="mi">99999999</span><span class="p">))</span>
             <span class="p">(</span><span class="nv">collatz-while-loop</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">expt</span> <span class="mi">2</span> <span class="mi">10000</span><span class="p">)))))</span>
          <span class="p">(</span><span class="s">&#34;collatz-cl-loop&#34;</span>
           <span class="p">(</span><span class="nb">let</span> <span class="p">((</span><span class="nv">integer-width</span> <span class="mi">99999999</span><span class="p">))</span>
             <span class="p">(</span><span class="nv">collatz-cl-loop</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">expt</span> <span class="mi">2</span> <span class="mi">10000</span><span class="p">)))))))</span>
</code></pre></div><div class="src-block-caption">
  <span class="src-block-number">Code Snippet 11:</span>
  bench-marking our Collatz function implementations
</div>
<p>We find the following results:</p>
<table>
<thead>
<tr>
<th>Form</th>
<th>x fastest</th>
<th>Total runtime</th>
<th># of GCs</th>
<th>Total GC runtime</th>
</tr>
</thead>
<tbody>
<tr>
<td>collatz-while-loop</td>
<td>fastest</td>
<td>0.876315</td>
<td>1</td>
<td>0.240661</td>
</tr>
<tr>
<td>collatz-cl-loop</td>
<td>1.02</td>
<td>0.896261</td>
<td>1</td>
<td>0.235273</td>
</tr>
<tr>
<td>collatz-cllabels-tco</td>
<td>1.43</td>
<td>1.255294</td>
<td>2</td>
<td>0.449736</td>
</tr>
<tr>
<td>collatz-stream</td>
<td>18.77</td>
<td>16.446478</td>
<td>48</td>
<td>11.677753</td>
</tr>
</tbody>
</table>
<p>Both types of loops turn out faster than even <code>collatz-cllabels-tco</code>, with the
plain emacs <code>while loop</code> method seeming slightly faster than the <code>cl-loop</code>
method, but probably within margin of error (or maybe just a bit of
extra machine in <code>cl-loop</code> which loses a small amount of efficiency.)</p>
<p>For our TCO tail-recurive <code>cll</code> maybe it&rsquo;s the additional garbage collection
that slows down <code>collatz-cllabels-tco</code>.</p>
<p>What if we just look at the two loop methods, and run more trials?</p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="p">(</span><span class="nv">bench-multi</span>
  <span class="nb">:times</span> <span class="mi">100</span>
  <span class="nb">:forms</span> <span class="p">((</span><span class="s">&#34;collatz-while-loop&#34;</span>
           <span class="p">(</span><span class="nb">let</span> <span class="p">((</span><span class="nv">integer-width</span> <span class="mi">99999999</span><span class="p">))</span>
             <span class="p">(</span><span class="nv">collatz-while-loop</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">expt</span> <span class="mi">2</span> <span class="mi">10000</span><span class="p">)))))</span>
          <span class="p">(</span><span class="s">&#34;collatz-cl-loop&#34;</span>
           <span class="p">(</span><span class="nb">let</span> <span class="p">((</span><span class="nv">integer-width</span> <span class="mi">99999999</span><span class="p">))</span>
             <span class="p">(</span><span class="nv">collatz-cl-loop</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">expt</span> <span class="mi">2</span> <span class="mi">10000</span><span class="p">)))))))</span>
</code></pre></div><div class="src-block-caption">
  <span class="src-block-number">Code Snippet 12:</span>
  bench-marking loop methods of implementing the Collatz function
</div>
<p>Our results are:</p>
<table>
<thead>
<tr>
<th>Form</th>
<th>x fastest</th>
<th>Total runtime</th>
<th># of GCs</th>
<th>Total GC runtime</th>
</tr>
</thead>
<tbody>
<tr>
<td>collatz-while-loop</td>
<td>fastest</td>
<td>17.584334</td>
<td>20</td>
<td>4.851656</td>
</tr>
<tr>
<td>collatz-cl-loop</td>
<td>1.03</td>
<td>18.027418</td>
<td>20</td>
<td>5.070158</td>
</tr>
</tbody>
</table>
<p>Still the plain <code>while</code> is slightly faster than <code>cl-loop</code>.</p>
<h3 id="an-attempt-at-promoting-our-recursive-tco-function">An attempt at promoting our recursive tco function</h3>
<p>I&rsquo;d really like to somehow improve our recursive TCO collatz function.</p>
<p>What if we pull the collector <code>r</code> out in a higher-scoping <code>let</code> and so
don&rsquo;t have to pass it into <code>collatz*</code> each time; thus:</p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="p">(</span><span class="nb">defun</span> <span class="nv">collatz-cllabels-tco-improved</span> <span class="p">(</span><span class="nv">n</span><span class="p">)</span>
  <span class="s">&#34;Calculates the &#39;Collatz path&#39; for </span><span class="ss">`n&#39;</span><span class="s">,
</span><span class="s">return a list of all of the steps cons&#39;ed
</span><span class="s">with count of the steps in the path.
</span><span class="s">
</span><span class="s">[Uses </span><span class="ss">`cl-labels&#39;</span><span class="s"> to get tail-call optimisation.]&#34;</span>
  <span class="p">(</span><span class="nb">let</span> <span class="p">((</span><span class="nv">r</span> <span class="no">nil</span><span class="p">))</span>
    <span class="p">(</span><span class="nb">cl-labels</span> <span class="p">((</span><span class="nv">collatz*</span> <span class="p">(</span><span class="nv">n</span><span class="p">)</span>
                    <span class="p">(</span><span class="nb">setq</span> <span class="nv">r</span> <span class="p">(</span><span class="nf">cons</span> <span class="nv">n</span> <span class="nv">r</span><span class="p">))</span>
                    <span class="p">(</span><span class="nb">cond</span>
                       <span class="p">((</span><span class="nf">=</span> <span class="nv">n</span> <span class="mi">1</span><span class="p">)</span>
                        <span class="nv">r</span><span class="p">)</span>
                       <span class="p">((</span><span class="nf">=</span> <span class="p">(</span><span class="nf">%</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)</span> <span class="mi">0</span><span class="p">)</span>
                          <span class="p">(</span><span class="nv">collatz*</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">n</span> <span class="mi">2</span><span class="p">)))</span>
                       <span class="p">(</span><span class="no">t</span>
                          <span class="p">(</span><span class="nv">collatz*</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">*</span> <span class="mi">3</span> <span class="nv">n</span><span class="p">)))))))</span>
      <span class="p">(</span><span class="nb">let*</span> <span class="p">((</span><span class="nv">clst</span> <span class="p">(</span><span class="nv">collatz*</span> <span class="nv">n</span><span class="p">))</span>
            <span class="p">(</span><span class="nv">clngth</span> <span class="p">(</span><span class="nf">length</span> <span class="nv">clst</span><span class="p">)))</span>
        <span class="p">(</span><span class="nf">cons</span> <span class="p">(</span><span class="nf">nreverse</span> <span class="nv">clst</span><span class="p">)</span> <span class="nv">clngth</span><span class="p">)))))</span>
</code></pre></div><div class="src-block-caption">
  <span class="src-block-number">Code Snippet 13:</span>
  trying to eke out more performance for TCO cl-labels recursive Collatz function
</div>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="p">(</span><span class="nv">bench-multi</span>
  <span class="nb">:times</span> <span class="mi">10</span>
  <span class="nb">:forms</span> <span class="p">((</span><span class="s">&#34;collatz-cllabels-tco&#34;</span>
           <span class="p">(</span><span class="nb">let</span> <span class="p">((</span><span class="nv">integer-width</span> <span class="mi">99999999</span><span class="p">))</span>
             <span class="p">(</span><span class="nv">collatz-cllabels-tco</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">expt</span> <span class="mi">2</span> <span class="mi">10000</span><span class="p">)))))</span>
          <span class="p">(</span><span class="s">&#34;collatz-cllabels-tco-improved&#34;</span>
           <span class="p">(</span><span class="nb">let</span> <span class="p">((</span><span class="nv">integer-width</span> <span class="mi">99999999</span><span class="p">))</span>
             <span class="p">(</span><span class="nv">collatz-cllabels-tco-improved</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">expt</span> <span class="mi">2</span> <span class="mi">10000</span><span class="p">)))))))</span>
</code></pre></div><div class="src-block-caption">
  <span class="src-block-number">Code Snippet 14:</span>
  bench-marking the two cl-labels recursive Collatz functions
</div>
<p>Here are the results:</p>
<table>
<thead>
<tr>
<th>Form</th>
<th>x fastest</th>
<th>Total runtime</th>
<th># of GCs</th>
<th>Total GC runtime</th>
</tr>
</thead>
<tbody>
<tr>
<td>collatz-cllabels-tco-improved</td>
<td>fastest</td>
<td>2.198572</td>
<td>3</td>
<td>0.719563</td>
</tr>
<tr>
<td>collatz-cllabels-tco</td>
<td>1.17</td>
<td>2.579470</td>
<td>4</td>
<td>0.923288</td>
</tr>
</tbody>
</table>
<p>We do seem to eke out a bit more performance.</p>
<p>But compared to the loops, it&rsquo;s still not as performant:</p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="p">(</span><span class="nv">bench-multi</span>
  <span class="nb">:times</span> <span class="mi">10</span>
  <span class="nb">:forms</span> <span class="p">((</span><span class="s">&#34;collatz-cllabels-tco&#34;</span>
           <span class="p">(</span><span class="nb">let</span> <span class="p">((</span><span class="nv">integer-width</span> <span class="mi">99999999</span><span class="p">))</span>
             <span class="p">(</span><span class="nv">collatz-cllabels-tco</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">expt</span> <span class="mi">2</span> <span class="mi">10000</span><span class="p">)))))</span>
          <span class="p">(</span><span class="s">&#34;collatz-cllabels-tco-improved&#34;</span>
           <span class="p">(</span><span class="nb">let</span> <span class="p">((</span><span class="nv">integer-width</span> <span class="mi">99999999</span><span class="p">))</span>
             <span class="p">(</span><span class="nv">collatz-cllabels-tco-improved</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">expt</span> <span class="mi">2</span> <span class="mi">10000</span><span class="p">)))))</span>
          <span class="p">(</span><span class="s">&#34;collatz-while-loop&#34;</span>
           <span class="p">(</span><span class="nb">let</span> <span class="p">((</span><span class="nv">integer-width</span> <span class="mi">99999999</span><span class="p">))</span>
             <span class="p">(</span><span class="nv">collatz-while-loop</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">expt</span> <span class="mi">2</span> <span class="mi">10000</span><span class="p">)))))</span>
          <span class="p">(</span><span class="s">&#34;collatz-cl-loop&#34;</span>
           <span class="p">(</span><span class="nb">let</span> <span class="p">((</span><span class="nv">integer-width</span> <span class="mi">99999999</span><span class="p">))</span>
             <span class="p">(</span><span class="nv">collatz-cl-loop</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">expt</span> <span class="mi">2</span> <span class="mi">10000</span><span class="p">)))))))</span>
</code></pre></div><div class="src-block-caption">
  <span class="src-block-number">Code Snippet 15:</span>
  benchmarking two cl-labels and two loop Collatz implementations
</div>
<p>We seem to have done a bit better. Now <code>collatz-cllabels-tco-improved</code> is only
1.26x slower than the fastest, <code>collatz-while-loop</code>. We save an extra gc
over the older <code>collatz-cllabels-tco</code>, but still have to run an additional one
compared to the two loop functions.</p>
<table>
<thead>
<tr>
<th>Form</th>
<th>x fastest</th>
<th>Total runtime</th>
<th># of GCs</th>
<th>Total GC runtime</th>
</tr>
</thead>
<tbody>
<tr>
<td>collatz-while-loop</td>
<td>fastest</td>
<td>1.754987</td>
<td>2</td>
<td>0.486154</td>
</tr>
<tr>
<td>collatz-cl-loop</td>
<td>1.01</td>
<td>1.769489</td>
<td>2</td>
<td>0.486728</td>
</tr>
<tr>
<td>collatz-cllabels-tco-improved</td>
<td>1.26</td>
<td>2.208662</td>
<td>3</td>
<td>0.732637</td>
</tr>
<tr>
<td>collatz-cllabels-tco</td>
<td>1.44</td>
<td>2.528099</td>
<td>4</td>
<td>0.899793</td>
</tr>
</tbody>
</table>
<p>Putting all of the methods we&rsquo;ve come up with together and running more trials:</p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="p">(</span><span class="nv">bench-multi</span>
  <span class="nb">:times</span> <span class="mi">100</span>
  <span class="nb">:forms</span> <span class="p">((</span><span class="s">&#34;collatz-stream&#34;</span>
           <span class="p">(</span><span class="nb">let</span> <span class="p">((</span><span class="nv">integer-width</span> <span class="mi">99999999</span><span class="p">))</span>
             <span class="p">(</span><span class="nv">collatz-stream</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">expt</span> <span class="mi">2</span> <span class="mi">10000</span><span class="p">)))))</span>
          <span class="p">(</span><span class="s">&#34;collatz-cllabels-tco&#34;</span>
           <span class="p">(</span><span class="nb">let</span> <span class="p">((</span><span class="nv">integer-width</span> <span class="mi">99999999</span><span class="p">))</span>
             <span class="p">(</span><span class="nv">collatz-cllabels-tco</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">expt</span> <span class="mi">2</span> <span class="mi">10000</span><span class="p">)))))</span>
          <span class="p">(</span><span class="s">&#34;collatz-cllabels-tco-improved&#34;</span>
           <span class="p">(</span><span class="nb">let</span> <span class="p">((</span><span class="nv">integer-width</span> <span class="mi">99999999</span><span class="p">))</span>
             <span class="p">(</span><span class="nv">collatz-cllabels-tco-improved</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">expt</span> <span class="mi">2</span> <span class="mi">10000</span><span class="p">)))))</span>
          <span class="p">(</span><span class="s">&#34;collatz-while-loop&#34;</span>
           <span class="p">(</span><span class="nb">let</span> <span class="p">((</span><span class="nv">integer-width</span> <span class="mi">99999999</span><span class="p">))</span>
             <span class="p">(</span><span class="nv">collatz-while-loop</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">expt</span> <span class="mi">2</span> <span class="mi">10000</span><span class="p">)))))</span>
          <span class="p">(</span><span class="s">&#34;collatz-cl-loop&#34;</span>
           <span class="p">(</span><span class="nb">let</span> <span class="p">((</span><span class="nv">integer-width</span> <span class="mi">99999999</span><span class="p">))</span>
             <span class="p">(</span><span class="nv">collatz-cl-loop</span> <span class="p">(</span><span class="nf">1+</span> <span class="p">(</span><span class="nf">expt</span> <span class="mi">2</span> <span class="mi">10000</span><span class="p">)))))))</span>
</code></pre></div><div class="src-block-caption">
  <span class="src-block-number">Code Snippet 16:</span>
  full benchmark of all of our Collatz implementations
</div>
<p>Here, interestingly, we end up with <code>collatz-cl-loop</code> slightly edging
out <code>collatz-while-loop</code>. And our favourite (well, my favourite)
<code>collatz-cllabels-tco-improved</code> function doesn&rsquo;t do too poorly: it&rsquo;s only x1.28 slower
than the fastest (<code>collatz-cl-loop</code>); and even the old <code>collatz-cllabels-tco</code> with
additional argument passing is only x1.53 slower</p>
<table>
<thead>
<tr>
<th>Form</th>
<th>x fastest</th>
<th>Total runtime</th>
<th># of GCs</th>
<th>Total GC runtime</th>
</tr>
</thead>
<tbody>
<tr>
<td>collatz-cl-loop</td>
<td>fastest</td>
<td>17.733980</td>
<td>19</td>
<td>4.817641</td>
</tr>
<tr>
<td>collatz-while-loop</td>
<td>1.01</td>
<td>17.850171</td>
<td>20</td>
<td>4.977408</td>
</tr>
<tr>
<td>collatz-cllabels-tco-improved</td>
<td>1.28</td>
<td>22.736898</td>
<td>33</td>
<td>7.961263</td>
</tr>
<tr>
<td>collatz-cllabels-tco</td>
<td>1.53</td>
<td>27.146827</td>
<td>47</td>
<td>10.735285</td>
</tr>
<tr>
<td>collatz-stream</td>
<td>18.97</td>
<td>336.443089</td>
<td>961</td>
<td>240.167718</td>
</tr>
</tbody>
</table>
<p>The <code>collatz-stream</code> function remains significantly slower, x19 so.</p>
<p>There is an obvious correlation between runtime and garbage
collection, (19 vs 20 vs 33 vs 47 vs 961), so again possibly tweaking
garbage collection could change things. Although, if we get rid of the
garbage collection runtime differences we end up with:</p>
<table>
<thead>
<tr>
<th>Form</th>
<th>Total runtime w/o GC</th>
<th>x fastest</th>
</tr>
</thead>
<tbody>
<tr>
<td>collatz-while-loop</td>
<td>12.872762999999999</td>
<td>fastest</td>
</tr>
<tr>
<td>collatz-cl-loop</td>
<td>12.916338999999999</td>
<td>1.003</td>
</tr>
<tr>
<td>collatz-cllabels-tco-improved</td>
<td>14.775635000000001</td>
<td>1.148</td>
</tr>
<tr>
<td>collatz-cllabels-tco</td>
<td>16.411541999999997</td>
<td>1.275</td>
</tr>
<tr>
<td>collatz-stream</td>
<td>96.27537099999998</td>
<td>7.479</td>
</tr>
</tbody>
</table>
<p>Now <code>collatz-while-loop</code> is again indeed actually the fastest, but still
just barely more so than <code>collatz-cl-loop</code>; both recursive TCO&rsquo;ing
<code>cl-labels</code> aren&rsquo;t actually too much slower than the loops, though the
improved version is indeed better; and <code>collatz-stream</code> is still quite slow
in comparison. So garbage collection is part of the difference, but
not the only one, especially for the <code>streams</code> method.</p>
<h2 id="escaping--at-least-some--loops-out-of-recursion-and-into-dot-dot-dot-different-recursion--next-time">Escaping (at least some) loops: out of recursion and into&hellip; different recursion (next time)</h2>
<p>This was really an excursus (on an excursus). And, next time — really
— we&rsquo;ll deal with the Y Combinator. I know this one really wasn&rsquo;t a lambda
calculus post at all, but an excursion on our previous excursion into
recursion, here mostly practical considerations for Emacs. But
recursion is crucial for the upcoming discussion of the Y Combinator,
and paradoxes (and their uses). And that&rsquo;ll be interesting for lambda
calculus, and its connections with Lisp.</p>
<p>And, after we&rsquo;re through with Y Combinators and Fibonacci sequences
and barbers who shave everyone who does&rsquo;t shave themselves, and how
these things all tie together, we can get to something I&rsquo;ve been
working on for a while:— given that, connections aside, Lisp isn&rsquo;t
lambda calculus: can we come up with a good implementation of lambda
calculus in Lisp?</p>
<p>(And specifically in Emacs Lisp: which is maybe one of the Lisps least
naturally suited for this: a Scheme or Clojure would be a better
choice really. But it&rsquo;s more fun to try to get it to work in Elisp,
with all of the additional challenges it presents.)</p>
<section class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1" role="doc-endnote">
<p>(I&rsquo;m perhaps very slightly giving the game away; or, at least
providing a clue in the naming of it if you can think of what C-words
&ldquo;ersatz&rdquo; rhymes with.) <a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2" role="doc-endnote">
<p>See <a href="https://www.algoritmarte.com/the-collatz-tree/">The Collatz Tree | Algoritmarte</a>. And the video it&rsquo;s
based on
<a href="https://www.youtube.com/watch?v=LqKpkdRRLZw">https://www.youtube.com/watch?v=LqKpkdRRLZw</a></p>
<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/246l3U2zngk?si=Y5owwBoDC3ivBouI" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
 <a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></li>
<li id="fn:3" role="doc-endnote">
<p>The <a href="https://www.quantamagazine.org/why-mathematicians-still-cant-solve-the-collatz-conjecture-20200922/">Quantamagazine article</a> notes:</p>
<blockquote>
<p>Do not try to solve this math problem.</p>
<p>You will be tempted. This problem is simply stated, easily understood,
and all too inviting. Just pick a number, any number: If the number is
even, cut it in half; if it’s odd, triple it and add 1. Take that new
number and repeat the process, again and again. If you keep this up,
you’ll eventually get stuck in a loop. At least, that’s what we think
will happen.</p>
<p>Take 10 for example: 10 is even, so we cut it in half to get 5. Since
5 is odd, we triple it and add 1. Now we have 16, which is even, so we
halve it to get 8, then halve that to get 4, then halve it again to
get 2, and once more to get 1. Since 1 is odd, we triple it and
add 1. Now we’re back at 4, and we know where this goes: 4 goes to 2
which goes to 1 which goes to 4, and so on. We’re stuck in a loop.</p>
<p>Or try 11: It’s odd, so we triple it and add 1. Now we have 34, which
is even, so we halve it to get 17, triple that and add 1 to get 52,
halve that to get 26 and again to get 13, triple that and add 1 to get
40, halve that to get 20, then 10, then 5, triple that and add 1 to
get 16, and halve that to get 8, then 4, 2 and 1. And we’re stuck in
the loop again.</p>
<p>The infamous Collatz conjecture says that if you start with any
positive integer, you’ll always end up in this loop. And you’ll
probably ignore my warning about trying to solve it: It just seems too
simple and too orderly to resist understanding. In fact, it would be
hard to find a mathematician who hasn’t played around with this
problem.</p>
<p>I couldn’t ignore it when I first learned of it in school. My friends
and I spent days trading thrilling insights that never seemed to get
us any closer to an answer. But the Collatz conjecture is infamous for
a reason: Even though every number that’s ever been tried ends up in
that loop, we’re still not sure it’s always true. Despite all the
attention, it’s still just a conjecture.</p>
<p>&hellip;.</p>
<p>It’s easy to verify that the Collatz conjecture is true for any
particular number: Just compute the orbit until you arrive at 1. But
to see why it’s hard to prove for every number, let’s explore a
slightly simpler function, <code>ℊ</code>.</p>
<p><code>g(n)=</code> <code>{n/2n+1, if n is even</code></p>
<p><code>{n+1, if n is odd</code></p>
<p>We might conjecture that orbits under <code>ℊ</code> always get to 1. I’ll call this
the “Nollatz” conjecture, but we could also call it the <code>n + 1</code>
conjecture. We could explore this by testing more orbits, but knowing
something is true for a bunch of numbers — even 268 of them — isn’t a
proof that it’s true for every number. Fortunately, the Nollatz
conjecture can actually be proved. Here’s how.</p>
<p>First, we know that half of a positive integer is always less than the
integer itself. So if <code>n</code> is even and positive, then <code>ℊ(n) = n/2 &lt; n</code>. In
other words, when an orbit reaches an even number, the next number
will always be smaller.
&hellip;.
This tells us that when an orbit under <code>ℊ</code> reaches an odd number greater
than 1, we’ll always be at a smaller number two steps later. And now
we can outline a proof of the Nollatz conjecture: Anywhere in our
orbit, whether at an even or an odd number, we’ll trend downward. The
only exception is when we hit 1 at the bottom of our descent. But once
we hit 1 we’re trapped the loop, just as we conjectured.
&hellip;
[For <code>f</code>, the Collatz conjencture,] as with <code>ℊ</code>, applying <code>f</code> to an even
number makes it smaller. And as with <code>ℊ</code>, applying <code>f</code> to an odd number
produces an even number, which means we know what happens next: <code>f</code> will
cut the new number in half.</p>
<p>But here’s where our argument falls apart. Unlike our example above,
this number is bigger than <code>n</code>: <code>3n+12 = 3n2 + 12</code>, and <code>3n2 = 1.5n</code>, which
is always bigger than <code>n</code>. The key to our proof of the Nollatz
conjecture was that an odd number must end up smaller two steps later,
but this isn’t true in the Collatz case. Our argument won’t work.</p>
</blockquote>
 <a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></li>
</ol>
</section>
]]></content>
            
                 
                    
                         
                        
                            
                             
                                <category scheme="https://babbagefiles.xyz/categories/emacs" term="emacs" label="emacs" />
                            
                        
                    
                 
                    
                 
                    
                         
                        
                            
                             
                                <category scheme="https://babbagefiles.xyz/tags/recursion" term="recursion" label="recursion" />
                            
                        
                    
                
            
        </entry>
    
        
        <entry>
            <title type="html"><![CDATA[Lambda Calculus and Lisp, part 2 (recursion excursion)]]></title>
            <link href="https://babbagefiles.xyz/lambda-calculus-and-lisp-02-recursion/"/>
            <id>https://babbagefiles.xyz/lambda-calculus-and-lisp-02-recursion/</id>
            
                    <author>
                        <name>Benjamin Slade</name>
                    </author>
            <published>2025-02-20T01:26:00-06:00</published>
            <updated>2025-02-24T12:16:46-06:00</updated>
            
            
            <content type="html"><![CDATA[<p>From the <a href="https://babbagefiles.xyz/lambda-calculus-and-lisp-01/">previous entry in this series</a>, one of the things of note in
discussing the nature of the connections between LISP and (the) lambda
calculus was John McCarthy&rsquo;s concern about recursion and higher-order
functions.</p>
<p>A couple of excerpts from previous quotes from McCarthy on the subject
to set the stage:</p>
<blockquote>
<p>…And so, the way in which to [be able to handle function passing/higher
order functions] was to borrow from Church&rsquo;s Lambda Calculus, to
borrow the lambda definition. Now, having borrowed this notation, one
the myths concerning LISP that people think up or invent for
themselves becomes apparent, and that is that LISP is somehow a
realization of the lambda calculus, or that was the intention. The
truth is that I didn&rsquo;t understand the lambda calculus, really. In
particular, I didn&rsquo;t understand that you really could do conditional
expressions in <strong>recursion</strong> in some sense in the pure lambda calculus.…</p>
<p><strong>[McCarthy 1978a:190<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>]</strong></p>
</blockquote>
<!--quoteend-->
<blockquote>
<p>…Writing <code>eval</code> required inventing a notation representing LISP
functions as LISP data, and such a notation was devised for the
purposes of the paper with no thought that it would be used to express
LISP programs in practice. Logical completeness required that the
notation used to express functions used as functional arguments be
extended to provide for recursive functions, and the <code>LABEL</code> notation
was invented by Nathaniel Rochester for that purpose. D.M.R. Park
pointed out that <code>LABEL</code> was logically unnecessary since the result
could be achieved using only <code>LAMBDA</code> — by a construction analogous to
Church&rsquo;s <em>Y</em>-operator, albeit in a more complicated way.…</p>
<p><strong>[McCarthy 1978a:179<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>]</strong></p>
</blockquote>
<p>Examining Church&rsquo;s Y Combinator will be something we return to
(probably in a number of posts), but I&rsquo;ll defer discussion of it for
the moment.</p>
<p>For now, let&rsquo;s consider recursion in lisps. We&rsquo;ll be talking a lot of
recursion in Emacs Lisp today in fact.</p>
<h2 id="self-reference-self-embedding">Self-reference, self-embedding</h2>
<p><strong>Recursion</strong> is a concept or process depends on a simpler or previous
version of itself. It&rsquo;s ubiquitous, including in the natural world:
Wikipedia <a href="https://en.wikipedia.org/wiki/Recursion#In_biology">notes</a> that &ldquo;Shapes that seem to have been created by
recursive processes sometimes appear in plants and animals, such as in
branching structures in which one large part branches out into two or
more similar smaller parts. One example is Romanesco broccoli.&rdquo;</p>



<figure>
    
        <img src="https://babbagefiles.xyz/ox-hugo/Romanesco_broccoli_%28Brassica_oleracea%29.jpg" alt="Figure 1: Romanesco broccoli (Brassica oleracea), from Wikipedia"/> <figcaption>
                
                <p>
                    <span class="figure-number">Figure 1: </span>Romanesco broccoli (Brassica oleracea), from <a href="Romanesco broccoli (Brassica oleracea)">Wikipedia</a>
                    
                        
                        </p>
                
            </figcaption></figure>

<p>Recursion is a thing I deal with a lot in my day job, as it is a
feature of natural language, especially syntax and semantics. To
provide a quick illustration — though this is not at all how modern
generative syntax is done anymore — consider <a href="https://en.wikipedia.org/wiki/Phrase_structure_grammar">phrase structure grammar</a>
and <a href="https://en.wikipedia.org/wiki/Phrase_structure_rules">phrase structure rules</a> used by <a href="https://en.wikipedia.org/wiki/Noam_Chomsky">Noam Chomsky</a> and his colleagues in
the 1950s.</p>
<p>Sentences (and linguistics objects generally) have formal structure,
and it is part of the productive/creative nature of language that we
might envision this structure as involving abstract structure rules
that can be expanded in different ways (and then have vocabulary
filled in).</p>
<p>A phrase structure rule will generally have the form <code>A → [B C]</code>,
indicating that <code>A</code> may be rewritten or expanded into <code>[B C]</code>. (In the
following, I&rsquo;ll use round brackets <code>()</code>'s to denote optional
constituents.)</p>
<p>So, a subset of these rules for English might include something like
(note that some things have multiple rules that can apply to them):</p>
<div class="highlight"><pre class="chroma"><code class="language-prolog" data-lang="prolog"><span class="mf">1.</span> <span class="nv">S</span> <span class="s">→</span> <span class="nv">NP</span> <span class="nv">VP</span>
<span class="mf">2.</span> <span class="nv">NP</span> <span class="s">→</span> <span class="p">(</span><span class="nv">Det</span><span class="p">)</span> <span class="nv">N</span>
<span class="mf">3.</span> <span class="nv">N</span> <span class="s">→</span> <span class="p">(</span><span class="nv">AdjP</span><span class="p">)</span><span class="o">*</span> <span class="nv">N</span>
<span class="mf">4.</span> <span class="nv">VP</span> <span class="s">→</span> <span class="nv">V</span>
<span class="mf">5.</span> <span class="nv">VP</span> <span class="s">→</span> <span class="nv">V</span> <span class="nv">NP</span> <span class="p">(</span><span class="nv">NP</span><span class="p">)</span>
<span class="mf">6.</span> <span class="nv">VP</span> <span class="s">→</span> <span class="nv">V</span> <span class="nv">CP</span>
<span class="mf">7.</span> <span class="nv">CP</span> <span class="s">→</span> <span class="p">(</span><span class="nv">Comp</span><span class="p">)</span> <span class="nv">S</span>
<span class="p">...</span>
</code></pre></div><div class="src-block-caption">
  <span class="src-block-number">Code Snippet 1:</span>
  a snippet of phrase structure grammar rules for English [Nb.: again, not prolog, but maybe the best fontlocking choice here]
</div>
<p>(Where <code>S</code> is &ldquo;sentence&rdquo;; <code>Det</code> is a determiner (like &ldquo;the&rdquo;, &ldquo;a&rdquo;); <code>NP</code> is a
noun phrase; <code>Nₙ</code> is a noun head; <code>AdjP</code> is an adjective phrase; <code>VP</code> is
a verb phrase; <code>V</code> is a verb head; <code>CP</code> is a complementiser phrase; <code>Comp</code>
is a complementiser (like &ldquo;that&rdquo;).)</p>
<p>So we can rewrite <code>S</code> as <code>NP VP</code> (1) and then rewrite <code>NP VP</code> as <code>Det N VP</code>
(2, choosing an optional <code>Det</code>) and then <code>Det N VP</code> as <code>Det N V</code> (4) and then
insert lexical items of the appropriate category into the &lsquo;heads&rsquo; (the
non-<code>P</code> elements). So we might choose &ldquo;the&rdquo; for <code>Det</code> and &ldquo;cat&rdquo; for <code>N</code> and
&ldquo;purrs&rdquo; for <code>V</code>, and get the sentence &ldquo;the cat purrs&rdquo;.</p>
<p>But note that some of the rules allow for expansion into elements that
contain expansions back into themselves. So rule (1) allows an <code>S</code> to
exapnd into <code>NP VP</code> and rule (6) allows for a <code>VP</code> to expand into <code>V CP</code> and rule
(7) allows for a <code>CP</code> to expand into an <code>S</code>. At which point we can apply
rule (1) again to expand the new <code>S</code> into <code>NP VP</code>, and then repeat this
process as many times as we like:</p>
<div class="highlight"><pre class="chroma"><code class="language-prolog" data-lang="prolog"><span class="nv">S</span>
<span class="nv">NP</span> <span class="nv">VP</span>
<span class="nv">N</span> <span class="nv">VP</span>
<span class="nv">N</span> <span class="nv">V</span> <span class="nv">CP</span>
<span class="nv">N</span> <span class="nv">V</span> <span class="nv">Comp</span> <span class="nv">S</span>
<span class="nv">N</span> <span class="nv">V</span> <span class="nv">Comp</span> <span class="nv">NP</span> <span class="nv">VP</span>
<span class="nv">N</span> <span class="nv">V</span> <span class="nv">Comp</span> <span class="nv">N</span> <span class="nv">VP</span>
<span class="nv">N</span> <span class="nv">V</span> <span class="nv">Comp</span> <span class="nv">N</span> <span class="nv">V</span> <span class="nv">CP</span>
<span class="nv">N</span> <span class="nv">V</span> <span class="nv">Comp</span> <span class="nv">N</span> <span class="nv">V</span> <span class="nv">Comp</span> <span class="nv">S</span>
<span class="nv">N</span> <span class="nv">V</span> <span class="nv">Comp</span> <span class="nv">N</span> <span class="nv">V</span> <span class="nv">Comp</span> <span class="nv">NP</span> <span class="nv">VP</span>
<span class="nv">N</span> <span class="nv">V</span> <span class="nv">Comp</span> <span class="nv">N</span> <span class="nv">V</span> <span class="nv">Comp</span> <span class="nv">N</span> <span class="nv">VP</span>
<span class="nv">N</span> <span class="nv">V</span> <span class="nv">Comp</span> <span class="nv">N</span> <span class="nv">V</span> <span class="nv">Comp</span> <span class="nv">N</span> <span class="nv">V</span> <span class="nv">CP</span>
<span class="nv">N</span> <span class="nv">V</span> <span class="nv">Comp</span> <span class="nv">N</span> <span class="nv">V</span> <span class="nv">Comp</span> <span class="nv">N</span> <span class="nv">V</span> <span class="nv">Comp</span> <span class="nv">S</span>
<span class="nv">N</span> <span class="nv">V</span> <span class="nv">Comp</span> <span class="nv">N</span> <span class="nv">V</span> <span class="nv">Comp</span> <span class="nv">N</span> <span class="nv">V</span> <span class="nv">Comp</span> <span class="nv">NP</span> <span class="nv">VP</span>
<span class="nv">N</span> <span class="nv">V</span> <span class="nv">Comp</span> <span class="nv">N</span> <span class="nv">V</span> <span class="nv">Comp</span> <span class="nv">N</span> <span class="nv">V</span> <span class="nv">Comp</span> <span class="nv">N</span> <span class="nv">VP</span>
<span class="nv">N</span> <span class="nv">V</span> <span class="nv">Comp</span> <span class="nv">N</span> <span class="nv">V</span> <span class="nv">Comp</span> <span class="nv">N</span> <span class="nv">V</span> <span class="nv">Comp</span> <span class="nv">N</span> <span class="nv">V</span> <span class="nv">CP</span>
<span class="nv">N</span> <span class="nv">V</span> <span class="nv">Comp</span> <span class="nv">N</span> <span class="nv">V</span> <span class="nv">Comp</span> <span class="nv">N</span> <span class="nv">V</span> <span class="nv">Comp</span> <span class="nv">N</span> <span class="nv">V</span> <span class="nv">Comp</span> <span class="nv">S</span>
<span class="nv">N</span> <span class="nv">V</span> <span class="nv">Comp</span> <span class="nv">N</span> <span class="nv">V</span> <span class="nv">Comp</span> <span class="nv">N</span> <span class="nv">V</span> <span class="nv">Comp</span> <span class="nv">N</span> <span class="nv">V</span> <span class="nv">Comp</span> <span class="nv">NP</span> <span class="nv">VP</span>
<span class="p">...</span>
</code></pre></div><div class="src-block-caption">
  <span class="src-block-number">Code Snippet 2:</span>
  a recursive English sentence expansion [Nb.: again, not prolog, but maybe the best fontlocking choice here]
</div>
<p>And it&rsquo;s easy to imagine examples of what such a sentence could be
like, e.g., &ldquo;John said that Sita said that Bill said that Mary said
that Ram said that Kim said that&hellip;&quot;. It won&rsquo;t be infinitely long, but
there&rsquo;s no particular theoretical bound on how long it could be
(memory processing and finite human lifespans will impose practical
limits, of course).</p>
<p>On the formal semantics side, things are similar: consider that
logical languages too (which are often used to formalise natural
language semantics) allow for recursion. <a href="https://en.wikipedia.org/wiki/Propositional_calculus">Propositional logic</a>
construction with Boolean operators too have no theoretical upper
limits: we can write <code>(t ↔ (p ∧ (q ∨ (r → (s ∧ ¬¬¬¬¬¬t)))))</code>,<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> and
there&rsquo;s nothing which prevents composing this bit of formalism with
yet another bit, and so on.</p>
<p>And in mathematics and computer science, recursion is often a thing
which suggests itself.</p>
<p>For instance, though there are other ways of calculating it, the
Fibonacci sequence<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>, i.e., a sequence of numbers in which each
element is the sum of the two elements that precede it (e.g. <code>0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144…</code>).</p>
<p>A natural way of writing an equation to calculate these is something
like:</p>
<blockquote>
<ol>
<li>Fib(0) = 0 as base case 1.</li>
<li>Fib(1) = 1 as base case 2.</li>
<li>For all integers <em>n</em> &gt; 1, Fib(<em>n</em>) = Fib(<em>n</em> − 1) + Fib(<em>n</em> − 2).</li>
</ol>
</blockquote>
<p>Rule 3 makes reference to itself. I.e., in order (by this method) to
calculate <code>Fib(6)</code>, you have to calculate <code>Fib(5)</code>, for which you have to
calculate <code>Fib(4))</code>, for which you have to calculate <code>Fib(3)</code>, for which
you have to calculate <code>Fib(2)</code>, which you can then base on rules (1) &amp;
(2): you can add <code>0</code> and <code>1</code> (= <code>Fib(0)</code> and <code>Fib(1))</code> together to get <code>Fib(2)</code>,
and then you can calculate <code>Fib(3)</code> by adding <code>Fib(1)</code> and <code>Fib(2)</code> and so on.</p>
<h2 id="cursed-recursion">Cursed recursion</h2>
<p>In early Lisp(s), despite the concern around recursion, writing
recursive functions was/is not always pragmatically viable, because it
can lead to stack overflows (potential infinities are hard in
practice).</p>
<p><a href="https://en.wikipedia.org/wiki/Scheme_(programming_language)">Scheme</a>, a Lisp dialect originally created at MIT by <a href="https://en.wikipedia.org/wiki/Guy_L._Steele">Guy L. Steele, Jr.</a>
and <a href="https://en.wikipedia.org/wiki/Gerald_Jay_Sussman">Gerald Jay Sussman</a>, was the first Lisp to implement tail call
optimisation, which is a way of making significantly recursive
functions viable, making tail calls similar in memory requirement to
their equivalent loops.</p>
<p>Before talking (a little bit more) about tail recursion, let&rsquo;s look at
concrete examples of a tail recursive function and its loop
equivalent. We&rsquo;ve mentioned Fibonacci numbers already, so let&rsquo;s try to
write functions calculate these (in Emacs Lisp).</p>
<p>Following the mathematical abstraction for the Fibonacci sequence
above, we could write a function like this:</p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="c1">;; -*- lexical-binding: t; -*-</span>
<span class="p">(</span><span class="nb">defun</span> <span class="nv">fib1</span> <span class="p">(</span><span class="nv">n</span> <span class="nv">a</span> <span class="nv">b</span><span class="p">)</span>
  <span class="s">&#34;Calculate the first </span><span class="ss">`n&#39;</span><span class="s"> Fibonacci numbers, recursively.&#34;</span>
  <span class="p">(</span><span class="nb">if</span> <span class="p">(</span><span class="nf">&lt;</span> <span class="nv">n</span> <span class="mi">1</span><span class="p">)</span>
      <span class="nv">a</span>
    <span class="p">(</span><span class="nf">cons</span> <span class="nv">a</span>
          <span class="p">(</span><span class="nv">fib1</span> <span class="p">(</span><span class="nf">1-</span> <span class="nv">n</span><span class="p">)</span> <span class="nv">b</span> <span class="p">(</span><span class="nf">+</span> <span class="nv">a</span> <span class="nv">b</span><span class="p">)))))</span>
</code></pre></div><div class="src-block-caption">
  <span class="src-block-number">Code Snippet 3:</span>
  a first go at a recursive elisp function for fibonacci numbers
</div>
<p>I&rsquo;ve tried to make this as simple as possible, we could make it nicer
(say, with a wrapper function or some some of <code>flet</code>) so that we didn&rsquo;t
have to pass in the initial values. But, keeping it simple (for now):
<code>fib1</code> is a function taking three arguments: <code>n</code>, the quantity of
Fibonacci numbers to return; <code>a</code>, the first number to start with; and <code>b</code>,
the second number to start with.</p>
<p>Following the schema above, we&rsquo;re going to pass <code>0</code> for <code>a</code> and <code>1</code> for
<code>b</code>. Let&rsquo;s get the first ten numbers of the sequence, and pass <code>10</code> for <code>n</code>:</p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="p">(</span><span class="nv">fib1</span> <span class="mi">10</span> <span class="mi">0</span> <span class="mi">1</span><span class="p">)</span>  <span class="c1">; (0 1 1 2 3 5 8 13 21 34 . 55)</span>
</code></pre></div><p>I know, the output is a bit ugly because we&rsquo;re just cons&rsquo;ing the
results and so it&rsquo;s not a proper list, but we&rsquo;re keeping things
simple.</p>
<p>Let&rsquo;s walk through how it works. The function first looks at <code>n</code>, if <code>n</code>
is less than <code>1</code>, it returns <code>a</code> (whatever it is). If <code>n</code> isn&rsquo;t less than <code>1</code>,
we return the <code>cons</code> of <code>a</code> with the result of calling <code>fib1</code> itself on &ldquo;<code>n</code>
minus 1&rdquo; <code>b</code> and &ldquo;<code>a</code> plus <code>b</code>&rdquo;.</p>
<p>So if we start with <code>n=3</code>, <code>a=0</code>, <code>b=1</code>, that is, evaluate <code>(fib1 3 0 1)</code>, the
function would say, well, 3 isn&rsquo;t less than 1, so I&rsquo;m going to create
a <code>cons</code> with <code>0</code> and the result of calling <code>(fib1 2 1 1)</code> (2 = &ldquo;<code>n</code> minus 1&rdquo;,
because <code>n</code> is currently 3; <code>1</code> because <code>b=1</code>; and <code>1</code> because <code>a + b</code> = <code>0 + 1</code> =
<code>1</code>).</p>
<p>So at this point we have a <code>cons</code> that looks like this:</p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="p">(</span><span class="mi">0</span> <span class="o">.</span> <span class="p">(</span><span class="nv">fib1</span> <span class="mi">2</span> <span class="mi">1</span> <span class="mi">1</span><span class="p">))</span>  <span class="c1">;; [= (cons 0 (fib1 2 1 1))]</span>
</code></pre></div><p>When we evaluate <code>(fib1 2 1 1)</code>, <code>n</code> is still not less than <code>1</code>, so we&rsquo;re
going to <code>cons</code> the current value of <code>a</code> (which is <code>1</code>) with another call to
<code>fib1</code>: <code>(fib1 1 1 2)</code> (1 = &ldquo;<code>n</code> minus 1&rdquo;, because <code>n</code> is currently 2; <code>1</code>
because <code>b=1</code>; and <code>2</code> because <code>a + b</code> = <code>1 + 1</code> = <code>2</code>).</p>
<p>So now we have:</p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="p">(</span><span class="mi">0</span> <span class="mi">1</span> <span class="o">.</span> <span class="p">(</span><span class="nv">fib1</span> <span class="mi">1</span> <span class="mi">1</span> <span class="mi">2</span><span class="p">))</span>  <span class="c1">;; [= (cons 0 (cons 1 (fib1 1 1 2)))]</span>
</code></pre></div><p>Now we have to evaluate <code>(fib1 1 1 2)</code>. <code>n</code> is still not less than 1; so
we create another <code>cons</code> of <code>1</code> (as <code>a</code> is currently <code>1</code>) with yet another
call of <code>fib1</code>: <code>(fib1 0 2 3)</code> (0 = &ldquo;<code>n</code> minus 1&rdquo;, because <code>n</code> is currently 1; <code>2</code>
because <code>b=2</code>; and <code>3</code> because <code>a + b</code> = <code>1 + 2</code> = <code>3</code>). And so now:</p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="p">(</span><span class="mi">0</span> <span class="mi">1</span> <span class="mi">1</span> <span class="o">.</span> <span class="p">(</span><span class="nv">fib1</span> <span class="mi">0</span> <span class="mi">2</span> <span class="mi">3</span><span class="p">))</span>  <span class="c1">;; [= (cons 0 (cons 1 (cons 1 (fib1 0 2 3))))]</span>
</code></pre></div><p>And, finally, evaluating <code>(fib1 0 2 3)</code>, now <code>n</code> is less than one, so we
take the first branch of the conditional and just return <code>a</code>, which is
<code>2</code>. So the result of starting with <code>(fib1 3 0 1)</code> is:</p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="p">(</span><span class="mi">0</span> <span class="mi">1</span> <span class="mi">1</span> <span class="o">.</span> <span class="mi">2</span><span class="p">)</span>  <span class="c1">;; [= (cons 0 (cons 1 (cons 1 2)))]</span>
</code></pre></div><p>And you can try this with other values of <code>n</code>, e.g., try evaluating
<code>(fib1 100 0 1)</code> to get the first 100 members of the sequence.<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup></p>
<p>But, at least for me on Emacs 30.0.93, 529 is the limit. If we try
<code>(fib1 520 0 1)</code>, the debugger pops up with a 1622 line long error,
which begins:</p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="nv">Debugger</span> <span class="nv">entered--Lisp</span> <span class="nv">error:</span> <span class="p">(</span><span class="nv">excessive-lisp-nesting</span> <span class="mi">1622</span><span class="p">)</span>
  <span class="nv">cl-print--cons-tail</span><span class="p">(</span><span class="nv">excessive-lisp-nesting</span> <span class="p">(</span><span class="mi">1601</span><span class="p">)</span> <span class="err">#</span><span class="nv">&lt;buffer</span>  <span class="vg">*temp*</span><span class="nf">&gt;</span><span class="p">)</span>
  <span class="err">#</span><span class="nv">f</span><span class="p">(</span><span class="nv">compiled-function</span> <span class="p">(</span><span class="nv">object</span> <span class="nv">stream</span><span class="p">)</span> <span class="err">#</span><span class="nv">&lt;bytecode</span> <span class="nv">0x491d55561699a09&gt;</span><span class="p">)(</span><span class="err">#</span><span class="mi">0</span> <span class="err">#</span><span class="nv">&lt;buffer</span>  <span class="vg">*temp*</span><span class="nf">&gt;</span><span class="p">)</span>
  <span class="nf">apply</span><span class="p">(</span><span class="err">#</span><span class="nv">f</span><span class="p">(</span><span class="nv">compiled-function</span> <span class="p">(</span><span class="nv">object</span> <span class="nv">stream</span><span class="p">)</span> <span class="err">#</span><span class="nv">&lt;bytecode</span> <span class="nv">0x491d55561699a09&gt;</span><span class="p">)</span> <span class="p">(</span><span class="err">#</span><span class="mi">0</span> <span class="err">#</span><span class="nv">&lt;buffer</span>  <span class="vg">*temp*</span><span class="nf">&gt;</span><span class="p">))</span>
  <span class="err">#</span><span class="nv">f</span><span class="p">(</span><span class="nv">compiled-function</span> <span class="p">(</span><span class="kp">&amp;rest</span> <span class="nv">args</span><span class="p">)</span> <span class="err">#</span><span class="nv">&lt;bytecode</span> <span class="nv">0x1c31d892b8046a8b&gt;</span><span class="p">)()</span>
  <span class="err">#</span><span class="nv">f</span><span class="p">(</span><span class="nv">compiled-function</span> <span class="p">(</span><span class="nv">cl--cnm</span> <span class="nv">object</span> <span class="nv">stream</span><span class="p">)</span> <span class="err">#</span><span class="nv">&lt;bytecode</span> <span class="nv">0x7c361f66f109692&gt;</span><span class="p">)(</span><span class="err">#</span><span class="nv">f</span><span class="p">(</span><span class="nv">compiled-function</span> <span class="p">(</span><span class="kp">&amp;rest</span> <span class="nv">args</span><span class="p">)</span> <span class="err">#</span><span class="nv">&lt;bytecode</span> <span class="nv">0x1c31d892b8046a8b&gt;</span><span class="p">)</span> <span class="err">#</span><span class="mi">0</span> <span class="err">#</span><span class="nv">&lt;buffer</span>  <span class="vg">*temp*</span><span class="nf">&gt;</span><span class="p">)</span>
  <span class="nf">apply</span><span class="p">(</span><span class="err">#</span><span class="nv">f</span><span class="p">(</span><span class="nv">compiled-function</span> <span class="p">(</span><span class="nv">cl--cnm</span> <span class="nv">object</span> <span class="nv">stream</span><span class="p">)</span> <span class="err">#</span><span class="nv">&lt;bytecode</span> <span class="nv">0x7c361f66f109692&gt;</span><span class="p">)</span> <span class="err">#</span><span class="nv">f</span><span class="p">(</span><span class="nv">compiled-function</span> <span class="p">(</span><span class="kp">&amp;rest</span> <span class="nv">args</span><span class="p">)</span> <span class="err">#</span><span class="nv">&lt;bytecode</span> <span class="nv">0x1c31d892b8046a8b&gt;</span><span class="p">)</span> <span class="p">(</span><span class="err">#</span><span class="mi">0</span> <span class="err">#</span><span class="nv">&lt;buffer</span>  <span class="vg">*temp*</span><span class="nf">&gt;</span><span class="p">))</span>
  <span class="err">#</span><span class="nv">f</span><span class="p">(</span><span class="nv">compiled-function</span> <span class="p">(</span><span class="nv">object</span> <span class="nv">stream</span><span class="p">)</span> <span class="err">#</span><span class="nv">&lt;bytecode</span> <span class="nv">0x1f277a9a6dc403fa&gt;</span><span class="p">)(</span><span class="err">#</span><span class="mi">0</span> <span class="err">#</span><span class="nv">&lt;buffer</span>  <span class="vg">*temp*</span><span class="nf">&gt;</span><span class="p">)</span>
  <span class="nf">apply</span><span class="p">(</span><span class="err">#</span><span class="nv">f</span><span class="p">(</span><span class="nv">compiled-function</span> <span class="p">(</span><span class="nv">object</span> <span class="nv">stream</span><span class="p">)</span> <span class="err">#</span><span class="nv">&lt;bytecode</span> <span class="nv">0x1f277a9a6dc403fa&gt;</span><span class="p">)</span> <span class="err">#</span><span class="mi">0</span> <span class="err">#</span><span class="nv">&lt;buffer</span>  <span class="vg">*temp*</span><span class="nf">&gt;</span><span class="p">)</span>
  <span class="nv">cl-print-object</span><span class="p">(</span><span class="err">#</span><span class="mi">0</span> <span class="err">#</span><span class="nv">&lt;buffer</span>  <span class="vg">*temp*</span><span class="nf">&gt;</span><span class="p">)</span>
  <span class="nv">cl-prin1</span><span class="p">(</span><span class="err">#</span><span class="mi">0</span> <span class="err">#</span><span class="nv">&lt;buffer</span>  <span class="vg">*temp*</span><span class="nf">&gt;</span><span class="p">)</span>
  <span class="nv">backtrace--print</span><span class="p">(</span><span class="err">#</span><span class="mi">0</span> <span class="err">#</span><span class="nv">&lt;buffer</span>  <span class="vg">*temp*</span><span class="nf">&gt;</span><span class="p">)</span>
  <span class="nv">cl-print-to-string-with-limit</span><span class="p">(</span><span class="nv">backtrace--print</span> <span class="err">#</span><span class="mi">0</span> <span class="mi">5000</span><span class="p">)</span>
  <span class="nv">backtrace--print-to-string</span><span class="p">(</span><span class="err">#</span><span class="mi">0</span> <span class="no">nil</span><span class="p">)</span>
  <span class="nv">backtrace-print-to-string</span><span class="p">(</span><span class="err">#</span><span class="mi">0</span><span class="p">)</span>
  <span class="nv">debugger--insert-header</span><span class="p">((</span><span class="ne">error</span> <span class="err">#</span><span class="mi">0</span> <span class="nb">:backtrace-base</span> <span class="nv">eval-expression--debug</span><span class="p">))</span>
  <span class="err">#</span><span class="nv">f</span><span class="p">(</span><span class="nv">compiled-function</span> <span class="p">()</span> <span class="err">#</span><span class="nv">&lt;bytecode</span> <span class="nv">0x299e53d67d1ac62&gt;</span><span class="p">)()</span>
  <span class="nv">backtrace-print</span><span class="p">()</span>
  <span class="nv">debugger-setup-buffer</span><span class="p">((</span><span class="ne">error</span> <span class="err">#</span><span class="mi">0</span> <span class="nb">:backtrace-base</span> <span class="nv">eval-expression--debug</span><span class="p">))</span>
  <span class="nv">debug</span><span class="p">(</span><span class="ne">error</span> <span class="err">#</span><span class="mi">0</span> <span class="nb">:backtrace-base</span> <span class="nv">eval-expression--debug</span><span class="p">)</span>
  <span class="nv">eval-expression--debug</span><span class="p">(</span><span class="err">#</span><span class="mi">0</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">if</span> <span class="p">(</span><span class="nf">&lt;</span> <span class="nv">n</span> <span class="mi">1</span><span class="p">)</span> <span class="nv">a</span> <span class="p">(</span><span class="nf">cons</span> <span class="nv">a</span> <span class="p">(</span><span class="nv">fib1</span> <span class="p">(</span><span class="nf">1-</span> <span class="nv">n</span><span class="p">)</span> <span class="nv">b</span> <span class="p">(</span><span class="nf">+</span> <span class="nv">a</span> <span class="nv">b</span><span class="p">))))</span>
  <span class="nv">fib1</span><span class="p">(</span><span class="mi">0</span> <span class="mi">259396630450514843945535792456880074043523940756078363514486570322782139633750401577338505233670220572153381665</span> <span class="mi">419712564636128966418863068957011388899128076671547993021605479585858227224221424221791102364954108601240491394</span><span class="p">)</span>
  <span class="p">(</span><span class="nf">cons</span> <span class="nv">a</span> <span class="p">(</span><span class="nv">fib1</span> <span class="p">(</span><span class="nf">1-</span> <span class="nv">n</span><span class="p">)</span> <span class="nv">b</span> <span class="p">(</span><span class="nf">+</span> <span class="nv">a</span> <span class="nv">b</span><span class="p">)))</span>
  <span class="p">(</span><span class="nb">if</span> <span class="p">(</span><span class="nf">&lt;</span> <span class="nv">n</span> <span class="mi">1</span><span class="p">)</span> <span class="nv">a</span> <span class="p">(</span><span class="nf">cons</span> <span class="nv">a</span> <span class="p">(</span><span class="nv">fib1</span> <span class="p">(</span><span class="nf">1-</span> <span class="nv">n</span><span class="p">)</span> <span class="nv">b</span> <span class="p">(</span><span class="nf">+</span> <span class="nv">a</span> <span class="nv">b</span><span class="p">))))</span>
  <span class="nv">fib1</span><span class="p">(</span><span class="mi">1</span> <span class="mi">160315934185614122473327276500131314855604135915469629507118909263076087590471022644452597131283888029087109729</span> <span class="mi">259396630450514843945535792456880074043523940756078363514486570322782139633750401577338505233670220572153381665</span><span class="p">)</span>
  <span class="p">(</span><span class="nf">cons</span> <span class="nv">a</span> <span class="p">(</span><span class="nv">fib1</span> <span class="p">(</span><span class="nf">1-</span> <span class="nv">n</span><span class="p">)</span> <span class="nv">b</span> <span class="p">(</span><span class="nf">+</span> <span class="nv">a</span> <span class="nv">b</span><span class="p">)))</span>
  <span class="p">(</span><span class="nb">if</span> <span class="p">(</span><span class="nf">&lt;</span> <span class="nv">n</span> <span class="mi">1</span><span class="p">)</span> <span class="nv">a</span> <span class="p">(</span><span class="nf">cons</span> <span class="nv">a</span> <span class="p">(</span><span class="nv">fib1</span> <span class="p">(</span><span class="nf">1-</span> <span class="nv">n</span><span class="p">)</span> <span class="nv">b</span> <span class="p">(</span><span class="nf">+</span> <span class="nv">a</span> <span class="nv">b</span><span class="p">))))</span>
  <span class="nv">fib1</span><span class="p">(</span><span class="mi">2</span> <span class="mi">99080696264900721472208515956748759187919804840608734007367661059706052043279378932885908102386332543066271936</span> <span class="mi">160315934185614122473327276500131314855604135915469629507118909263076087590471022644452597131283888029087109729</span><span class="p">)</span>
<span class="o">....</span>
</code></pre></div><div class="src-block-caption">
  <span class="src-block-number">Code Snippet 4:</span>
  beginning of excessive-lisp-nesting error for our fib1 function
</div>
<p>Because we&rsquo;ve built up a long, deeply-embedded list of conses and
Emacs has a limit of how deep it&rsquo;s willing/able to go (you can see
above that we&rsquo;ve almost made it to the end, just needing to calculate
<code>fib1(0)</code>, when Emacs decides it&rsquo;s had enough).</p>
<p>In Scheme and elsewhere, self-recursive calls at the ends (&ldquo;tails&rdquo;) of
functions can be optimised to avoid these sorts of stack overflows
(<code>excessive-lisp-nesting</code>).<sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup> Tail-call optimisation lets
procedure calls in tail positions be treated a specialised GOTO
statements, which can be efficiently processed:</p>
<blockquote>
<p>…only in cases where structures are explicitly declared to be
dynamically referenced should the compiler be forced to leave them on
the stack in an otherwise tail-recursive situation. In general,
procedure calls may be usefully thought of as GOTO statements which
also pass parameters, and can be uniformly encoded as JUMP
instructions. This is a simple, universal technique, to be contrasted
with […] more powerful recursion-removal techniques…</p>
<p><strong>[Steele 1977:155<sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup>]</strong></p>
</blockquote>
<p>But our <code>fib1</code> function doesn&rsquo;t do this, and we end up flooded the stack
with too many conses.</p>
<h2 id="back-to-loops">Back to loops</h2>
<p>Recursive functions are perhaps most idiomatic in Scheme (among lisps,
I mean). Some implementations of Common Lisp can do tail-call
optimisation, but loops are perhaps more common, and certainly in
Emacs Lisp (for reasons you can see above), loops are usually what are
used. And so we can write a new Fibonacci function with a loop. It
won&rsquo;t be nearly as pretty, but it&rsquo;ll work better.</p>
<p>Here&rsquo;s one possible implementation:</p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="c1">;; -*- lexical-binding: t; -*-</span>
<span class="p">(</span><span class="nb">defun</span> <span class="nv">fib2</span> <span class="p">(</span><span class="nv">n</span> <span class="nv">a</span> <span class="nv">b</span><span class="p">)</span>
  <span class="s">&#34;Calculate the first </span><span class="ss">`n&#39;</span><span class="s"> Fibonacci numbers,
</span><span class="s">in a loop.&#34;</span>
  <span class="p">(</span><span class="nb">let</span> <span class="p">((</span><span class="nv">result</span> <span class="no">nil</span><span class="p">))</span>
    <span class="p">(</span><span class="nb">dotimes</span> <span class="p">(</span><span class="nv">c</span> <span class="nv">n</span><span class="p">)</span>
      <span class="p">(</span><span class="nb">setq</span> <span class="nv">result</span> <span class="p">(</span><span class="nf">cons</span> <span class="nv">a</span> <span class="nv">result</span><span class="p">))</span>
      <span class="p">(</span><span class="nb">setq</span> <span class="nv">tempa</span> <span class="nv">b</span><span class="p">)</span>
      <span class="p">(</span><span class="nb">setq</span> <span class="nv">b</span> <span class="p">(</span><span class="nf">+</span> <span class="nv">a</span> <span class="nv">b</span><span class="p">))</span>
      <span class="p">(</span><span class="nb">setq</span> <span class="nv">a</span> <span class="nv">tempa</span><span class="p">))</span>
    <span class="p">(</span><span class="nf">nreverse</span> <span class="nv">result</span><span class="p">)))</span>

<span class="p">(</span><span class="nv">fib2</span> <span class="mi">10</span> <span class="mi">0</span> <span class="mi">1</span><span class="p">)</span> <span class="c1">; (0 1 1 2 3 5 8 13 21 34)</span>

<span class="p">(</span><span class="nb">setq</span> <span class="nv">bigfib-50000</span> <span class="p">(</span><span class="nv">fib2</span> <span class="mi">50000</span> <span class="mi">0</span> <span class="mi">1</span><span class="p">))</span> <span class="c1">; this will work - we can get 50,000 numbers</span>
</code></pre></div><div class="src-block-caption">
  <span class="src-block-number">Code Snippet 5:</span>
  a second go at a fibonacci function, with looping
</div>
<p>The result is prettier at least: a proper rather than an improper list
(because we started by <code>cons</code>'ing onto an empty list). Our <code>fib2</code> function
itself isn&rsquo;t as mathematically pleasing as our <code>fib1</code> function, we end
up with a lot of <code>setq</code>'s (the <code>nreverse</code> at the end reverses our list,
because the way we build up our list is by <code>cons</code>'ing the first results
first, so they end up at the end until we flip them with
<code>nreverse</code>). But it works well. If you try to <code>(fib2 100000 0 1)</code>, it&rsquo;ll
fail, but not because of stack overflow, just because we end up with
numbers that are too big for Emacs. But you can certain get the over
50,000 members of the Fibonacci sequence, which is much better than
<code>fib1</code>'s limit of 529.</p>
<p>And <code>dotimes</code> is just one loop procedure available. (See <a href="https://www.gnu.org/software/emacs/manual/html_node/cl/Loop-Examples.html"><code>cl-loop</code></a> for a more
powerful one.)</p>
<h2 id="optimal-tail-with-emacs">Optimal Tail with Emacs</h2>
<p>Ok, so, practically, we should probably generally prefer loops over
tail-recursive functions in Emacs. But, what if we just like the latter
more?<sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup> Are there any other possibilities?</p>
<p><a href="https://mastodon.social/@wilfredh">Wilfred Hughes</a> has an emacs package <a href="https://github.com/Wilfred/tco.el"><code>tco.el</code></a> which implements a
special macro for writing tail-recursive functions.<sup id="fnref:8"><a href="#fn:8" class="footnote-ref" role="doc-noteref">8</a></sup> It works by
replacing each self-call with a <a href="https://en.wikipedia.org/wiki/Thunk">thunk</a>, and wrapping the function body
in a loop that repeatedly evaluates the thunk. Thus a
function <code>foo</code> defined with the <code>defun-tco</code> macro:</p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="p">(</span><span class="nv">defun-tco</span> <span class="nv">foo</span> <span class="p">(</span><span class="o">...</span><span class="p">)</span>
  <span class="p">(</span><span class="o">...</span><span class="p">)</span>
  <span class="p">(</span><span class="nv">foo</span> <span class="p">(</span><span class="o">...</span><span class="p">)))</span>
</code></pre></div><p>would be re-written as:</p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="p">(</span><span class="nb">defun</span> <span class="nv">foo</span> <span class="p">(</span><span class="o">...</span><span class="p">)</span>
   <span class="p">(</span><span class="nb">flet</span> <span class="p">(</span><span class="nv">foo-thunk</span> <span class="p">(</span><span class="o">...</span><span class="p">)</span>
               <span class="p">(</span><span class="o">...</span><span class="p">)</span>
               <span class="p">(</span><span class="nb">lambda</span> <span class="p">()</span> <span class="p">(</span><span class="nv">foo-thunk</span> <span class="p">(</span><span class="o">...</span><span class="p">))))</span>
     <span class="p">(</span><span class="nb">let</span> <span class="p">((</span><span class="nv">result</span> <span class="p">(</span><span class="nf">apply</span> <span class="nv">foo-thunk</span> <span class="p">(</span><span class="o">...</span><span class="p">))))</span>
       <span class="p">(</span><span class="nb">while</span> <span class="p">(</span><span class="nf">functionp</span> <span class="nv">result</span><span class="p">)</span>
         <span class="p">(</span><span class="nb">setq</span> <span class="nv">result</span> <span class="p">(</span><span class="nf">funcall</span> <span class="nv">result</span><span class="p">)))</span>
       <span class="nv">result</span><span class="p">)))</span>
</code></pre></div><p>And this delays evaluation in such a way as to avoid stack
overflows. Unfortunately, at least currently for me (Emacs 30.0.93
again), tco.el seems to <a href="https://github.com/Wilfred/tco.el/issues/10">have some issues</a>.</p>
<p>In Emacs 28.1, <code>cl-labels</code> (one of the ways of sort of doing <code>let</code>'s for
functions) <a href="https://github.com/emacs-mirror/emacs/commit/29c7f8c915c3889dfd5b25878aa0692f826cd38f">gained some limited tail-call optimisation</a> (as did
<code>named-let</code>, which uses <code>cl-labels</code>).</p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="c1">;; -*- lexical-binding: t; -*-</span>
<span class="p">(</span><span class="nb">defun</span> <span class="nv">fib3</span> <span class="p">(</span><span class="nv">n</span><span class="p">)</span>
  <span class="s">&#34;Calculate the first </span><span class="ss">`n&#39;</span><span class="s"> Fibonacci numbers,
</span><span class="s">recursively, with limited tail-call optimisation
</span><span class="s">through </span><span class="ss">`cl-labels&#39;</span><span class="s">?!&#34;</span>
  <span class="p">(</span><span class="nb">cl-labels</span> <span class="p">((</span><span class="nv">fib*</span> <span class="p">(</span><span class="nv">n</span> <span class="nv">a</span> <span class="nv">b</span><span class="p">)</span>
                <span class="p">(</span><span class="nb">if</span> <span class="p">(</span><span class="nf">&lt;</span> <span class="nv">n</span> <span class="mi">1</span><span class="p">)</span>
                    <span class="nv">a</span>
                  <span class="p">(</span><span class="nf">cons</span> <span class="nv">a</span>
                        <span class="p">(</span><span class="nv">fib*</span> <span class="p">(</span><span class="nf">1-</span> <span class="nv">n</span><span class="p">)</span>
                              <span class="nv">b</span>
                              <span class="p">(</span><span class="nf">+</span> <span class="nv">a</span> <span class="nv">b</span><span class="p">))))))</span>
    <span class="p">(</span><span class="nv">fib*</span> <span class="nv">n</span> <span class="mi">0</span> <span class="mi">1</span><span class="p">)))</span>

<span class="p">(</span><span class="nb">setq</span> <span class="nv">bigfib3</span> <span class="p">(</span><span class="nv">fib3</span> <span class="mi">397</span><span class="p">))</span> <span class="c1">; 396 highest that works</span>
</code></pre></div><div class="src-block-caption">
  <span class="src-block-number">Code Snippet 6:</span>
  a third go at a fibonacci function, with cl-labels
</div>
<p>At least the way I&rsquo;ve written it, it seems to suffer an overflow even
sooner (at 397 rather than 529 as for our <code>fib1</code>), because it has to
come back and do the <code>cons</code> after the tail-call — so <code>fib*</code> isn&rsquo;t actually
in the tail. (We can fix this in at least one way, which we&rsquo;ll do in <code>fib5</code>.)</p>
<p>We could try to write an accumulator as a hack, where we try to do
ours conses one at a time and pass along the results, but this fares no
better than our <code>fib1</code>:</p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="c1">;; -*- lexical-binding: t; -*-</span>
<span class="p">(</span><span class="nb">defun</span> <span class="nv">fib4</span> <span class="p">(</span><span class="nv">n</span> <span class="nv">a</span> <span class="nv">b</span> <span class="nv">accum</span><span class="p">)</span>
  <span class="s">&#34;Calculate the first </span><span class="ss">`n&#39;</span><span class="s"> Fibonacci numbers, recursively,
</span><span class="s">but collect conses as we go and keep track of the length of
</span><span class="s">the </span><span class="ss">`accum&#39;</span><span class="s"> cp. against </span><span class="ss">`n&#39;</span><span class="s">.&#34;</span>
  <span class="p">(</span><span class="nb">let*</span> <span class="p">((</span><span class="nv">accum</span> <span class="p">(</span><span class="nf">cons</span> <span class="nv">a</span> <span class="nv">accum</span><span class="p">))</span>
         <span class="p">(</span><span class="nv">accum-lng</span> <span class="p">(</span><span class="nf">length</span> <span class="nv">accum</span><span class="p">)))</span>
    <span class="p">(</span><span class="nb">if</span> <span class="p">(</span><span class="nf">&lt;</span> <span class="nv">n</span> <span class="nv">accum-lng</span><span class="p">)</span>
        <span class="p">(</span><span class="nf">nreverse</span> <span class="nv">accum</span><span class="p">)</span>
      <span class="p">(</span><span class="nv">fib4</span> <span class="nv">n</span> <span class="nv">b</span> <span class="p">(</span><span class="nf">+</span> <span class="nv">b</span> <span class="nv">a</span><span class="p">)</span> <span class="nv">accum</span><span class="p">))))</span>

<span class="p">(</span><span class="nb">setq</span> <span class="nv">bigfib4-529</span> <span class="p">(</span><span class="nv">fib4</span> <span class="mi">529</span> <span class="mi">0</span> <span class="mi">1</span> <span class="no">nil</span><span class="p">))</span> <span class="c1">; last good</span>
<span class="p">(</span><span class="nb">setq</span> <span class="nv">bigfib4-530</span> <span class="p">(</span><span class="nv">fib4</span> <span class="mi">530</span> <span class="mi">0</span> <span class="mi">1</span> <span class="no">nil</span><span class="p">))</span> <span class="c1">; overflows</span>
</code></pre></div><div class="src-block-caption">
  <span class="src-block-number">Code Snippet 7:</span>
  a fourth go at a fibonacci function, with an accumulator
</div>
<p>If we combine <code>cl-labels</code> and the accumulator trick, however, we do seem
to be able to escape stack overflows, because now we&rsquo;ve got <code>fib*</code>
properly in the tail:</p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="c1">;; -*- lexical-binding: t; -*-</span>
<span class="p">(</span><span class="nb">defun</span> <span class="nv">fib5</span> <span class="p">(</span><span class="nv">n</span><span class="p">)</span>
  <span class="s">&#34;Calculate the first </span><span class="ss">`n&#39;</span><span class="s"> Fibonacci numbers, recursively,
</span><span class="s">using both cl-labels and the accumulator trick.&#34;</span>
  <span class="p">(</span><span class="nb">cl-labels</span> <span class="p">((</span><span class="nv">fib*</span> <span class="p">(</span><span class="nv">a</span> <span class="nv">b</span> <span class="nv">accum</span><span class="p">)</span>
                   <span class="p">(</span><span class="nb">let*</span> <span class="p">((</span><span class="nv">accum</span> <span class="p">(</span><span class="nf">cons</span> <span class="nv">a</span> <span class="nv">accum</span><span class="p">))</span>
                         <span class="p">(</span><span class="nv">accum-lng</span> <span class="p">(</span><span class="nf">length</span> <span class="nv">accum</span><span class="p">)))</span>
                     <span class="p">(</span><span class="nb">if</span> <span class="p">(</span><span class="nf">&lt;</span> <span class="nv">n</span> <span class="nv">accum-lng</span><span class="p">)</span>
                         <span class="p">(</span><span class="nf">nreverse</span> <span class="nv">accum</span><span class="p">)</span>
                         <span class="p">(</span><span class="nv">fib*</span> <span class="nv">b</span> <span class="p">(</span><span class="nf">+</span> <span class="nv">b</span> <span class="nv">a</span><span class="p">)</span> <span class="nv">accum</span><span class="p">)))))</span>
            <span class="p">(</span><span class="nv">fib*</span> <span class="mi">0</span> <span class="mi">1</span> <span class="no">nil</span><span class="p">)))</span>

<span class="p">(</span><span class="nb">setq</span> <span class="nv">bigfib5-10000</span> <span class="p">(</span><span class="nv">fib5</span> <span class="mi">10000</span><span class="p">))</span> <span class="c1">; ok</span>
<span class="p">(</span><span class="nb">setq</span> <span class="nv">bigfib5-50000</span> <span class="p">(</span><span class="nv">fib5</span> <span class="mi">50000</span><span class="p">))</span> <span class="c1">; very slow, but ok</span>
</code></pre></div><div class="src-block-caption">
  <span class="src-block-number">Code Snippet 8:</span>
  a fifth go at a fibonacci function, with cl-labels and an accumulator
</div>
<p>Now we&rsquo;re back in the realms of what our <code>fib2</code> non-recursive loop-style
function could do. Although <code>(setq bigfib5-50000 (fib5 50000))</code>
calculates very slowly (worse than our looping <code>fib2</code>), so that&rsquo;s not ideal.</p>
<h2 id="stream-of-conses-ness">Stream of Conses-ness</h2>
<p>But here&rsquo;s another possibility: <a href="https://nicolas.petton.fr">Nicholas Pettton</a>&lsquo;s <a href="https://elpa.gnu.org/packages/stream.html"><code>stream</code></a> package
for emacs, where &ldquo;streams&rdquo; are delayed evaluations of <code>cons</code> cells.</p>
<div class="highlight"><pre class="chroma"><code class="language-elisp" data-lang="elisp"><span class="c1">;; -*- lexical-binding: t; -*-</span>
<span class="p">(</span><span class="nb">defun</span> <span class="nv">fib6</span> <span class="p">(</span><span class="nv">n</span><span class="p">)</span>
  <span class="s">&#34;Return a list of the first </span><span class="ss">`n&#39;</span><span class="s"> Fibonacci numbers,
</span><span class="s">implemented as stream of (delayed evaluation) conses.&#34;</span>
  <span class="p">(</span><span class="nb">cl-labels</span> <span class="p">((</span><span class="nv">fibonacci-populate</span> <span class="p">(</span><span class="nv">a</span> <span class="nv">b</span><span class="p">)</span>
                <span class="p">(</span><span class="nv">stream-cons</span> <span class="nv">a</span> <span class="p">(</span><span class="nv">fibonacci-populate</span> <span class="nv">b</span> <span class="p">(</span><span class="nf">+</span> <span class="nv">a</span> <span class="nv">b</span><span class="p">)))))</span>
    <span class="p">(</span><span class="nb">let</span> <span class="p">((</span><span class="nv">fibonacci-stream</span>
           <span class="p">(</span><span class="nv">fibonacci-populate</span> <span class="mi">0</span> <span class="mi">1</span><span class="p">))</span>
          <span class="p">(</span><span class="nv">fibs</span> <span class="no">nil</span><span class="p">))</span>
      <span class="p">(</span><span class="nb">dotimes</span> <span class="p">(</span><span class="nv">c</span> <span class="nv">n</span><span class="p">)</span>
        <span class="p">(</span><span class="nb">setq</span> <span class="nv">fibs</span> <span class="p">(</span><span class="nf">cons</span> <span class="p">(</span><span class="nv">stream-pop</span> <span class="nv">fibonacci-stream</span><span class="p">)</span> <span class="nv">fibs</span><span class="p">)))</span>
      <span class="p">(</span><span class="nf">nreverse</span> <span class="nv">fibs</span><span class="p">))))</span>

<span class="p">(</span><span class="nb">setq</span> <span class="nv">fib6-10k</span> <span class="p">(</span><span class="nv">fib6</span> <span class="mi">10000</span><span class="p">))</span> <span class="c1">; ok</span>
<span class="p">(</span><span class="nb">setq</span> <span class="nv">fib6-50k</span> <span class="p">(</span><span class="nv">fib6</span> <span class="mi">50000</span><span class="p">))</span> <span class="c1">; little slow, but works</span>
<span class="p">(</span><span class="nb">setq</span> <span class="nv">fib6-100k</span> <span class="p">(</span><span class="nv">fib6</span> <span class="mi">100000</span><span class="p">))</span> <span class="c1">; little slow &amp; overflow error</span>
</code></pre></div><div class="src-block-caption">
  <span class="src-block-number">Code Snippet 9:</span>
  a sixth go at a fibonacci function, with delayed evaluation conses
</div>
<p>This works well. <code>(fib6 50000)</code> still turns out to run a bit slower than
our <code>(fib2 50000)</code>, so loops are still probably more efficient, but
streams are pretty interesting. They can can used to represent
infinite sequences. So here, above, <code>fibonacci-stream</code> (set by
<code>(fibonacci-populate 0 1)</code>) is actually an infinite stream of Fibonaccis
numbers, but lazily evaluated, so we just get the next one each time
we call <code>stream-pop</code> on our <code>fibonacci-stream</code> local variable. (What
happens is that <code>stream-pop</code> takes the <code>car</code> of <code>fibonacci-stream</code>,
evaluates and returns it, and then sets <code>fibonacci-stream</code> to be its <code>cdr</code>
(i.e., popping off and &ldquo;discarding&rdquo; the first element; which which
captured in our <code>fibs</code> collector.))</p>
<h3 id="cascades-of-fibonacci-numbers">Cascades of Fibonacci numbers</h3>
<p>Oh, incidentally and irrelevantly, if you inspect the contents of your
<code>fib6-50k</code>, it&rsquo;s very aesthetically pleasing, a cascade of numbers:</p>



<figure>
    
        <img src="https://babbagefiles.xyz/ox-hugo/Fibonacci_Flooding_Streams.png" alt="Figure 2: fibonacci numbers burst forth from their seeds and spill out into the buffer"/> <figcaption>
                
                <p>
                    <span class="figure-number">Figure 2: </span>fibonacci numbers burst forth from their seeds and spill out into the buffer
                    
                        
                        </p>
                
            </figcaption></figure>

<h2 id="excessive-lisp-nesting--overflow-error"><code>excessive-lisp-nesting</code>: <strong>(overflow-error)</strong></h2>
<p>I had hoped to get to the Y Combinator today (and think I might have
suggested a promise of that), for that&rsquo;s where things really get
interesting. And we need to get back to lambda calculus, of course.
But we may be near the limits of excessive lisp nesting ourselves
here.</p>
<p>However, the recursion discussion here has set the stage for the Y
Combinator, which we&rsquo;ve already talked a couple of times, especially
in connection to John McCarthy&rsquo;s claims about &ldquo;not really
understanding&rdquo; lambda calculus and the fact that these really centre
on his not seeing how one could get recursion without direct
Self-reference (and thus the need for <code>LABEL</code>) because of not knowing
about the Y Combinator.</p>



<figure>
    
        <img src="https://babbagefiles.xyz/ox-hugo/phoe-ycombinator-codex-closeup-fibo.jpg" alt="Figure 3: a close-up of a section of Michał &ldquo;phoe&rdquo; Herda&rsquo;s hand-illuminated Y Combinator Codex showing part of a Fibonacci defun"/> <figcaption>
                
                <p>
                    <span class="figure-number">Figure 3: </span>a close-up of a section of <a href="https://phoe.github.io/">Michał &ldquo;phoe&rdquo; Herda&rsquo;s</a> hand-illuminated <a href="https://phoe.github.io/codex.html">Y Combinator Codex</a> showing part of a Fibonacci defun
                    
                        
                        </p>
                
            </figcaption></figure>

<p>And, the Y Combinator ties in with all sorts of other curious
things. Paradoxes, types, calligraphy.</p>
<p>[Thus, I ended up with an excursus on this excursus as the next
post. I&rsquo;ll put a link here to the proper third part when it&rsquo;s up.]</p>
<section class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1" role="doc-endnote">
<p>McCarthy, John. 1978a. History of Lisp. In <em>History of programming languages</em>, ed. Richard L. Wexelblat, 173–185. New York:
Association for Computing Machinery. <a href="https://dl.acm.org/doi/10.1145/800025.1198360">https://dl.acm.org/doi/10.1145/800025.1198360</a> <a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2" role="doc-endnote">
<p>&ldquo;t if and only if p and q or if r then s and
not not not not not not t&rdquo; <a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3" role="doc-endnote">
<p>A number of Indian philosophers, at least as far back as
Virahāṅka (ca. AD 600–800), gave formulations for what is usually
called the Fibonacci sequence. See Singh, P. (1985). The so-called
fibonacci numbers in ancient and medieval India. <em>Historia Mathematica</em>,
12(3), 229–244. <a href="https://doi.org/10.1016/0315-0860(85)90021-7">https://doi.org/10.1016/0315-0860(85)90021-7</a> [<a href="https://sci-hub.se/https://www.sciencedirect.com/science/article/pii/0315086085900217?via%3Dihub">pdf</a>] <a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4" role="doc-endnote">
<p>You might actually want to do something like <code>(setq my-fib1-100 (fib1 100 0 1))</code> to put the result into a variable, because
the echo area at the bottom of Emacs isn&rsquo;t big enough for all of the
numbers. (Oh, to <code>eval</code> things in an Emacs buffer, put your cursor/point
at the end of the expression and press <code>C-x C-e</code>. But don&rsquo;t do that for
this one. If you want Emacs to just stick the results in directly into
the buffer rather than echoing them, press <code>C-u C-x C-e</code>. But don&rsquo;t do
that here either, because Emacs will still end up printing an ellipsis
because it thinks it&rsquo;s too long.) And then press <code>C-h v</code> and type
<code>my-fib1-100</code> and enter to see the result. <a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5" role="doc-endnote">
<p>See further <a href="https://en.wikipedia.org/wiki/Tail_call">here</a>, for instance, for more about tail calls and
tail call optimisation. <a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6" role="doc-endnote">
<p>Steele, Guy L., Jr. 1977. Debunking the “expensive procedure
call” myth or, procedure call implementations considered harmful or,
LAMBDA: The Ultimate GOTO. <em>ACM &lsquo;77: Proceedings of the 1977 annual
conference</em>, 153–162. [<a href="https://dl.acm.org/doi/10.1145/800179.810196">https://dl.acm.org/doi/10.1145/800179.810196</a>] <a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7" role="doc-endnote">
<p>If you&rsquo;ve read any of Paul Graham&rsquo;s Common Lisp books
(e.g., <a href="https://en.wikipedia.org/wiki/On_Lisp"><em>On Lisp</em></a>) or any of the <a href="https://web.archive.org/web/20150426092105/http://www.ccs.neu.edu/home/matthias/BTLS/">Little Schemer</a> books (the latter with
<a href="https://wiki.c2.com/?DuaneBibby">Duane Bibby</a>&lsquo;s lovely artwork in them), you may be disposed towards
using recursion rather than loops.</p>
<p>


<figure>
    
        <img src="https://babbagefiles.xyz/ox-hugo/little-scheming-phant.png" alt="Figure 4: close-up of Duane Bibby&rsquo;s cover illustration for &ldquo;The Little Schemer&rdquo;"/> <figcaption>
                
                <p>
                    <span class="figure-number">Figure 4: </span>close-up of Duane Bibby&rsquo;s cover illustration for &ldquo;The Little Schemer&rdquo;
                    
                        
                        </p>
                
            </figcaption></figure>
 <a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:8" role="doc-endnote">
<p>One of my emacs packages, <a href="https://melpa.org/#/equake">Equake</a>, actually used to use
tco.el (until <a href="https://github.com/emacsomancer/equake/commit/0ab08019e8aee5f2e27db6ee90f6a64856f39ff9">commit #0ab0801</a> <span class="timestamp-wrapper"><span class="timestamp">[2020-08-24 Mon]</span></span>). <a href="#fnref:8" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</section>
]]></content>
            
                 
                    
                         
                        
                            
                             
                                <category scheme="https://babbagefiles.xyz/categories/lambdacalculus" term="lambdacalculus" label="lambdacalculus" />
                             
                                <category scheme="https://babbagefiles.xyz/categories/emacs" term="emacs" label="emacs" />
                             
                                <category scheme="https://babbagefiles.xyz/categories/lisp" term="lisp" label="lisp" />
                            
                        
                    
                 
                    
                 
                    
                         
                        
                            
                             
                                <category scheme="https://babbagefiles.xyz/tags/recursion" term="recursion" label="recursion" />
                            
                        
                    
                
            
        </entry>
    
</feed>
