Regenerated docs.
This commit is contained in:
@@ -12602,7 +12602,7 @@ primrec == [i] genrec
|
|||||||
<div class="prompt input_prompt">In [ ]:</div>
|
<div class="prompt input_prompt">In [ ]:</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="input_area">
|
<div class="input_area">
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span>
|
<div class=" highlight hl-ipython2"><pre><span></span>
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -22,12 +22,11 @@ it's "off the shelf" technology.)
|
|||||||
.. code:: ipython2
|
.. code:: ipython2
|
||||||
|
|
||||||
J('1 2 3 clear')
|
J('1 2 3 clear')
|
||||||
J('1 2 3 clear')
|
|
||||||
|
|
||||||
|
|
||||||
.. parsed-literal::
|
.. parsed-literal::
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
``dup`` ``dupd``
|
``dup`` ``dupd``
|
||||||
|
|||||||
@@ -12447,7 +12447,7 @@ div#notebook {
|
|||||||
<div class="input_area">
|
<div class="input_area">
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="kn">from</span> <span class="nn">sympy</span> <span class="kn">import</span> <span class="n">floor</span><span class="p">,</span> <span class="n">lambdify</span><span class="p">,</span> <span class="n">solve</span><span class="p">,</span> <span class="n">symbols</span>
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="kn">from</span> <span class="nn">sympy</span> <span class="kn">import</span> <span class="n">floor</span><span class="p">,</span> <span class="n">lambdify</span><span class="p">,</span> <span class="n">solve</span><span class="p">,</span> <span class="n">symbols</span>
|
||||||
<span class="kn">from</span> <span class="nn">sympy</span> <span class="kn">import</span> <span class="n">init_printing</span>
|
<span class="kn">from</span> <span class="nn">sympy</span> <span class="kn">import</span> <span class="n">init_printing</span>
|
||||||
<span class="n">init_printing</span><span class="p">()</span>
|
<span class="n">init_printing</span><span class="p">()</span>
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -12600,7 +12600,7 @@ $$4 k \left(k + 1\right) + 2$$
|
|||||||
<div class="prompt input_prompt">In [19]:</div>
|
<div class="prompt input_prompt">In [19]:</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="input_area">
|
<div class="input_area">
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="o">%</span><span class="n">time</span> <span class="n">rank_of</span><span class="p">(</span><span class="mi">23000000000000</span><span class="p">)</span> <span class="c1"># Compare runtime with rank_and_offset()!</span>
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="o">%</span><span class="k">time</span> rank_of(23000000000000) # Compare runtime with rank_and_offset()!
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -12645,7 +12645,7 @@ $$2397916$$
|
|||||||
<div class="prompt input_prompt">In [20]:</div>
|
<div class="prompt input_prompt">In [20]:</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="input_area">
|
<div class="input_area">
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="o">%</span><span class="n">time</span> <span class="n">rank_and_offset</span><span class="p">(</span><span class="mi">23000000000000</span><span class="p">)</span>
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="o">%</span><span class="k">time</span> rank_and_offset(23000000000000)
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -12911,7 +12911,7 @@ $$\lfloor{\frac{1}{2} \sqrt{y - 1} - \frac{1}{2}}\rfloor + 1$$
|
|||||||
<div class="prompt input_prompt">In [28]:</div>
|
<div class="prompt input_prompt">In [28]:</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="input_area">
|
<div class="input_area">
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="o">%</span><span class="n">time</span> <span class="nb">int</span><span class="p">(</span><span class="n">F</span><span class="p">(</span><span class="mi">23000000000000</span><span class="p">))</span> <span class="c1"># The clear winner.</span>
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="o">%</span><span class="k">time</span> int(F(23000000000000)) # The clear winner.
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -12981,7 +12981,7 @@ $$2397916$$
|
|||||||
<div class="prompt input_prompt">In [30]:</div>
|
<div class="prompt input_prompt">In [30]:</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="input_area">
|
<div class="input_area">
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="o">%</span><span class="n">time</span> <span class="n">mrank_of</span><span class="p">(</span><span class="mi">23000000000000</span><span class="p">)</span>
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="o">%</span><span class="k">time</span> mrank_of(23000000000000)
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -13227,7 +13227,7 @@ $$4572225$$
|
|||||||
<div class="prompt input_prompt">In [37]:</div>
|
<div class="prompt input_prompt">In [37]:</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="input_area">
|
<div class="input_area">
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="o">%</span><span class="n">time</span> <span class="n">aoc20173</span><span class="p">(</span><span class="mi">23000000000000000000000000</span><span class="p">)</span> <span class="c1"># Fast for large values.</span>
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="o">%</span><span class="k">time</span> aoc20173(23000000000000000000000000) # Fast for large values.
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+344
-329
@@ -11797,33 +11797,65 @@ div#notebook {
|
|||||||
</div>
|
</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="text_cell_render border-box-sizing rendered_html">
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
<p>Consider the <code>x</code> combinator <code>x == dup i</code>:</p>
|
<p>Consider the <code>x</code> combinator:</p>
|
||||||
|
|
||||||
<pre><code>[a B] x
|
<pre><code>x == dup i
|
||||||
[a B] a B
|
|
||||||
|
|
||||||
</code></pre>
|
</code></pre>
|
||||||
<p>Let <code>B</code> <code>swap</code> the <code>a</code> with the quote and run some function <code>[C]</code> on it.</p>
|
<p>We can apply it to a quoted program consisting of some value <code>a</code> and a function <code>B</code>:</p>
|
||||||
|
|
||||||
<pre><code>[a B] a B
|
<pre><code>[a B] x
|
||||||
|
[a B] a B</code></pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<p>Let <code>B</code> function <code>swap</code> the <code>a</code> with the quote and run some function <code>C</code> on it to generate a new value <code>b</code>:</p>
|
||||||
|
|
||||||
|
<pre><code>B == swap [C] dip
|
||||||
|
|
||||||
|
[a B] a B
|
||||||
[a B] a swap [C] dip
|
[a B] a swap [C] dip
|
||||||
a [a B] [C] dip
|
a [a B] [C] dip
|
||||||
a C [a B]
|
a C [a B]
|
||||||
|
b [a B]</code></pre>
|
||||||
|
|
||||||
</code></pre>
|
</div>
|
||||||
<p>Now discard the quoted <code>a</code> with <code>rest</code> and <code>cons</code> the result of <code>C</code> on <code>a</code> whatever that is:</p>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<p>Now discard the quoted <code>a</code> with <code>rest</code> then <code>cons</code> <code>b</code>:</p>
|
||||||
|
|
||||||
<pre><code>aC [a B] rest cons
|
<pre><code>b [a B] rest cons
|
||||||
aC [B] cons
|
b [B] cons
|
||||||
[aC B]
|
[b B]</code></pre>
|
||||||
|
|
||||||
</code></pre>
|
</div>
|
||||||
<p>Altogether, this is the definition of <code>B</code>:</p>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<p>Putting it together, this is the definition of <code>B</code>:</p>
|
||||||
|
|
||||||
<pre><code>B == swap [C] dip rest cons
|
<pre><code>B == swap [C] dip rest cons</code></pre>
|
||||||
|
|
||||||
</code></pre>
|
</div>
|
||||||
<p>We can create a quoted program that generates the Natural numbers (integers 0, 1, 2, ...) by using <code>0</code> for <code>a</code> and <code>[dup ++]</code> for <code>[C]</code>:</p>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<p>We can create a quoted program that generates the Natural numbers (0, 1, 2, ...) by using <code>0</code> for <code>a</code> and <code>[dup ++]</code> for <code>[C]</code>:</p>
|
||||||
|
|
||||||
<pre><code>[0 swap [dup ++] dip rest cons]
|
<pre><code>[0 swap [dup ++] dip rest cons]
|
||||||
|
|
||||||
@@ -11983,16 +12015,19 @@ aC [B] cons
|
|||||||
</div>
|
</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="text_cell_render border-box-sizing rendered_html">
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
<h1 id="Generating-Generators">Generating Generators<a class="anchor-link" href="#Generating-Generators">¶</a></h1><p>We want to go from:</p>
|
<h1 id="Making-Generators">Making Generators<a class="anchor-link" href="#Making-Generators">¶</a></h1><p>We want to define a function that accepts <code>a</code> and <code>[C]</code> and builds our quoted program:</p>
|
||||||
|
|
||||||
<pre><code>a [C] G
|
<pre><code> a [C] G
|
||||||
|
-------------------------
|
||||||
|
[a swap [C] direco]</code></pre>
|
||||||
|
|
||||||
</code></pre>
|
</div>
|
||||||
<p>to:</p>
|
</div>
|
||||||
|
</div>
|
||||||
<pre><code>[a swap [C] direco]
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
</code></pre>
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
<p>Working in reverse:</p>
|
<p>Working in reverse:</p>
|
||||||
|
|
||||||
<pre><code>[a swap [C] direco] cons
|
<pre><code>[a swap [C] direco] cons
|
||||||
@@ -12005,12 +12040,7 @@ a [C] [direco] cons [swap]
|
|||||||
<p>Reading from the bottom up:</p>
|
<p>Reading from the bottom up:</p>
|
||||||
|
|
||||||
<pre><code>G == [direco] cons [swap] swap concat cons
|
<pre><code>G == [direco] cons [swap] swap concat cons
|
||||||
G == [direco] cons [swap] swoncat cons
|
G == [direco] cons [swap] swoncat cons</code></pre>
|
||||||
|
|
||||||
</code></pre>
|
|
||||||
<p>We can try it out:</p>
|
|
||||||
|
|
||||||
<pre><code>0 [dup ++] G</code></pre>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -12027,13 +12057,22 @@ G == [direco] cons [swap] swoncat cons
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<p>Let's try it out:</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="cell border-box-sizing code_cell rendered">
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<div class="prompt input_prompt">In [7]:</div>
|
<div class="prompt input_prompt">In [7]:</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="input_area">
|
<div class="input_area">
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">V</span><span class="p">(</span><span class="s1">'0 [dup ++] G'</span><span class="p">)</span>
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'0 [dup ++] G'</span><span class="p">)</span>
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -12050,17 +12089,7 @@ G == [direco] cons [swap] swoncat cons
|
|||||||
|
|
||||||
|
|
||||||
<div class="output_subarea output_stream output_stdout output_text">
|
<div class="output_subarea output_stream output_stdout output_text">
|
||||||
<pre> . 0 [dup ++] G
|
<pre>[0 swap [dup ++] direco]
|
||||||
0 . [dup ++] G
|
|
||||||
0 [dup ++] . G
|
|
||||||
0 [dup ++] . [direco] cons [swap] swoncat cons
|
|
||||||
0 [dup ++] [direco] . cons [swap] swoncat cons
|
|
||||||
0 [[dup ++] direco] . [swap] swoncat cons
|
|
||||||
0 [[dup ++] direco] [swap] . swoncat cons
|
|
||||||
0 [[dup ++] direco] [swap] . swap concat cons
|
|
||||||
0 [swap] [[dup ++] direco] . concat cons
|
|
||||||
0 [swap [dup ++] direco] . cons
|
|
||||||
[0 swap [dup ++] direco] .
|
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -12074,7 +12103,7 @@ G == [direco] cons [swap] swoncat cons
|
|||||||
<div class="prompt input_prompt">In [8]:</div>
|
<div class="prompt input_prompt">In [8]:</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="input_area">
|
<div class="input_area">
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">V</span><span class="p">(</span><span class="s1">'0 [dup ++] G x'</span><span class="p">)</span>
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'0 [dup ++] G x x x pop'</span><span class="p">)</span>
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -12091,28 +12120,7 @@ G == [direco] cons [swap] swoncat cons
|
|||||||
|
|
||||||
|
|
||||||
<div class="output_subarea output_stream output_stdout output_text">
|
<div class="output_subarea output_stream output_stdout output_text">
|
||||||
<pre> . 0 [dup ++] G x
|
<pre>0 1 2
|
||||||
0 . [dup ++] G x
|
|
||||||
0 [dup ++] . G x
|
|
||||||
0 [dup ++] . [direco] cons [swap] swoncat cons x
|
|
||||||
0 [dup ++] [direco] . cons [swap] swoncat cons x
|
|
||||||
0 [[dup ++] direco] . [swap] swoncat cons x
|
|
||||||
0 [[dup ++] direco] [swap] . swoncat cons x
|
|
||||||
0 [[dup ++] direco] [swap] . swap concat cons x
|
|
||||||
0 [swap] [[dup ++] direco] . concat cons x
|
|
||||||
0 [swap [dup ++] direco] . cons x
|
|
||||||
[0 swap [dup ++] direco] . x
|
|
||||||
[0 swap [dup ++] direco] . 0 swap [dup ++] direco
|
|
||||||
[0 swap [dup ++] direco] 0 . swap [dup ++] direco
|
|
||||||
0 [0 swap [dup ++] direco] . [dup ++] direco
|
|
||||||
0 [0 swap [dup ++] direco] [dup ++] . direco
|
|
||||||
0 [0 swap [dup ++] direco] [dup ++] . dip rest cons
|
|
||||||
0 . dup ++ [0 swap [dup ++] direco] rest cons
|
|
||||||
0 0 . ++ [0 swap [dup ++] direco] rest cons
|
|
||||||
0 1 . [0 swap [dup ++] direco] rest cons
|
|
||||||
0 1 [0 swap [dup ++] direco] . rest cons
|
|
||||||
0 1 [swap [dup ++] direco] . cons
|
|
||||||
0 [1 swap [dup ++] direco] .
|
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -12134,7 +12142,7 @@ G == [direco] cons [swap] swoncat cons
|
|||||||
<div class="prompt input_prompt">In [9]:</div>
|
<div class="prompt input_prompt">In [9]:</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="input_area">
|
<div class="input_area">
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'1 [dup 1 <<] G x x x x x x x x x'</span><span class="p">)</span>
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'1 [dup 1 <<] G x x x x x x x x x pop'</span><span class="p">)</span>
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -12151,7 +12159,7 @@ G == [direco] cons [swap] swoncat cons
|
|||||||
|
|
||||||
|
|
||||||
<div class="output_subarea output_stream output_stdout output_text">
|
<div class="output_subarea output_stream output_stdout output_text">
|
||||||
<pre>1 2 4 8 16 32 64 128 256 [512 swap [dup 1 <<] direco]
|
<pre>1 2 4 8 16 32 64 128 256
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -12164,8 +12172,7 @@ G == [direco] cons [swap] swoncat cons
|
|||||||
</div>
|
</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="text_cell_render border-box-sizing rendered_html">
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
<h1 id="n-[x]-times"><code>n [x] times</code><a class="anchor-link" href="#n-[x]-times">¶</a></h1><p>If we have one of these quoted programs we can drive it using <code>times</code> with the <code>x</code> combinator.</p>
|
<h3 id="[x]-times"><code>[x] times</code><a class="anchor-link" href="#[x]-times">¶</a></h3><p>If we have one of these quoted programs we can drive it using <code>times</code> with the <code>x</code> combinator.</p>
|
||||||
<p>Let's define a word <code>n_range</code> that takes a starting integer and a count and leaves that many consecutive integers on the stack. For example:</p>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -12175,7 +12182,7 @@ G == [direco] cons [swap] swoncat cons
|
|||||||
<div class="prompt input_prompt">In [10]:</div>
|
<div class="prompt input_prompt">In [10]:</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="input_area">
|
<div class="input_area">
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'23 [dup ++] G 5 [x] times pop'</span><span class="p">)</span>
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'23 [dup ++] G 5 [x] times'</span><span class="p">)</span>
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -12192,140 +12199,7 @@ G == [direco] cons [swap] swoncat cons
|
|||||||
|
|
||||||
|
|
||||||
<div class="output_subarea output_stream output_stdout output_text">
|
<div class="output_subarea output_stream output_stdout output_text">
|
||||||
<pre>23 24 25 26 27
|
<pre>23 24 25 26 27 [28 swap [dup ++] direco]
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
|
||||||
</div>
|
|
||||||
<div class="inner_cell">
|
|
||||||
<div class="text_cell_render border-box-sizing rendered_html">
|
|
||||||
<p>We can use <code>dip</code> to untangle <code>[dup ++] G</code> from the arguments.</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="cell border-box-sizing code_cell rendered">
|
|
||||||
<div class="input">
|
|
||||||
<div class="prompt input_prompt">In [11]:</div>
|
|
||||||
<div class="inner_cell">
|
|
||||||
<div class="input_area">
|
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'23 5 [[dup ++] G] dip [x] times pop'</span><span class="p">)</span>
|
|
||||||
</pre></div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="output_wrapper">
|
|
||||||
<div class="output">
|
|
||||||
|
|
||||||
|
|
||||||
<div class="output_area">
|
|
||||||
|
|
||||||
<div class="prompt"></div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="output_subarea output_stream output_stdout output_text">
|
|
||||||
<pre>23 24 25 26 27
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
|
||||||
</div>
|
|
||||||
<div class="inner_cell">
|
|
||||||
<div class="text_cell_render border-box-sizing rendered_html">
|
|
||||||
<p>Now that the givens (arguments) are on the left we have the definition we're looking for:</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="cell border-box-sizing code_cell rendered">
|
|
||||||
<div class="input">
|
|
||||||
<div class="prompt input_prompt">In [12]:</div>
|
|
||||||
<div class="inner_cell">
|
|
||||||
<div class="input_area">
|
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">'n_range == [[dup ++] G] dip [x] times pop'</span><span class="p">)</span>
|
|
||||||
</pre></div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="cell border-box-sizing code_cell rendered">
|
|
||||||
<div class="input">
|
|
||||||
<div class="prompt input_prompt">In [13]:</div>
|
|
||||||
<div class="inner_cell">
|
|
||||||
<div class="input_area">
|
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'450 10 n_range'</span><span class="p">)</span>
|
|
||||||
</pre></div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="output_wrapper">
|
|
||||||
<div class="output">
|
|
||||||
|
|
||||||
|
|
||||||
<div class="output_area">
|
|
||||||
|
|
||||||
<div class="prompt"></div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="output_subarea output_stream output_stdout output_text">
|
|
||||||
<pre>450 451 452 453 454 455 456 457 458 459
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
|
||||||
</div>
|
|
||||||
<div class="inner_cell">
|
|
||||||
<div class="text_cell_render border-box-sizing rendered_html">
|
|
||||||
<p>This is better just using the <code>times</code> combinator though...</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="cell border-box-sizing code_cell rendered">
|
|
||||||
<div class="input">
|
|
||||||
<div class="prompt input_prompt">In [14]:</div>
|
|
||||||
<div class="inner_cell">
|
|
||||||
<div class="input_area">
|
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'450 9 [dup ++] times'</span><span class="p">)</span>
|
|
||||||
</pre></div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="output_wrapper">
|
|
||||||
<div class="output">
|
|
||||||
|
|
||||||
|
|
||||||
<div class="output_area">
|
|
||||||
|
|
||||||
<div class="prompt"></div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="output_subarea output_stream output_stdout output_text">
|
|
||||||
<pre>450 451 452 453 454 455 456 457 458 459
|
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -12356,7 +12230,7 @@ G == [direco] cons [swap] swoncat cons
|
|||||||
</div>
|
</div>
|
||||||
<div class="cell border-box-sizing code_cell rendered">
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<div class="prompt input_prompt">In [15]:</div>
|
<div class="prompt input_prompt">In [11]:</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="input_area">
|
<div class="input_area">
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">'PE1.1 == dup [3 &] dip 2 >>'</span><span class="p">)</span>
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">'PE1.1 == dup [3 &] dip 2 >>'</span><span class="p">)</span>
|
||||||
@@ -12369,7 +12243,7 @@ G == [direco] cons [swap] swoncat cons
|
|||||||
</div>
|
</div>
|
||||||
<div class="cell border-box-sizing code_cell rendered">
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<div class="prompt input_prompt">In [16]:</div>
|
<div class="prompt input_prompt">In [12]:</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="input_area">
|
<div class="input_area">
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">V</span><span class="p">(</span><span class="s1">'14811 PE1.1'</span><span class="p">)</span>
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">V</span><span class="p">(</span><span class="s1">'14811 PE1.1'</span><span class="p">)</span>
|
||||||
@@ -12419,7 +12293,7 @@ G == [direco] cons [swap] swoncat cons
|
|||||||
</div>
|
</div>
|
||||||
<div class="cell border-box-sizing code_cell rendered">
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<div class="prompt input_prompt">In [17]:</div>
|
<div class="prompt input_prompt">In [13]:</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="input_area">
|
<div class="input_area">
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'14811 [PE1.1] G'</span><span class="p">)</span>
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'14811 [PE1.1] G'</span><span class="p">)</span>
|
||||||
@@ -12447,37 +12321,6 @@ G == [direco] cons [swap] swoncat cons
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="cell border-box-sizing code_cell rendered">
|
|
||||||
<div class="input">
|
|
||||||
<div class="prompt input_prompt">In [18]:</div>
|
|
||||||
<div class="inner_cell">
|
|
||||||
<div class="input_area">
|
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'[14811 swap [PE1.1] direco] x'</span><span class="p">)</span>
|
|
||||||
</pre></div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="output_wrapper">
|
|
||||||
<div class="output">
|
|
||||||
|
|
||||||
|
|
||||||
<div class="output_area">
|
|
||||||
|
|
||||||
<div class="prompt"></div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="output_subarea output_stream output_stdout output_text">
|
|
||||||
<pre>3 [3702 swap [PE1.1] direco]
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
</div>
|
</div>
|
||||||
@@ -12490,7 +12333,7 @@ G == [direco] cons [swap] swoncat cons
|
|||||||
</div>
|
</div>
|
||||||
<div class="cell border-box-sizing code_cell rendered">
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<div class="prompt input_prompt">In [19]:</div>
|
<div class="prompt input_prompt">In [14]:</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="input_area">
|
<div class="input_area">
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'[14811 swap [PE1.1] direco] 7 [x] times'</span><span class="p">)</span>
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'[14811 swap [PE1.1] direco] 7 [x] times'</span><span class="p">)</span>
|
||||||
@@ -12530,7 +12373,7 @@ G == [direco] cons [swap] swoncat cons
|
|||||||
</div>
|
</div>
|
||||||
<div class="cell border-box-sizing code_cell rendered">
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<div class="prompt input_prompt">In [20]:</div>
|
<div class="prompt input_prompt">In [15]:</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="input_area">
|
<div class="input_area">
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">'PE1.1.check == dup [pop 14811] [] branch'</span><span class="p">)</span>
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">'PE1.1.check == dup [pop 14811] [] branch'</span><span class="p">)</span>
|
||||||
@@ -12543,7 +12386,38 @@ G == [direco] cons [swap] swoncat cons
|
|||||||
</div>
|
</div>
|
||||||
<div class="cell border-box-sizing code_cell rendered">
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<div class="prompt input_prompt">In [21]:</div>
|
<div class="prompt input_prompt">In [16]:</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="input_area">
|
||||||
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'14811 [PE1.1.check PE1.1] G'</span><span class="p">)</span>
|
||||||
|
</pre></div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="output_wrapper">
|
||||||
|
<div class="output">
|
||||||
|
|
||||||
|
|
||||||
|
<div class="output_area">
|
||||||
|
|
||||||
|
<div class="prompt"></div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="output_subarea output_stream output_stdout output_text">
|
||||||
|
<pre>[14811 swap [PE1.1.check PE1.1] direco]
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
|
<div class="input">
|
||||||
|
<div class="prompt input_prompt">In [17]:</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="input_area">
|
<div class="input_area">
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'[14811 swap [PE1.1.check PE1.1] direco] 21 [x] times'</span><span class="p">)</span>
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'[14811 swap [PE1.1.check PE1.1] direco] 21 [x] times'</span><span class="p">)</span>
|
||||||
@@ -12571,6 +12445,15 @@ G == [direco] cons [swap] swoncat cons
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<p>(It would be more efficient to reset the int every seven cycles but that's a little beyond the scope of this article. This solution does extra work, but not much, and we're not using it "in production" as they say.)</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
</div>
|
</div>
|
||||||
@@ -12583,7 +12466,7 @@ G == [direco] cons [swap] swoncat cons
|
|||||||
</div>
|
</div>
|
||||||
<div class="cell border-box-sizing code_cell rendered">
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<div class="prompt input_prompt">In [22]:</div>
|
<div class="prompt input_prompt">In [18]:</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="input_area">
|
<div class="input_area">
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'7 66 * 4 +'</span><span class="p">)</span>
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'7 66 * 4 +'</span><span class="p">)</span>
|
||||||
@@ -12623,10 +12506,10 @@ G == [direco] cons [swap] swoncat cons
|
|||||||
</div>
|
</div>
|
||||||
<div class="cell border-box-sizing code_cell rendered">
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<div class="prompt input_prompt">In [23]:</div>
|
<div class="prompt input_prompt">In [19]:</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="input_area">
|
<div class="input_area">
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'[14811 swap [PE1.1.check PE1.1] dip rest cons] 466 [x] times'</span><span class="p">)</span>
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'[14811 swap [PE1.1.check PE1.1] direco] 466 [x] times'</span><span class="p">)</span>
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -12643,7 +12526,7 @@ G == [direco] cons [swap] swoncat cons
|
|||||||
|
|
||||||
|
|
||||||
<div class="output_subarea output_stream output_stdout output_text">
|
<div class="output_subarea output_stream output_stdout output_text">
|
||||||
<pre>3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 [57 swap [PE1.1.check PE1.1] dip rest cons]
|
<pre>3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 [57 swap [PE1.1.check PE1.1] direco]
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -12654,10 +12537,10 @@ G == [direco] cons [swap] swoncat cons
|
|||||||
</div>
|
</div>
|
||||||
<div class="cell border-box-sizing code_cell rendered">
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<div class="prompt input_prompt">In [24]:</div>
|
<div class="prompt input_prompt">In [20]:</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="input_area">
|
<div class="input_area">
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'[14811 swap [PE1.1.check PE1.1] dip rest cons] 466 [x] times pop enstacken sum'</span><span class="p">)</span>
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'[14811 swap [PE1.1.check PE1.1] direco] 466 [x] times pop enstacken sum'</span><span class="p">)</span>
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -12693,7 +12576,7 @@ G == [direco] cons [swap] swoncat cons
|
|||||||
</div>
|
</div>
|
||||||
<div class="cell border-box-sizing code_cell rendered">
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<div class="prompt input_prompt">In [25]:</div>
|
<div class="prompt input_prompt">In [21]:</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="input_area">
|
<div class="input_area">
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">'PE1.2 == + dup [+] dip'</span><span class="p">)</span>
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">'PE1.2 == + dup [+] dip'</span><span class="p">)</span>
|
||||||
@@ -12708,54 +12591,14 @@ G == [direco] cons [swap] swoncat cons
|
|||||||
</div>
|
</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="text_cell_render border-box-sizing rendered_html">
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
<p>Now we can add <code>PE1.2</code> to the quoted program given to <code>times</code>.</p>
|
<p>Now we can add <code>PE1.2</code> to the quoted program given to <code>G</code>.</p>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="cell border-box-sizing code_cell rendered">
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<div class="prompt input_prompt">In [26]:</div>
|
<div class="prompt input_prompt">In [22]:</div>
|
||||||
<div class="inner_cell">
|
|
||||||
<div class="input_area">
|
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'0 0 [0 swap [PE1.1.check PE1.1] direco] 466 [x [PE1.2] dip] times popop'</span><span class="p">)</span>
|
|
||||||
</pre></div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="output_wrapper">
|
|
||||||
<div class="output">
|
|
||||||
|
|
||||||
|
|
||||||
<div class="output_area">
|
|
||||||
|
|
||||||
<div class="prompt"></div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="output_subarea output_stream output_stdout output_text">
|
|
||||||
<pre>233168
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
|
||||||
</div>
|
|
||||||
<div class="inner_cell">
|
|
||||||
<div class="text_cell_render border-box-sizing rendered_html">
|
|
||||||
<p>Or using <code>G</code> we can write:</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="cell border-box-sizing code_cell rendered">
|
|
||||||
<div class="input">
|
|
||||||
<div class="prompt input_prompt">In [27]:</div>
|
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="input_area">
|
<div class="input_area">
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'0 0 0 [PE1.1.check PE1.1] G 466 [x [PE1.2] dip] times popop'</span><span class="p">)</span>
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'0 0 0 [PE1.1.check PE1.1] G 466 [x [PE1.2] dip] times popop'</span><span class="p">)</span>
|
||||||
@@ -12791,73 +12634,135 @@ G == [direco] cons [swap] swoncat cons
|
|||||||
<h1 id="A-generator-for-the-Fibonacci-Sequence.">A generator for the Fibonacci Sequence.<a class="anchor-link" href="#A-generator-for-the-Fibonacci-Sequence.">¶</a></h1><p>Consider:</p>
|
<h1 id="A-generator-for-the-Fibonacci-Sequence.">A generator for the Fibonacci Sequence.<a class="anchor-link" href="#A-generator-for-the-Fibonacci-Sequence.">¶</a></h1><p>Consider:</p>
|
||||||
|
|
||||||
<pre><code>[b a F] x
|
<pre><code>[b a F] x
|
||||||
[b a F] b a F
|
[b a F] b a F</code></pre>
|
||||||
|
|
||||||
</code></pre>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
<p>The obvious first thing to do is just add <code>b</code> and <code>a</code>:</p>
|
<p>The obvious first thing to do is just add <code>b</code> and <code>a</code>:</p>
|
||||||
|
|
||||||
<pre><code>[b a F] b a +
|
<pre><code>[b a F] b a +
|
||||||
[b a F] b+a
|
[b a F] b+a</code></pre>
|
||||||
|
|
||||||
</code></pre>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
<p>From here we want to arrive at:</p>
|
<p>From here we want to arrive at:</p>
|
||||||
|
|
||||||
<pre><code>b [b+a b F]
|
<pre><code>b [b+a b F]</code></pre>
|
||||||
|
|
||||||
</code></pre>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
<p>Let's start with <code>swons</code>:</p>
|
<p>Let's start with <code>swons</code>:</p>
|
||||||
|
|
||||||
<pre><code>[b a F] b+a swons
|
<pre><code>[b a F] b+a swons
|
||||||
[b+a b a F]
|
[b+a b a F]</code></pre>
|
||||||
|
|
||||||
</code></pre>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
<p>Considering this quote as a stack:</p>
|
<p>Considering this quote as a stack:</p>
|
||||||
|
|
||||||
<pre><code>F a b b+a
|
<pre><code>F a b b+a</code></pre>
|
||||||
|
|
||||||
</code></pre>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
<p>We want to get it to:</p>
|
<p>We want to get it to:</p>
|
||||||
|
|
||||||
<pre><code>F b b+a b
|
<pre><code>F b b+a b</code></pre>
|
||||||
|
|
||||||
</code></pre>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
<p>So:</p>
|
<p>So:</p>
|
||||||
|
|
||||||
<pre><code>F a b b+a popdd over
|
<pre><code>F a b b+a popdd over
|
||||||
F b b+a b
|
F b b+a b</code></pre>
|
||||||
|
|
||||||
</code></pre>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
<p>And therefore:</p>
|
<p>And therefore:</p>
|
||||||
|
|
||||||
<pre><code>[b+a b a F] [popdd over] infra
|
<pre><code>[b+a b a F] [popdd over] infra
|
||||||
[b b+a b F]
|
[b b+a b F]</code></pre>
|
||||||
|
|
||||||
</code></pre>
|
</div>
|
||||||
<p>And lastly:</p>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<p>But we can just use <code>cons</code> to carry <code>b+a</code> into the quote:</p>
|
||||||
|
|
||||||
|
<pre><code>[b a F] b+a [popdd over] cons infra
|
||||||
|
[b a F] [b+a popdd over] infra
|
||||||
|
[b b+a b F]</code></pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<p>Lastly:</p>
|
||||||
|
|
||||||
<pre><code>[b b+a b F] uncons
|
<pre><code>[b b+a b F] uncons
|
||||||
b [b+a b F]
|
b [b+a b F]</code></pre>
|
||||||
|
|
||||||
</code></pre>
|
</div>
|
||||||
<p>Done.</p>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
<p>Putting it all together:</p>
|
<p>Putting it all together:</p>
|
||||||
|
|
||||||
<pre><code>F == + swons [popdd over] infra uncons
|
<pre><code>F == + [popdd over] cons infra uncons
|
||||||
|
fib_gen == [1 1 F]</code></pre>
|
||||||
</code></pre>
|
|
||||||
<p>And:</p>
|
|
||||||
|
|
||||||
<pre><code>fib_gen == [1 1 F]</code></pre>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="cell border-box-sizing code_cell rendered">
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<div class="prompt input_prompt">In [28]:</div>
|
<div class="prompt input_prompt">In [23]:</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="input_area">
|
<div class="input_area">
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">'fib == + swons [popdd over] infra uncons'</span><span class="p">)</span>
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">'fib == + [popdd over] cons infra uncons'</span><span class="p">)</span>
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -12867,7 +12772,7 @@ b [b+a b F]
|
|||||||
</div>
|
</div>
|
||||||
<div class="cell border-box-sizing code_cell rendered">
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<div class="prompt input_prompt">In [29]:</div>
|
<div class="prompt input_prompt">In [24]:</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="input_area">
|
<div class="input_area">
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">'fib_gen == [1 1 fib]'</span><span class="p">)</span>
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">'fib_gen == [1 1 fib]'</span><span class="p">)</span>
|
||||||
@@ -12880,7 +12785,7 @@ b [b+a b F]
|
|||||||
</div>
|
</div>
|
||||||
<div class="cell border-box-sizing code_cell rendered">
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<div class="prompt input_prompt">In [30]:</div>
|
<div class="prompt input_prompt">In [25]:</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="input_area">
|
<div class="input_area">
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'fib_gen 10 [x] times'</span><span class="p">)</span>
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'fib_gen 10 [x] times'</span><span class="p">)</span>
|
||||||
@@ -12914,7 +12819,8 @@ b [b+a b F]
|
|||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="text_cell_render border-box-sizing rendered_html">
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
<h3 id="Project-Euler-Problem-Two">Project Euler Problem Two<a class="anchor-link" href="#Project-Euler-Problem-Two">¶</a></h3>
|
<h3 id="Project-Euler-Problem-Two">Project Euler Problem Two<a class="anchor-link" href="#Project-Euler-Problem-Two">¶</a></h3>
|
||||||
<pre><code>By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
|
<pre><code>By considering the terms in the Fibonacci sequence whose values do not exceed four million,
|
||||||
|
find the sum of the even-valued terms.
|
||||||
|
|
||||||
</code></pre>
|
</code></pre>
|
||||||
<p>Now that we have a generator for the Fibonacci sequence, we need a function that adds a term in the sequence to a sum if it is even, and <code>pop</code>s it otherwise.</p>
|
<p>Now that we have a generator for the Fibonacci sequence, we need a function that adds a term in the sequence to a sum if it is even, and <code>pop</code>s it otherwise.</p>
|
||||||
@@ -12924,7 +12830,7 @@ b [b+a b F]
|
|||||||
</div>
|
</div>
|
||||||
<div class="cell border-box-sizing code_cell rendered">
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<div class="prompt input_prompt">In [31]:</div>
|
<div class="prompt input_prompt">In [26]:</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="input_area">
|
<div class="input_area">
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">'PE2.1 == dup 2 % [+] [pop] branch'</span><span class="p">)</span>
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">'PE2.1 == dup 2 % [+] [pop] branch'</span><span class="p">)</span>
|
||||||
@@ -12946,7 +12852,7 @@ b [b+a b F]
|
|||||||
</div>
|
</div>
|
||||||
<div class="cell border-box-sizing code_cell rendered">
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<div class="prompt input_prompt">In [32]:</div>
|
<div class="prompt input_prompt">In [27]:</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="input_area">
|
<div class="input_area">
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">'>4M == 4000000 >'</span><span class="p">)</span>
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">'>4M == 4000000 >'</span><span class="p">)</span>
|
||||||
@@ -12968,7 +12874,7 @@ b [b+a b F]
|
|||||||
</div>
|
</div>
|
||||||
<div class="cell border-box-sizing code_cell rendered">
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<div class="prompt input_prompt">In [33]:</div>
|
<div class="prompt input_prompt">In [28]:</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="input_area">
|
<div class="input_area">
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">'PE2 == 0 fib_gen x [pop >4M] [popop] [[PE2.1] dip x] primrec'</span><span class="p">)</span>
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">'PE2 == 0 fib_gen x [pop >4M] [popop] [[PE2.1] dip x] primrec'</span><span class="p">)</span>
|
||||||
@@ -12981,7 +12887,7 @@ b [b+a b F]
|
|||||||
</div>
|
</div>
|
||||||
<div class="cell border-box-sizing code_cell rendered">
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<div class="prompt input_prompt">In [34]:</div>
|
<div class="prompt input_prompt">In [29]:</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="input_area">
|
<div class="input_area">
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'PE2'</span><span class="p">)</span>
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'PE2'</span><span class="p">)</span>
|
||||||
@@ -13052,7 +12958,7 @@ o + e = o
|
|||||||
</div>
|
</div>
|
||||||
<div class="cell border-box-sizing code_cell rendered">
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<div class="prompt input_prompt">In [35]:</div>
|
<div class="prompt input_prompt">In [30]:</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="input_area">
|
<div class="input_area">
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'[1 0 fib] x x x'</span><span class="p">)</span> <span class="c1"># To start the sequence with 1 1 2 3 instead of 1 2 3.</span>
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'[1 0 fib] x x x'</span><span class="p">)</span> <span class="c1"># To start the sequence with 1 1 2 3 instead of 1 2 3.</span>
|
||||||
@@ -13092,7 +12998,7 @@ o + e = o
|
|||||||
</div>
|
</div>
|
||||||
<div class="cell border-box-sizing code_cell rendered">
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<div class="prompt input_prompt">In [36]:</div>
|
<div class="prompt input_prompt">In [31]:</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="input_area">
|
<div class="input_area">
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'[1 0 fib] x x x [popop] dipd'</span><span class="p">)</span>
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'[1 0 fib] x x x [popop] dipd'</span><span class="p">)</span>
|
||||||
@@ -13123,7 +13029,7 @@ o + e = o
|
|||||||
</div>
|
</div>
|
||||||
<div class="cell border-box-sizing code_cell rendered">
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<div class="prompt input_prompt">In [37]:</div>
|
<div class="prompt input_prompt">In [32]:</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="input_area">
|
<div class="input_area">
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">'PE2.2 == x x x [popop] dipd'</span><span class="p">)</span>
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">'PE2.2 == x x x [popop] dipd'</span><span class="p">)</span>
|
||||||
@@ -13136,7 +13042,7 @@ o + e = o
|
|||||||
</div>
|
</div>
|
||||||
<div class="cell border-box-sizing code_cell rendered">
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<div class="prompt input_prompt">In [38]:</div>
|
<div class="prompt input_prompt">In [33]:</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="input_area">
|
<div class="input_area">
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'[1 0 fib] 10 [PE2.2] times'</span><span class="p">)</span>
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'[1 0 fib] 10 [PE2.2] times'</span><span class="p">)</span>
|
||||||
@@ -13176,7 +13082,7 @@ o + e = o
|
|||||||
</div>
|
</div>
|
||||||
<div class="cell border-box-sizing code_cell rendered">
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<div class="prompt input_prompt">In [39]:</div>
|
<div class="prompt input_prompt">In [34]:</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="input_area">
|
<div class="input_area">
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'0 [1 0 fib] PE2.2 [pop >4M] [popop] [[PE2.1] dip PE2.2] primrec'</span><span class="p">)</span>
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'0 [1 0 fib] PE2.2 [pop >4M] [popop] [[PE2.1] dip PE2.2] primrec'</span><span class="p">)</span>
|
||||||
@@ -13213,6 +13119,115 @@ o + e = o
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<h1 id="An-Interesting-Variation">An Interesting Variation<a class="anchor-link" href="#An-Interesting-Variation">¶</a></h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
|
<div class="input">
|
||||||
|
<div class="prompt input_prompt">In [35]:</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="input_area">
|
||||||
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">'codireco == cons dip rest cons'</span><span class="p">)</span>
|
||||||
|
</pre></div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
|
<div class="input">
|
||||||
|
<div class="prompt input_prompt">In [36]:</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="input_area">
|
||||||
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">V</span><span class="p">(</span><span class="s1">'[0 [dup ++] codireco] x'</span><span class="p">)</span>
|
||||||
|
</pre></div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="output_wrapper">
|
||||||
|
<div class="output">
|
||||||
|
|
||||||
|
|
||||||
|
<div class="output_area">
|
||||||
|
|
||||||
|
<div class="prompt"></div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="output_subarea output_stream output_stdout output_text">
|
||||||
|
<pre> . [0 [dup ++] codireco] x
|
||||||
|
[0 [dup ++] codireco] . x
|
||||||
|
[0 [dup ++] codireco] . 0 [dup ++] codireco
|
||||||
|
[0 [dup ++] codireco] 0 . [dup ++] codireco
|
||||||
|
[0 [dup ++] codireco] 0 [dup ++] . codireco
|
||||||
|
[0 [dup ++] codireco] 0 [dup ++] . cons dip rest cons
|
||||||
|
[0 [dup ++] codireco] [0 dup ++] . dip rest cons
|
||||||
|
. 0 dup ++ [0 [dup ++] codireco] rest cons
|
||||||
|
0 . dup ++ [0 [dup ++] codireco] rest cons
|
||||||
|
0 0 . ++ [0 [dup ++] codireco] rest cons
|
||||||
|
0 1 . [0 [dup ++] codireco] rest cons
|
||||||
|
0 1 [0 [dup ++] codireco] . rest cons
|
||||||
|
0 1 [[dup ++] codireco] . cons
|
||||||
|
0 [1 [dup ++] codireco] .
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
|
<div class="input">
|
||||||
|
<div class="prompt input_prompt">In [37]:</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="input_area">
|
||||||
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">define</span><span class="p">(</span><span class="s1">'G == [codireco] cons cons'</span><span class="p">)</span>
|
||||||
|
</pre></div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
|
<div class="input">
|
||||||
|
<div class="prompt input_prompt">In [38]:</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="input_area">
|
||||||
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s1">'230 [dup ++] G 5 [x] times pop'</span><span class="p">)</span>
|
||||||
|
</pre></div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="output_wrapper">
|
||||||
|
<div class="output">
|
||||||
|
|
||||||
|
|
||||||
|
<div class="output_area">
|
||||||
|
|
||||||
|
<div class="prompt"></div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="output_subarea output_stream output_stdout output_text">
|
||||||
|
<pre>230 231 232 233 234
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+97
-127
@@ -8,29 +8,36 @@ Cf. jp-reprod.html
|
|||||||
from notebook_preamble import J, V, define
|
from notebook_preamble import J, V, define
|
||||||
```
|
```
|
||||||
|
|
||||||
Consider the `x` combinator `x == dup i`:
|
Consider the `x` combinator:
|
||||||
|
|
||||||
|
x == dup i
|
||||||
|
|
||||||
|
We can apply it to a quoted program consisting of some value `a` and a function `B`:
|
||||||
|
|
||||||
[a B] x
|
[a B] x
|
||||||
[a B] a B
|
[a B] a B
|
||||||
|
|
||||||
Let `B` `swap` the `a` with the quote and run some function `[C]` on it.
|
Let `B` function `swap` the `a` with the quote and run some function `C` on it to generate a new value `b`:
|
||||||
|
|
||||||
|
B == swap [C] dip
|
||||||
|
|
||||||
[a B] a B
|
[a B] a B
|
||||||
[a B] a swap [C] dip
|
[a B] a swap [C] dip
|
||||||
a [a B] [C] dip
|
a [a B] [C] dip
|
||||||
a C [a B]
|
a C [a B]
|
||||||
|
b [a B]
|
||||||
|
|
||||||
Now discard the quoted `a` with `rest` and `cons` the result of `C` on `a` whatever that is:
|
Now discard the quoted `a` with `rest` then `cons` `b`:
|
||||||
|
|
||||||
aC [a B] rest cons
|
b [a B] rest cons
|
||||||
aC [B] cons
|
b [B] cons
|
||||||
[aC B]
|
[b B]
|
||||||
|
|
||||||
Altogether, this is the definition of `B`:
|
Putting it together, this is the definition of `B`:
|
||||||
|
|
||||||
B == swap [C] dip rest cons
|
B == swap [C] dip rest cons
|
||||||
|
|
||||||
We can create a quoted program that generates the Natural numbers (integers 0, 1, 2, ...) by using `0` for `a` and `[dup ++]` for `[C]`:
|
We can create a quoted program that generates the Natural numbers (0, 1, 2, ...) by using `0` for `a` and `[dup ++]` for `[C]`:
|
||||||
|
|
||||||
[0 swap [dup ++] dip rest cons]
|
[0 swap [dup ++] dip rest cons]
|
||||||
|
|
||||||
@@ -92,14 +99,12 @@ V('[0 swap [dup ++] direco] x')
|
|||||||
0 [1 swap [dup ++] direco] .
|
0 [1 swap [dup ++] direco] .
|
||||||
|
|
||||||
|
|
||||||
# Generating Generators
|
# Making Generators
|
||||||
We want to go from:
|
We want to define a function that accepts `a` and `[C]` and builds our quoted program:
|
||||||
|
|
||||||
a [C] G
|
a [C] G
|
||||||
|
-------------------------
|
||||||
to:
|
[a swap [C] direco]
|
||||||
|
|
||||||
[a swap [C] direco]
|
|
||||||
|
|
||||||
Working in reverse:
|
Working in reverse:
|
||||||
|
|
||||||
@@ -114,118 +119,48 @@ Reading from the bottom up:
|
|||||||
G == [direco] cons [swap] swap concat cons
|
G == [direco] cons [swap] swap concat cons
|
||||||
G == [direco] cons [swap] swoncat cons
|
G == [direco] cons [swap] swoncat cons
|
||||||
|
|
||||||
We can try it out:
|
|
||||||
|
|
||||||
0 [dup ++] G
|
|
||||||
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
define('G == [direco] cons [swap] swoncat cons')
|
define('G == [direco] cons [swap] swoncat cons')
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Let's try it out:
|
||||||
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
V('0 [dup ++] G')
|
J('0 [dup ++] G')
|
||||||
```
|
```
|
||||||
|
|
||||||
. 0 [dup ++] G
|
[0 swap [dup ++] direco]
|
||||||
0 . [dup ++] G
|
|
||||||
0 [dup ++] . G
|
|
||||||
0 [dup ++] . [direco] cons [swap] swoncat cons
|
|
||||||
0 [dup ++] [direco] . cons [swap] swoncat cons
|
|
||||||
0 [[dup ++] direco] . [swap] swoncat cons
|
|
||||||
0 [[dup ++] direco] [swap] . swoncat cons
|
|
||||||
0 [[dup ++] direco] [swap] . swap concat cons
|
|
||||||
0 [swap] [[dup ++] direco] . concat cons
|
|
||||||
0 [swap [dup ++] direco] . cons
|
|
||||||
[0 swap [dup ++] direco] .
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
V('0 [dup ++] G x')
|
J('0 [dup ++] G x x x pop')
|
||||||
```
|
```
|
||||||
|
|
||||||
. 0 [dup ++] G x
|
0 1 2
|
||||||
0 . [dup ++] G x
|
|
||||||
0 [dup ++] . G x
|
|
||||||
0 [dup ++] . [direco] cons [swap] swoncat cons x
|
|
||||||
0 [dup ++] [direco] . cons [swap] swoncat cons x
|
|
||||||
0 [[dup ++] direco] . [swap] swoncat cons x
|
|
||||||
0 [[dup ++] direco] [swap] . swoncat cons x
|
|
||||||
0 [[dup ++] direco] [swap] . swap concat cons x
|
|
||||||
0 [swap] [[dup ++] direco] . concat cons x
|
|
||||||
0 [swap [dup ++] direco] . cons x
|
|
||||||
[0 swap [dup ++] direco] . x
|
|
||||||
[0 swap [dup ++] direco] . 0 swap [dup ++] direco
|
|
||||||
[0 swap [dup ++] direco] 0 . swap [dup ++] direco
|
|
||||||
0 [0 swap [dup ++] direco] . [dup ++] direco
|
|
||||||
0 [0 swap [dup ++] direco] [dup ++] . direco
|
|
||||||
0 [0 swap [dup ++] direco] [dup ++] . dip rest cons
|
|
||||||
0 . dup ++ [0 swap [dup ++] direco] rest cons
|
|
||||||
0 0 . ++ [0 swap [dup ++] direco] rest cons
|
|
||||||
0 1 . [0 swap [dup ++] direco] rest cons
|
|
||||||
0 1 [0 swap [dup ++] direco] . rest cons
|
|
||||||
0 1 [swap [dup ++] direco] . cons
|
|
||||||
0 [1 swap [dup ++] direco] .
|
|
||||||
|
|
||||||
|
|
||||||
### Powers of 2
|
### Powers of 2
|
||||||
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
J('1 [dup 1 <<] G x x x x x x x x x')
|
J('1 [dup 1 <<] G x x x x x x x x x pop')
|
||||||
```
|
```
|
||||||
|
|
||||||
1 2 4 8 16 32 64 128 256 [512 swap [dup 1 <<] direco]
|
1 2 4 8 16 32 64 128 256
|
||||||
|
|
||||||
|
|
||||||
# `n [x] times`
|
### `[x] times`
|
||||||
If we have one of these quoted programs we can drive it using `times` with the `x` combinator.
|
If we have one of these quoted programs we can drive it using `times` with the `x` combinator.
|
||||||
|
|
||||||
Let's define a word `n_range` that takes a starting integer and a count and leaves that many consecutive integers on the stack. For example:
|
|
||||||
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
J('23 [dup ++] G 5 [x] times pop')
|
J('23 [dup ++] G 5 [x] times')
|
||||||
```
|
```
|
||||||
|
|
||||||
23 24 25 26 27
|
23 24 25 26 27 [28 swap [dup ++] direco]
|
||||||
|
|
||||||
|
|
||||||
We can use `dip` to untangle `[dup ++] G` from the arguments.
|
|
||||||
|
|
||||||
|
|
||||||
```python
|
|
||||||
J('23 5 [[dup ++] G] dip [x] times pop')
|
|
||||||
```
|
|
||||||
|
|
||||||
23 24 25 26 27
|
|
||||||
|
|
||||||
|
|
||||||
Now that the givens (arguments) are on the left we have the definition we're looking for:
|
|
||||||
|
|
||||||
|
|
||||||
```python
|
|
||||||
define('n_range == [[dup ++] G] dip [x] times pop')
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
```python
|
|
||||||
J('450 10 n_range')
|
|
||||||
```
|
|
||||||
|
|
||||||
450 451 452 453 454 455 456 457 458 459
|
|
||||||
|
|
||||||
|
|
||||||
This is better just using the `times` combinator though...
|
|
||||||
|
|
||||||
|
|
||||||
```python
|
|
||||||
J('450 9 [dup ++] times')
|
|
||||||
```
|
|
||||||
|
|
||||||
450 451 452 453 454 455 456 457 458 459
|
|
||||||
|
|
||||||
|
|
||||||
# Generating Multiples of Three and Five
|
# Generating Multiples of Three and Five
|
||||||
@@ -273,14 +208,6 @@ J('14811 [PE1.1] G')
|
|||||||
[14811 swap [PE1.1] direco]
|
[14811 swap [PE1.1] direco]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
```python
|
|
||||||
J('[14811 swap [PE1.1] direco] x')
|
|
||||||
```
|
|
||||||
|
|
||||||
3 [3702 swap [PE1.1] direco]
|
|
||||||
|
|
||||||
|
|
||||||
...we get a generator that works for seven cycles before it reaches zero:
|
...we get a generator that works for seven cycles before it reaches zero:
|
||||||
|
|
||||||
|
|
||||||
@@ -300,6 +227,14 @@ define('PE1.1.check == dup [pop 14811] [] branch')
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
J('14811 [PE1.1.check PE1.1] G')
|
||||||
|
```
|
||||||
|
|
||||||
|
[14811 swap [PE1.1.check PE1.1] direco]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
J('[14811 swap [PE1.1.check PE1.1] direco] 21 [x] times')
|
J('[14811 swap [PE1.1.check PE1.1] direco] 21 [x] times')
|
||||||
```
|
```
|
||||||
@@ -307,6 +242,8 @@ J('[14811 swap [PE1.1.check PE1.1] direco] 21 [x] times')
|
|||||||
3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 [0 swap [PE1.1.check PE1.1] direco]
|
3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 [0 swap [PE1.1.check PE1.1] direco]
|
||||||
|
|
||||||
|
|
||||||
|
(It would be more efficient to reset the int every seven cycles but that's a little beyond the scope of this article. This solution does extra work, but not much, and we're not using it "in production" as they say.)
|
||||||
|
|
||||||
### Run 466 times
|
### Run 466 times
|
||||||
In the PE1 problem we are asked to sum all the multiples of three and five less than 1000. It's worked out that we need to use all seven numbers sixty-six times and then four more.
|
In the PE1 problem we are asked to sum all the multiples of three and five less than 1000. It's worked out that we need to use all seven numbers sixty-six times and then four more.
|
||||||
|
|
||||||
@@ -322,15 +259,15 @@ If we drive our generator 466 times and sum the stack we get 999.
|
|||||||
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
J('[14811 swap [PE1.1.check PE1.1] dip rest cons] 466 [x] times')
|
J('[14811 swap [PE1.1.check PE1.1] direco] 466 [x] times')
|
||||||
```
|
```
|
||||||
|
|
||||||
3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 [57 swap [PE1.1.check PE1.1] dip rest cons]
|
3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 [57 swap [PE1.1.check PE1.1] direco]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
J('[14811 swap [PE1.1.check PE1.1] dip rest cons] 466 [x] times pop enstacken sum')
|
J('[14811 swap [PE1.1.check PE1.1] direco] 466 [x] times pop enstacken sum')
|
||||||
```
|
```
|
||||||
|
|
||||||
999
|
999
|
||||||
@@ -343,17 +280,7 @@ J('[14811 swap [PE1.1.check PE1.1] dip rest cons] 466 [x] times pop enstacken su
|
|||||||
define('PE1.2 == + dup [+] dip')
|
define('PE1.2 == + dup [+] dip')
|
||||||
```
|
```
|
||||||
|
|
||||||
Now we can add `PE1.2` to the quoted program given to `times`.
|
Now we can add `PE1.2` to the quoted program given to `G`.
|
||||||
|
|
||||||
|
|
||||||
```python
|
|
||||||
J('0 0 [0 swap [PE1.1.check PE1.1] direco] 466 [x [PE1.2] dip] times popop')
|
|
||||||
```
|
|
||||||
|
|
||||||
233168
|
|
||||||
|
|
||||||
|
|
||||||
Or using `G` we can write:
|
|
||||||
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
@@ -401,24 +328,25 @@ And therefore:
|
|||||||
[b+a b a F] [popdd over] infra
|
[b+a b a F] [popdd over] infra
|
||||||
[b b+a b F]
|
[b b+a b F]
|
||||||
|
|
||||||
And lastly:
|
But we can just use `cons` to carry `b+a` into the quote:
|
||||||
|
|
||||||
|
[b a F] b+a [popdd over] cons infra
|
||||||
|
[b a F] [b+a popdd over] infra
|
||||||
|
[b b+a b F]
|
||||||
|
|
||||||
|
Lastly:
|
||||||
|
|
||||||
[b b+a b F] uncons
|
[b b+a b F] uncons
|
||||||
b [b+a b F]
|
b [b+a b F]
|
||||||
|
|
||||||
Done.
|
|
||||||
|
|
||||||
Putting it all together:
|
Putting it all together:
|
||||||
|
|
||||||
F == + swons [popdd over] infra uncons
|
F == + [popdd over] cons infra uncons
|
||||||
|
|
||||||
And:
|
|
||||||
|
|
||||||
fib_gen == [1 1 F]
|
fib_gen == [1 1 F]
|
||||||
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
define('fib == + swons [popdd over] infra uncons')
|
define('fib == + [popdd over] cons infra uncons')
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
@@ -435,7 +363,8 @@ J('fib_gen 10 [x] times')
|
|||||||
|
|
||||||
|
|
||||||
### Project Euler Problem Two
|
### Project Euler Problem Two
|
||||||
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
|
By considering the terms in the Fibonacci sequence whose values do not exceed four million,
|
||||||
|
find the sum of the even-valued terms.
|
||||||
|
|
||||||
Now that we have a generator for the Fibonacci sequence, we need a function that adds a term in the sequence to a sum if it is even, and `pop`s it otherwise.
|
Now that we have a generator for the Fibonacci sequence, we need a function that adds a term in the sequence to a sum if it is even, and `pop`s it otherwise.
|
||||||
|
|
||||||
@@ -536,3 +465,44 @@ J('0 [1 0 fib] PE2.2 [pop >4M] [popop] [[PE2.1] dip PE2.2] primrec')
|
|||||||
|
|
||||||
# How to compile these?
|
# How to compile these?
|
||||||
You would probably start with a special version of `G`, and perhaps modifications to the default `x`?
|
You would probably start with a special version of `G`, and perhaps modifications to the default `x`?
|
||||||
|
|
||||||
|
# An Interesting Variation
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
define('codireco == cons dip rest cons')
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
V('[0 [dup ++] codireco] x')
|
||||||
|
```
|
||||||
|
|
||||||
|
. [0 [dup ++] codireco] x
|
||||||
|
[0 [dup ++] codireco] . x
|
||||||
|
[0 [dup ++] codireco] . 0 [dup ++] codireco
|
||||||
|
[0 [dup ++] codireco] 0 . [dup ++] codireco
|
||||||
|
[0 [dup ++] codireco] 0 [dup ++] . codireco
|
||||||
|
[0 [dup ++] codireco] 0 [dup ++] . cons dip rest cons
|
||||||
|
[0 [dup ++] codireco] [0 dup ++] . dip rest cons
|
||||||
|
. 0 dup ++ [0 [dup ++] codireco] rest cons
|
||||||
|
0 . dup ++ [0 [dup ++] codireco] rest cons
|
||||||
|
0 0 . ++ [0 [dup ++] codireco] rest cons
|
||||||
|
0 1 . [0 [dup ++] codireco] rest cons
|
||||||
|
0 1 [0 [dup ++] codireco] . rest cons
|
||||||
|
0 1 [[dup ++] codireco] . cons
|
||||||
|
0 [1 [dup ++] codireco] .
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
define('G == [codireco] cons cons')
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
J('230 [dup ++] G 5 [x] times pop')
|
||||||
|
```
|
||||||
|
|
||||||
|
230 231 232 233 234
|
||||||
|
|
||||||
|
|||||||
+115
-151
@@ -8,41 +8,49 @@ Cf. jp-reprod.html
|
|||||||
|
|
||||||
from notebook_preamble import J, V, define
|
from notebook_preamble import J, V, define
|
||||||
|
|
||||||
Consider the ``x`` combinator ``x == dup i``:
|
Consider the ``x`` combinator:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
x == dup i
|
||||||
|
|
||||||
|
We can apply it to a quoted program consisting of some value ``a`` and a
|
||||||
|
function ``B``:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
[a B] x
|
[a B] x
|
||||||
[a B] a B
|
[a B] a B
|
||||||
|
|
||||||
Let ``B`` ``swap`` the ``a`` with the quote and run some function
|
Let ``B`` function ``swap`` the ``a`` with the quote and run some
|
||||||
``[C]`` on it.
|
function ``C`` on it to generate a new value ``b``:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
|
B == swap [C] dip
|
||||||
|
|
||||||
[a B] a B
|
[a B] a B
|
||||||
[a B] a swap [C] dip
|
[a B] a swap [C] dip
|
||||||
a [a B] [C] dip
|
a [a B] [C] dip
|
||||||
a C [a B]
|
a C [a B]
|
||||||
|
b [a B]
|
||||||
|
|
||||||
Now discard the quoted ``a`` with ``rest`` and ``cons`` the result of
|
Now discard the quoted ``a`` with ``rest`` then ``cons`` ``b``:
|
||||||
``C`` on ``a`` whatever that is:
|
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
aC [a B] rest cons
|
b [a B] rest cons
|
||||||
aC [B] cons
|
b [B] cons
|
||||||
[aC B]
|
[b B]
|
||||||
|
|
||||||
Altogether, this is the definition of ``B``:
|
Putting it together, this is the definition of ``B``:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
B == swap [C] dip rest cons
|
B == swap [C] dip rest cons
|
||||||
|
|
||||||
We can create a quoted program that generates the Natural numbers
|
We can create a quoted program that generates the Natural numbers (0, 1,
|
||||||
(integers 0, 1, 2, ...) by using ``0`` for ``a`` and ``[dup ++]`` for
|
2, ...) by using ``0`` for ``a`` and ``[dup ++]`` for ``[C]``:
|
||||||
``[C]``:
|
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
@@ -113,20 +121,17 @@ After one application of ``x`` the quoted program contains ``1`` and
|
|||||||
0 [1 swap [dup ++] direco] .
|
0 [1 swap [dup ++] direco] .
|
||||||
|
|
||||||
|
|
||||||
Generating Generators
|
Making Generators
|
||||||
=====================
|
=================
|
||||||
|
|
||||||
We want to go from:
|
We want to define a function that accepts ``a`` and ``[C]`` and builds
|
||||||
|
our quoted program:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
a [C] G
|
a [C] G
|
||||||
|
-------------------------
|
||||||
to:
|
[a swap [C] direco]
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
[a swap [C] direco]
|
|
||||||
|
|
||||||
Working in reverse:
|
Working in reverse:
|
||||||
|
|
||||||
@@ -145,65 +150,30 @@ Reading from the bottom up:
|
|||||||
G == [direco] cons [swap] swap concat cons
|
G == [direco] cons [swap] swap concat cons
|
||||||
G == [direco] cons [swap] swoncat cons
|
G == [direco] cons [swap] swoncat cons
|
||||||
|
|
||||||
We can try it out:
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
0 [dup ++] G
|
|
||||||
|
|
||||||
.. code:: ipython2
|
.. code:: ipython2
|
||||||
|
|
||||||
define('G == [direco] cons [swap] swoncat cons')
|
define('G == [direco] cons [swap] swoncat cons')
|
||||||
|
|
||||||
|
Let's try it out:
|
||||||
|
|
||||||
.. code:: ipython2
|
.. code:: ipython2
|
||||||
|
|
||||||
V('0 [dup ++] G')
|
J('0 [dup ++] G')
|
||||||
|
|
||||||
|
|
||||||
.. parsed-literal::
|
.. parsed-literal::
|
||||||
|
|
||||||
. 0 [dup ++] G
|
[0 swap [dup ++] direco]
|
||||||
0 . [dup ++] G
|
|
||||||
0 [dup ++] . G
|
|
||||||
0 [dup ++] . [direco] cons [swap] swoncat cons
|
|
||||||
0 [dup ++] [direco] . cons [swap] swoncat cons
|
|
||||||
0 [[dup ++] direco] . [swap] swoncat cons
|
|
||||||
0 [[dup ++] direco] [swap] . swoncat cons
|
|
||||||
0 [[dup ++] direco] [swap] . swap concat cons
|
|
||||||
0 [swap] [[dup ++] direco] . concat cons
|
|
||||||
0 [swap [dup ++] direco] . cons
|
|
||||||
[0 swap [dup ++] direco] .
|
|
||||||
|
|
||||||
|
|
||||||
.. code:: ipython2
|
.. code:: ipython2
|
||||||
|
|
||||||
V('0 [dup ++] G x')
|
J('0 [dup ++] G x x x pop')
|
||||||
|
|
||||||
|
|
||||||
.. parsed-literal::
|
.. parsed-literal::
|
||||||
|
|
||||||
. 0 [dup ++] G x
|
0 1 2
|
||||||
0 . [dup ++] G x
|
|
||||||
0 [dup ++] . G x
|
|
||||||
0 [dup ++] . [direco] cons [swap] swoncat cons x
|
|
||||||
0 [dup ++] [direco] . cons [swap] swoncat cons x
|
|
||||||
0 [[dup ++] direco] . [swap] swoncat cons x
|
|
||||||
0 [[dup ++] direco] [swap] . swoncat cons x
|
|
||||||
0 [[dup ++] direco] [swap] . swap concat cons x
|
|
||||||
0 [swap] [[dup ++] direco] . concat cons x
|
|
||||||
0 [swap [dup ++] direco] . cons x
|
|
||||||
[0 swap [dup ++] direco] . x
|
|
||||||
[0 swap [dup ++] direco] . 0 swap [dup ++] direco
|
|
||||||
[0 swap [dup ++] direco] 0 . swap [dup ++] direco
|
|
||||||
0 [0 swap [dup ++] direco] . [dup ++] direco
|
|
||||||
0 [0 swap [dup ++] direco] [dup ++] . direco
|
|
||||||
0 [0 swap [dup ++] direco] [dup ++] . dip rest cons
|
|
||||||
0 . dup ++ [0 swap [dup ++] direco] rest cons
|
|
||||||
0 0 . ++ [0 swap [dup ++] direco] rest cons
|
|
||||||
0 1 . [0 swap [dup ++] direco] rest cons
|
|
||||||
0 1 [0 swap [dup ++] direco] . rest cons
|
|
||||||
0 1 [swap [dup ++] direco] . cons
|
|
||||||
0 [1 swap [dup ++] direco] .
|
|
||||||
|
|
||||||
|
|
||||||
Powers of 2
|
Powers of 2
|
||||||
@@ -211,73 +181,28 @@ Powers of 2
|
|||||||
|
|
||||||
.. code:: ipython2
|
.. code:: ipython2
|
||||||
|
|
||||||
J('1 [dup 1 <<] G x x x x x x x x x')
|
J('1 [dup 1 <<] G x x x x x x x x x pop')
|
||||||
|
|
||||||
|
|
||||||
.. parsed-literal::
|
.. parsed-literal::
|
||||||
|
|
||||||
1 2 4 8 16 32 64 128 256 [512 swap [dup 1 <<] direco]
|
1 2 4 8 16 32 64 128 256
|
||||||
|
|
||||||
|
|
||||||
``n [x] times``
|
``[x] times``
|
||||||
===============
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
If we have one of these quoted programs we can drive it using ``times``
|
If we have one of these quoted programs we can drive it using ``times``
|
||||||
with the ``x`` combinator.
|
with the ``x`` combinator.
|
||||||
|
|
||||||
Let's define a word ``n_range`` that takes a starting integer and a
|
|
||||||
count and leaves that many consecutive integers on the stack. For
|
|
||||||
example:
|
|
||||||
|
|
||||||
.. code:: ipython2
|
.. code:: ipython2
|
||||||
|
|
||||||
J('23 [dup ++] G 5 [x] times pop')
|
J('23 [dup ++] G 5 [x] times')
|
||||||
|
|
||||||
|
|
||||||
.. parsed-literal::
|
.. parsed-literal::
|
||||||
|
|
||||||
23 24 25 26 27
|
23 24 25 26 27 [28 swap [dup ++] direco]
|
||||||
|
|
||||||
|
|
||||||
We can use ``dip`` to untangle ``[dup ++] G`` from the arguments.
|
|
||||||
|
|
||||||
.. code:: ipython2
|
|
||||||
|
|
||||||
J('23 5 [[dup ++] G] dip [x] times pop')
|
|
||||||
|
|
||||||
|
|
||||||
.. parsed-literal::
|
|
||||||
|
|
||||||
23 24 25 26 27
|
|
||||||
|
|
||||||
|
|
||||||
Now that the givens (arguments) are on the left we have the definition
|
|
||||||
we're looking for:
|
|
||||||
|
|
||||||
.. code:: ipython2
|
|
||||||
|
|
||||||
define('n_range == [[dup ++] G] dip [x] times pop')
|
|
||||||
|
|
||||||
.. code:: ipython2
|
|
||||||
|
|
||||||
J('450 10 n_range')
|
|
||||||
|
|
||||||
|
|
||||||
.. parsed-literal::
|
|
||||||
|
|
||||||
450 451 452 453 454 455 456 457 458 459
|
|
||||||
|
|
||||||
|
|
||||||
This is better just using the ``times`` combinator though...
|
|
||||||
|
|
||||||
.. code:: ipython2
|
|
||||||
|
|
||||||
J('450 9 [dup ++] times')
|
|
||||||
|
|
||||||
|
|
||||||
.. parsed-literal::
|
|
||||||
|
|
||||||
450 451 452 453 454 455 456 457 458 459
|
|
||||||
|
|
||||||
|
|
||||||
Generating Multiples of Three and Five
|
Generating Multiples of Three and Five
|
||||||
@@ -338,16 +263,6 @@ If we plug ``14811`` and ``[PE1.1]`` into our generator form...
|
|||||||
[14811 swap [PE1.1] direco]
|
[14811 swap [PE1.1] direco]
|
||||||
|
|
||||||
|
|
||||||
.. code:: ipython2
|
|
||||||
|
|
||||||
J('[14811 swap [PE1.1] direco] x')
|
|
||||||
|
|
||||||
|
|
||||||
.. parsed-literal::
|
|
||||||
|
|
||||||
3 [3702 swap [PE1.1] direco]
|
|
||||||
|
|
||||||
|
|
||||||
...we get a generator that works for seven cycles before it reaches
|
...we get a generator that works for seven cycles before it reaches
|
||||||
zero:
|
zero:
|
||||||
|
|
||||||
@@ -371,6 +286,16 @@ if so.
|
|||||||
|
|
||||||
define('PE1.1.check == dup [pop 14811] [] branch')
|
define('PE1.1.check == dup [pop 14811] [] branch')
|
||||||
|
|
||||||
|
.. code:: ipython2
|
||||||
|
|
||||||
|
J('14811 [PE1.1.check PE1.1] G')
|
||||||
|
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
[14811 swap [PE1.1.check PE1.1] direco]
|
||||||
|
|
||||||
|
|
||||||
.. code:: ipython2
|
.. code:: ipython2
|
||||||
|
|
||||||
J('[14811 swap [PE1.1.check PE1.1] direco] 21 [x] times')
|
J('[14811 swap [PE1.1.check PE1.1] direco] 21 [x] times')
|
||||||
@@ -381,6 +306,11 @@ if so.
|
|||||||
3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 [0 swap [PE1.1.check PE1.1] direco]
|
3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 [0 swap [PE1.1.check PE1.1] direco]
|
||||||
|
|
||||||
|
|
||||||
|
(It would be more efficient to reset the int every seven cycles but
|
||||||
|
that's a little beyond the scope of this article. This solution does
|
||||||
|
extra work, but not much, and we're not using it "in production" as they
|
||||||
|
say.)
|
||||||
|
|
||||||
Run 466 times
|
Run 466 times
|
||||||
~~~~~~~~~~~~~
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
@@ -402,17 +332,17 @@ If we drive our generator 466 times and sum the stack we get 999.
|
|||||||
|
|
||||||
.. code:: ipython2
|
.. code:: ipython2
|
||||||
|
|
||||||
J('[14811 swap [PE1.1.check PE1.1] dip rest cons] 466 [x] times')
|
J('[14811 swap [PE1.1.check PE1.1] direco] 466 [x] times')
|
||||||
|
|
||||||
|
|
||||||
.. parsed-literal::
|
.. parsed-literal::
|
||||||
|
|
||||||
3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 [57 swap [PE1.1.check PE1.1] dip rest cons]
|
3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 [57 swap [PE1.1.check PE1.1] direco]
|
||||||
|
|
||||||
|
|
||||||
.. code:: ipython2
|
.. code:: ipython2
|
||||||
|
|
||||||
J('[14811 swap [PE1.1.check PE1.1] dip rest cons] 466 [x] times pop enstacken sum')
|
J('[14811 swap [PE1.1.check PE1.1] direco] 466 [x] times pop enstacken sum')
|
||||||
|
|
||||||
|
|
||||||
.. parsed-literal::
|
.. parsed-literal::
|
||||||
@@ -427,19 +357,7 @@ Project Euler Problem One
|
|||||||
|
|
||||||
define('PE1.2 == + dup [+] dip')
|
define('PE1.2 == + dup [+] dip')
|
||||||
|
|
||||||
Now we can add ``PE1.2`` to the quoted program given to ``times``.
|
Now we can add ``PE1.2`` to the quoted program given to ``G``.
|
||||||
|
|
||||||
.. code:: ipython2
|
|
||||||
|
|
||||||
J('0 0 [0 swap [PE1.1.check PE1.1] direco] 466 [x [PE1.2] dip] times popop')
|
|
||||||
|
|
||||||
|
|
||||||
.. parsed-literal::
|
|
||||||
|
|
||||||
233168
|
|
||||||
|
|
||||||
|
|
||||||
Or using ``G`` we can write:
|
|
||||||
|
|
||||||
.. code:: ipython2
|
.. code:: ipython2
|
||||||
|
|
||||||
@@ -507,30 +425,31 @@ And therefore:
|
|||||||
[b+a b a F] [popdd over] infra
|
[b+a b a F] [popdd over] infra
|
||||||
[b b+a b F]
|
[b b+a b F]
|
||||||
|
|
||||||
And lastly:
|
But we can just use ``cons`` to carry ``b+a`` into the quote:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[b a F] b+a [popdd over] cons infra
|
||||||
|
[b a F] [b+a popdd over] infra
|
||||||
|
[b b+a b F]
|
||||||
|
|
||||||
|
Lastly:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
[b b+a b F] uncons
|
[b b+a b F] uncons
|
||||||
b [b+a b F]
|
b [b+a b F]
|
||||||
|
|
||||||
Done.
|
|
||||||
|
|
||||||
Putting it all together:
|
Putting it all together:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
F == + swons [popdd over] infra uncons
|
F == + [popdd over] cons infra uncons
|
||||||
|
|
||||||
And:
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
fib_gen == [1 1 F]
|
fib_gen == [1 1 F]
|
||||||
|
|
||||||
.. code:: ipython2
|
.. code:: ipython2
|
||||||
|
|
||||||
define('fib == + swons [popdd over] infra uncons')
|
define('fib == + [popdd over] cons infra uncons')
|
||||||
|
|
||||||
.. code:: ipython2
|
.. code:: ipython2
|
||||||
|
|
||||||
@@ -551,7 +470,8 @@ Project Euler Problem Two
|
|||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
|
By considering the terms in the Fibonacci sequence whose values do not exceed four million,
|
||||||
|
find the sum of the even-valued terms.
|
||||||
|
|
||||||
Now that we have a generator for the Fibonacci sequence, we need a
|
Now that we have a generator for the Fibonacci sequence, we need a
|
||||||
function that adds a term in the sequence to a sum if it is even, and
|
function that adds a term in the sequence to a sum if it is even, and
|
||||||
@@ -673,3 +593,47 @@ How to compile these?
|
|||||||
|
|
||||||
You would probably start with a special version of ``G``, and perhaps
|
You would probably start with a special version of ``G``, and perhaps
|
||||||
modifications to the default ``x``?
|
modifications to the default ``x``?
|
||||||
|
|
||||||
|
An Interesting Variation
|
||||||
|
========================
|
||||||
|
|
||||||
|
.. code:: ipython2
|
||||||
|
|
||||||
|
define('codireco == cons dip rest cons')
|
||||||
|
|
||||||
|
.. code:: ipython2
|
||||||
|
|
||||||
|
V('[0 [dup ++] codireco] x')
|
||||||
|
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
. [0 [dup ++] codireco] x
|
||||||
|
[0 [dup ++] codireco] . x
|
||||||
|
[0 [dup ++] codireco] . 0 [dup ++] codireco
|
||||||
|
[0 [dup ++] codireco] 0 . [dup ++] codireco
|
||||||
|
[0 [dup ++] codireco] 0 [dup ++] . codireco
|
||||||
|
[0 [dup ++] codireco] 0 [dup ++] . cons dip rest cons
|
||||||
|
[0 [dup ++] codireco] [0 dup ++] . dip rest cons
|
||||||
|
. 0 dup ++ [0 [dup ++] codireco] rest cons
|
||||||
|
0 . dup ++ [0 [dup ++] codireco] rest cons
|
||||||
|
0 0 . ++ [0 [dup ++] codireco] rest cons
|
||||||
|
0 1 . [0 [dup ++] codireco] rest cons
|
||||||
|
0 1 [0 [dup ++] codireco] . rest cons
|
||||||
|
0 1 [[dup ++] codireco] . cons
|
||||||
|
0 [1 [dup ++] codireco] .
|
||||||
|
|
||||||
|
|
||||||
|
.. code:: ipython2
|
||||||
|
|
||||||
|
define('G == [codireco] cons cons')
|
||||||
|
|
||||||
|
.. code:: ipython2
|
||||||
|
|
||||||
|
J('230 [dup ++] G 5 [x] times pop')
|
||||||
|
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
230 231 232 233 234
|
||||||
|
|
||||||
|
|||||||
@@ -13729,7 +13729,7 @@ tails == [] [not] [rest swons] [rest] paramorphism</code></pre>
|
|||||||
<li>A predicate <code>P :: A -> Bool</code> to detect the base case</li>
|
<li>A predicate <code>P :: A -> Bool</code> to detect the base case</li>
|
||||||
<li>A base case value <code>c :: B</code></li>
|
<li>A base case value <code>c :: B</code></li>
|
||||||
</ul>
|
</ul>
|
||||||
<h3 id="Hylo--Ana-,-Cata-">Hylo- Ana-, Cata-<a class="anchor-link" href="#Hylo--Ana-,-Cata-">¶</a></h3>
|
<h3 id="Hylo-,-Ana-,-Cata-">Hylo-, Ana-, Cata-<a class="anchor-link" href="#Hylo-,-Ana-,-Cata-">¶</a></h3>
|
||||||
<pre><code>w/ G :: A -> (A, B)
|
<pre><code>w/ G :: A -> (A, B)
|
||||||
|
|
||||||
H == [P ] [pop c ] [G ] [dip F ] genrec
|
H == [P ] [pop c ] [G ] [dip F ] genrec
|
||||||
@@ -13854,7 +13854,7 @@ H == c swap [P] [pop] [ [F] dupdip G] [i] genrec
|
|||||||
</div>
|
</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="text_cell_render border-box-sizing rendered_html">
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
<h3 id="4">4<a class="anchor-link" href="#4">¶</a></h3><p>And, last but not least, if you can combine as you go, starting with c, and the combiner needs to work on the current item this is the form:</p>
|
<h3 id="4">4<a class="anchor-link" href="#4">¶</a></h3><p>And, last but not least, if you can combine as you go, starting with c, and the combiner needs to work on the current item, this is the form:</p>
|
||||||
|
|
||||||
<pre><code>W == c swap [P] [pop] [[F] dupdip G] primrec
|
<pre><code>W == c swap [P] [pop] [[F] dupdip G] primrec
|
||||||
|
|
||||||
|
|||||||
@@ -1432,7 +1432,7 @@ Our story so far...
|
|||||||
- A base case value `c :: B`
|
- A base case value `c :: B`
|
||||||
|
|
||||||
|
|
||||||
### Hylo- Ana-, Cata-
|
### Hylo-, Ana-, Cata-
|
||||||
|
|
||||||
w/ G :: A -> (A, B)
|
w/ G :: A -> (A, B)
|
||||||
|
|
||||||
@@ -1526,7 +1526,7 @@ If the combiner and the generator both need to work on the current value then `d
|
|||||||
... c a'' F a' F a F
|
... c a'' F a' F a F
|
||||||
|
|
||||||
### 4
|
### 4
|
||||||
And, last but not least, if you can combine as you go, starting with c, and the combiner needs to work on the current item this is the form:
|
And, last but not least, if you can combine as you go, starting with c, and the combiner needs to work on the current item, this is the form:
|
||||||
|
|
||||||
W == c swap [P] [pop] [[F] dupdip G] primrec
|
W == c swap [P] [pop] [[F] dupdip G] primrec
|
||||||
|
|
||||||
|
|||||||
@@ -1571,8 +1571,8 @@ Our story so far...
|
|||||||
- A predicate ``P :: A -> Bool`` to detect the base case
|
- A predicate ``P :: A -> Bool`` to detect the base case
|
||||||
- A base case value ``c :: B``
|
- A base case value ``c :: B``
|
||||||
|
|
||||||
Hylo- Ana-, Cata-
|
Hylo-, Ana-, Cata-
|
||||||
~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
@@ -1706,7 +1706,7 @@ one item instead of two (the b is instead the duplicate of a.)
|
|||||||
~
|
~
|
||||||
|
|
||||||
And, last but not least, if you can combine as you go, starting with c,
|
And, last but not least, if you can combine as you go, starting with c,
|
||||||
and the combiner needs to work on the current item this is the form:
|
and the combiner needs to work on the current item, this is the form:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+709
-24
@@ -11920,10 +11920,10 @@ key left-keys right-keys
|
|||||||
</div>
|
</div>
|
||||||
<div class="cell border-box-sizing code_cell rendered">
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<div class="prompt input_prompt">In [1]:</div>
|
<div class="prompt input_prompt">In [6]:</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="input_area">
|
<div class="input_area">
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="kn">from</span> <span class="nn">notebook_preamble</span> <span class="kn">import</span> <span class="n">J</span><span class="p">,</span> <span class="n">V</span><span class="p">,</span> <span class="n">define</span>
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="kn">from</span> <span class="nn">notebook_preamble</span> <span class="kn">import</span> <span class="n">D</span><span class="p">,</span> <span class="n">J</span><span class="p">,</span> <span class="n">V</span><span class="p">,</span> <span class="n">define</span><span class="p">,</span> <span class="n">DefinitionWrapper</span>
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -13008,7 +13008,7 @@ E == pop swap roll< rest rest cons cons
|
|||||||
</div>
|
</div>
|
||||||
<div class="cell border-box-sizing code_cell rendered">
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<div class="prompt input_prompt">In [30]:</div>
|
<div class="prompt input_prompt">In [11]:</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="input_area">
|
<div class="input_area">
|
||||||
<div class=" highlight hl-ipython2"><pre><span></span><span class="kn">from</span> <span class="nn">joy.library</span> <span class="kn">import</span> <span class="n">FunctionWrapper</span>
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="kn">from</span> <span class="nn">joy.library</span> <span class="kn">import</span> <span class="n">FunctionWrapper</span>
|
||||||
@@ -13018,6 +13018,22 @@ E == pop swap roll< rest rest cons cons
|
|||||||
|
|
||||||
<span class="nd">@FunctionWrapper</span>
|
<span class="nd">@FunctionWrapper</span>
|
||||||
<span class="k">def</span> <span class="nf">cmp_</span><span class="p">(</span><span class="n">stack</span><span class="p">,</span> <span class="n">expression</span><span class="p">,</span> <span class="n">dictionary</span><span class="p">):</span>
|
<span class="k">def</span> <span class="nf">cmp_</span><span class="p">(</span><span class="n">stack</span><span class="p">,</span> <span class="n">expression</span><span class="p">,</span> <span class="n">dictionary</span><span class="p">):</span>
|
||||||
|
<span class="sd">'''</span>
|
||||||
|
<span class="sd"> cmp takes two values and three quoted programs on the stack and runs</span>
|
||||||
|
<span class="sd"> one of the three depending on the results of comparing the two values:</span>
|
||||||
|
|
||||||
|
<span class="sd"> a b [G] [E] [L] cmp</span>
|
||||||
|
<span class="sd"> ------------------------- a > b</span>
|
||||||
|
<span class="sd"> G</span>
|
||||||
|
|
||||||
|
<span class="sd"> a b [G] [E] [L] cmp</span>
|
||||||
|
<span class="sd"> ------------------------- a = b</span>
|
||||||
|
<span class="sd"> E</span>
|
||||||
|
|
||||||
|
<span class="sd"> a b [G] [E] [L] cmp</span>
|
||||||
|
<span class="sd"> ------------------------- a < b</span>
|
||||||
|
<span class="sd"> L</span>
|
||||||
|
<span class="sd"> '''</span>
|
||||||
<span class="n">L</span><span class="p">,</span> <span class="p">(</span><span class="n">E</span><span class="p">,</span> <span class="p">(</span><span class="n">G</span><span class="p">,</span> <span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">stack</span><span class="p">))))</span> <span class="o">=</span> <span class="n">stack</span>
|
<span class="n">L</span><span class="p">,</span> <span class="p">(</span><span class="n">E</span><span class="p">,</span> <span class="p">(</span><span class="n">G</span><span class="p">,</span> <span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">stack</span><span class="p">))))</span> <span class="o">=</span> <span class="n">stack</span>
|
||||||
<span class="n">expression</span> <span class="o">=</span> <span class="n">pushback</span><span class="p">(</span><span class="n">G</span> <span class="k">if</span> <span class="n">a</span> <span class="o">></span> <span class="n">b</span> <span class="k">else</span> <span class="n">L</span> <span class="k">if</span> <span class="n">a</span> <span class="o"><</span> <span class="n">b</span> <span class="k">else</span> <span class="n">E</span><span class="p">,</span> <span class="n">expression</span><span class="p">)</span>
|
<span class="n">expression</span> <span class="o">=</span> <span class="n">pushback</span><span class="p">(</span><span class="n">G</span> <span class="k">if</span> <span class="n">a</span> <span class="o">></span> <span class="n">b</span> <span class="k">else</span> <span class="n">L</span> <span class="k">if</span> <span class="n">a</span> <span class="o"><</span> <span class="n">b</span> <span class="k">else</span> <span class="n">E</span><span class="p">,</span> <span class="n">expression</span><span class="p">)</span>
|
||||||
<span class="k">return</span> <span class="n">stack</span><span class="p">,</span> <span class="n">expression</span><span class="p">,</span> <span class="n">dictionary</span>
|
<span class="k">return</span> <span class="n">stack</span><span class="p">,</span> <span class="n">expression</span><span class="p">,</span> <span class="n">dictionary</span>
|
||||||
@@ -13030,6 +13046,59 @@ E == pop swap roll< rest rest cons cons
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
|
<div class="input">
|
||||||
|
<div class="prompt input_prompt">In [14]:</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="input_area">
|
||||||
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="kn">from</span> <span class="nn">joy.library</span> <span class="kn">import</span> <span class="n">FunctionWrapper</span><span class="p">,</span> <span class="n">S_ifte</span>
|
||||||
|
|
||||||
|
|
||||||
|
<span class="nd">@FunctionWrapper</span>
|
||||||
|
<span class="k">def</span> <span class="nf">cond</span><span class="p">(</span><span class="n">stack</span><span class="p">,</span> <span class="n">expression</span><span class="p">,</span> <span class="n">dictionary</span><span class="p">):</span>
|
||||||
|
<span class="sd">'''</span>
|
||||||
|
<span class="sd"> like a case statement; works by rewriting into a chain of ifte.</span>
|
||||||
|
|
||||||
|
<span class="sd"> [..[[Bi] Ti]..[D]] -> ...</span>
|
||||||
|
|
||||||
|
|
||||||
|
<span class="sd"> [[[B0] T0] [[B1] T1] [D]] cond</span>
|
||||||
|
<span class="sd"> -----------------------------------------</span>
|
||||||
|
<span class="sd"> [B0] [T0] [[B1] [T1] [D] ifte] ifte</span>
|
||||||
|
|
||||||
|
<span class="sd"> '''</span>
|
||||||
|
<span class="n">conditions</span><span class="p">,</span> <span class="n">stack</span> <span class="o">=</span> <span class="n">stack</span>
|
||||||
|
<span class="k">if</span> <span class="n">conditions</span><span class="p">:</span>
|
||||||
|
<span class="n">expression</span> <span class="o">=</span> <span class="n">_cond</span><span class="p">(</span><span class="n">conditions</span><span class="p">,</span> <span class="n">expression</span><span class="p">)</span>
|
||||||
|
<span class="k">try</span><span class="p">:</span>
|
||||||
|
<span class="c1"># Attempt to preload the args to first ifte.</span>
|
||||||
|
<span class="p">(</span><span class="n">P</span><span class="p">,</span> <span class="p">(</span><span class="n">T</span><span class="p">,</span> <span class="p">(</span><span class="n">E</span><span class="p">,</span> <span class="n">expression</span><span class="p">)))</span> <span class="o">=</span> <span class="n">expression</span>
|
||||||
|
<span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
|
||||||
|
<span class="c1"># If, for any reason, the argument to cond should happen to contain</span>
|
||||||
|
<span class="c1"># only the default clause then this optimization will fail.</span>
|
||||||
|
<span class="k">pass</span>
|
||||||
|
<span class="k">else</span><span class="p">:</span>
|
||||||
|
<span class="n">stack</span> <span class="o">=</span> <span class="p">(</span><span class="n">E</span><span class="p">,</span> <span class="p">(</span><span class="n">T</span><span class="p">,</span> <span class="p">(</span><span class="n">P</span><span class="p">,</span> <span class="n">stack</span><span class="p">)))</span>
|
||||||
|
<span class="k">return</span> <span class="n">stack</span><span class="p">,</span> <span class="n">expression</span><span class="p">,</span> <span class="n">dictionary</span>
|
||||||
|
|
||||||
|
|
||||||
|
<span class="k">def</span> <span class="nf">_cond</span><span class="p">(</span><span class="n">conditions</span><span class="p">,</span> <span class="n">expression</span><span class="p">):</span>
|
||||||
|
<span class="p">(</span><span class="n">clause</span><span class="p">,</span> <span class="n">rest</span><span class="p">)</span> <span class="o">=</span> <span class="n">conditions</span>
|
||||||
|
<span class="k">if</span> <span class="ow">not</span> <span class="n">rest</span><span class="p">:</span> <span class="c1"># clause is [D]</span>
|
||||||
|
<span class="k">return</span> <span class="n">clause</span>
|
||||||
|
<span class="n">P</span><span class="p">,</span> <span class="n">T</span> <span class="o">=</span> <span class="n">clause</span>
|
||||||
|
<span class="k">return</span> <span class="p">(</span><span class="n">P</span><span class="p">,</span> <span class="p">(</span><span class="n">T</span><span class="p">,</span> <span class="p">(</span><span class="n">_cond</span><span class="p">(</span><span class="n">rest</span><span class="p">,</span> <span class="p">()),</span> <span class="p">(</span><span class="n">S_ifte</span><span class="p">,</span> <span class="n">expression</span><span class="p">))))</span>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<span class="n">D</span><span class="p">[</span><span class="s1">'cond'</span><span class="p">]</span> <span class="o">=</span> <span class="n">cond</span>
|
||||||
|
</pre></div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="cell border-box-sizing code_cell rendered">
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
<div class="input">
|
<div class="input">
|
||||||
@@ -13726,15 +13795,15 @@ BTree-get == [pop not] swap [] [P [T>] [E] [T<] cmp] genrec</code></pre>
|
|||||||
</div>
|
</div>
|
||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="text_cell_render border-box-sizing rendered_html">
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
<h1 id="TODO:-BTree-delete">TODO: BTree-delete<a class="anchor-link" href="#TODO:-BTree-delete">¶</a></h1><p>Then, once we have add, get, and delete we can see about abstracting them.</p>
|
<h1 id="BTree-delete">BTree-delete<a class="anchor-link" href="#BTree-delete">¶</a></h1><p>Now let's write a function that can return a tree datastructure with a key, value pair deleted:</p>
|
||||||
|
|
||||||
<pre><code> tree key [E] BTree-delete
|
<pre><code> tree key BTree-delete
|
||||||
---------------------------- key in tree
|
---------------------------
|
||||||
tree
|
tree
|
||||||
|
|
||||||
tree key [E] BTree-delete
|
|
||||||
---------------------------- key not in tree
|
</code></pre>
|
||||||
tree key E</code></pre>
|
<p>If the key is not in tree it just returns the tree unchanged.</p>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -13745,18 +13814,7 @@ BTree-get == [pop not] swap [] [P [T>] [E] [T<] cmp] genrec</code></pre>
|
|||||||
<div class="text_cell_render border-box-sizing rendered_html">
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
<p>So:</p>
|
<p>So:</p>
|
||||||
|
|
||||||
<pre><code>BTree-delete == [pop not] [] [R0] [R1] genrec
|
<pre><code>BTree-Delete == [pop not] swap [R0] [R1] genrec</code></pre>
|
||||||
|
|
||||||
</code></pre>
|
|
||||||
<p>And:</p>
|
|
||||||
|
|
||||||
<pre><code>[n_key n_value left right] key R0 [BTree-get] R1
|
|
||||||
[n_key n_value left right] key [dup first] dip [BTree-get] R1
|
|
||||||
[n_key n_value left right] n_key key [BTree-get] R1
|
|
||||||
[n_key n_value left right] n_key key [BTree-get] roll> [T>] [E] [T<] cmp
|
|
||||||
[n_key n_value left right] [BTree-get] n_key key [T>] [E] [T<] cmp
|
|
||||||
|
|
||||||
BTree-delete == [pop not] swap [[dup first] dip] [roll> [T>] [E] [T<] cmp] genrec</code></pre>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -13766,9 +13824,9 @@ BTree-delete == [pop not] swap [[dup first] dip] [roll> [T>] [E] [T<] c
|
|||||||
<div class="inner_cell">
|
<div class="inner_cell">
|
||||||
<div class="text_cell_render border-box-sizing rendered_html">
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
|
||||||
<pre><code>[n_key n_value left right] [BTree-get] T>
|
<pre><code> [Er] BTree-delete
|
||||||
[n_key n_value left right] [BTree-get] E
|
-------------------------------------
|
||||||
[n_key n_value left right] [BTree-get] T<</code></pre>
|
[pop not] [Er] [R0] [R1] genrec</code></pre>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -13782,6 +13840,633 @@ BTree-delete == [pop not] swap [[dup first] dip] [roll> [T>] [E] [T<] c
|
|||||||
[n_key n_value left right] [BTree-get] E
|
[n_key n_value left right] [BTree-get] E
|
||||||
[n_key n_value left right] [BTree-get] T<</code></pre>
|
[n_key n_value left right] [BTree-get] T<</code></pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<p>Now we get to figure out the recursive case:</p>
|
||||||
|
|
||||||
|
<pre><code>w/ D == [pop not] [Er] [R0] [R1] genrec
|
||||||
|
|
||||||
|
[node_key node_value left right] key R0 [D] R1
|
||||||
|
[node_key node_value left right] key over first swap dup [D] R1
|
||||||
|
[node_key node_value left right] node_key key key [D] R1
|
||||||
|
|
||||||
|
</code></pre>
|
||||||
|
<p>And then:</p>
|
||||||
|
|
||||||
|
<pre><code>[node_key node_value left right] node_key key key [D] R1
|
||||||
|
[node_key node_value left right] node_key key key [D] cons roll> [T>] [E] [T<] cmp
|
||||||
|
[node_key node_value left right] node_key key [key D] roll> [T>] [E] [T<] cmp
|
||||||
|
[node_key node_value left right] [key D] node_key key [T>] [E] [T<] cmp</code></pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<p>Now this:;</p>
|
||||||
|
|
||||||
|
<pre><code>[node_key node_value left right] [key D] node_key key [T>] [E] [T<] cmp
|
||||||
|
|
||||||
|
</code></pre>
|
||||||
|
<p>Becomes one of these three:;</p>
|
||||||
|
|
||||||
|
<pre><code>[node_key node_value left right] [key D] T>
|
||||||
|
[node_key node_value left right] [key D] E
|
||||||
|
[node_key node_value left right] [key D] T<</code></pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<h3 id="Greater-than-case-and-less-than-case">Greater than case and less than case<a class="anchor-link" href="#Greater-than-case-and-less-than-case">¶</a></h3>
|
||||||
|
<pre><code> [node_key node_value left right] [key D] T>
|
||||||
|
-------------------------------------------------
|
||||||
|
[node_key node_value left key D right]</code></pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<p>First:</p>
|
||||||
|
|
||||||
|
<pre><code>right left node_value node_key [key D] dipd
|
||||||
|
right left key D node_value node_key
|
||||||
|
right left' node_value node_key</code></pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<p>Ergo:</p>
|
||||||
|
|
||||||
|
<pre><code>[node_key node_value left right] [key D] [dipd] cons infra</code></pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<p>So:</p>
|
||||||
|
|
||||||
|
<pre><code>T> == [dipd] cons infra
|
||||||
|
T< == [dipdd] cons infra</code></pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<h3 id="The-else-case">The else case<a class="anchor-link" href="#The-else-case">¶</a></h3>
|
||||||
|
<pre><code>[node_key node_value left right] [key D] E
|
||||||
|
|
||||||
|
</code></pre>
|
||||||
|
<p>We have to handle three cases, so let's use <code>cond</code>.</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<p>The first two cases are symmetrical, if we only have one non-empty child node return it.</p>
|
||||||
|
|
||||||
|
<pre><code>E == [
|
||||||
|
[[pop third not] pop fourth]
|
||||||
|
[[pop fourth not] pop third]
|
||||||
|
[default]
|
||||||
|
] cond</code></pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<p>(If both child nodes are empty return an empty node.)</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<p>The initial structure of the default function:</p>
|
||||||
|
|
||||||
|
<pre><code>default == [E'] cons infra
|
||||||
|
|
||||||
|
[node_key node_value left right] [key D] default
|
||||||
|
[node_key node_value left right] [key D] [E'] cons infra
|
||||||
|
[node_key node_value left right] [[key D] E'] infra
|
||||||
|
|
||||||
|
right left node_value node_key [key D] E'</code></pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<p>If both child nodes are non-empty, we find the highest node in our lower sub-tree, take its key and value to replace (delete) our own, then get rid of it by recursively calling delete() on our lower sub-node with our new key.</p>
|
||||||
|
<p>(We could also find the lowest node in our higher sub-tree and take its key and value and delete it. I only implemented one of these two symmetrical options. Over a lot of deletions this might make the tree more unbalanced. Oh well.)</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<p>First things first, we no longer need this node's key and value:</p>
|
||||||
|
|
||||||
|
<pre><code>right left node_value node_key [key D] roll> popop E''
|
||||||
|
right left [key D] node_value node_key popop E''
|
||||||
|
right left [key D] E''</code></pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<p>Then we have to we find the highest (right-most) node in our lower (left) sub-tree:</p>
|
||||||
|
|
||||||
|
<pre><code>right left [key D] E''</code></pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<p>Ditch the key:</p>
|
||||||
|
|
||||||
|
<pre><code>right left [key D] rest E'''
|
||||||
|
right left [D] E'''</code></pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<p>Find the right-most node:</p>
|
||||||
|
|
||||||
|
<pre><code>right left [D] [dup W] dip E''''
|
||||||
|
right left dup W [D] E''''
|
||||||
|
right left left W [D] E''''</code></pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<p>Consider:</p>
|
||||||
|
|
||||||
|
<pre><code>left W</code></pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<p>We know left is not empty:</p>
|
||||||
|
|
||||||
|
<pre><code>[L_key L_value L_left L_right] W</code></pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<p>We want to keep extracting the right node as long as it is not empty:</p>
|
||||||
|
|
||||||
|
<pre><code>left [P] [B] while W'</code></pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<p>The predicate:</p>
|
||||||
|
|
||||||
|
<pre><code>[L_key L_value L_left L_right] P
|
||||||
|
[L_key L_value L_left L_right] fourth
|
||||||
|
L_right
|
||||||
|
|
||||||
|
</code></pre>
|
||||||
|
<p>(This has a bug, can run on <code>[]</code> so must be guarded:</p>
|
||||||
|
|
||||||
|
<pre><code>if_not_empty == [] swap [] ifte
|
||||||
|
?fourth == [fourth] if_not_empty
|
||||||
|
W.rightmost == [?fourth] [fourth] while</code></pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<p>The body is also <code>fourth</code>:</p>
|
||||||
|
|
||||||
|
<pre><code>left [fourth] [fourth] while W'
|
||||||
|
rightest W'</code></pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<p>We know rightest is not empty:</p>
|
||||||
|
|
||||||
|
<pre><code>[R_key R_value R_left R_right] W'
|
||||||
|
[R_key R_value R_left R_right] uncons uncons pop
|
||||||
|
R_key [R_value R_left R_right] uncons pop
|
||||||
|
R_key R_value [R_left R_right] pop
|
||||||
|
R_key R_value</code></pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<p>So:</p>
|
||||||
|
|
||||||
|
<pre><code>W == [fourth] [fourth] while uncons uncons pop</code></pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<p>And:</p>
|
||||||
|
|
||||||
|
<pre><code>right left left W [D] E''''
|
||||||
|
right left R_key R_value [D] E''''</code></pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<p>Final stretch. We want to end up with something like:</p>
|
||||||
|
|
||||||
|
<pre><code>right left [R_key D] i R_value R_key
|
||||||
|
right left R_key D R_value R_key
|
||||||
|
right left' R_value R_key</code></pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<p>If we adjust our definition of <code>W</code> to include <code>over</code> at the end:</p>
|
||||||
|
|
||||||
|
<pre><code>W == [fourth] [fourth] while uncons uncons pop over</code></pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<p>That will give us:</p>
|
||||||
|
|
||||||
|
<pre><code>right left R_key R_value R_key [D] E''''
|
||||||
|
|
||||||
|
right left R_key R_value R_key [D] cons dipdd E'''''
|
||||||
|
right left R_key R_value [R_key D] dipdd E'''''
|
||||||
|
right left R_key D R_key R_value E'''''
|
||||||
|
right left' R_key R_value E'''''
|
||||||
|
right left' R_key R_value swap
|
||||||
|
right left' R_value R_key</code></pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<p>So:</p>
|
||||||
|
|
||||||
|
<pre><code>E' == roll> popop E''
|
||||||
|
|
||||||
|
E'' == rest E'''
|
||||||
|
|
||||||
|
E''' == [dup W] dip E''''
|
||||||
|
|
||||||
|
E'''' == cons dipdd swap</code></pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<p>Substituting:</p>
|
||||||
|
|
||||||
|
<pre><code>W == [fourth] [fourth] while uncons uncons pop over
|
||||||
|
E' == roll> popop rest [dup W] dip cons dipdd swap
|
||||||
|
E == [
|
||||||
|
[[pop third not] pop fourth]
|
||||||
|
[[pop fourth not] pop third]
|
||||||
|
[[E'] cons infra]
|
||||||
|
] cond</code></pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<p>Minor rearrangement:</p>
|
||||||
|
|
||||||
|
<pre><code>W == dup [fourth] [fourth] while uncons uncons pop over
|
||||||
|
E' == roll> popop rest [W] dip cons dipdd swap
|
||||||
|
E == [
|
||||||
|
[[pop third not] pop fourth]
|
||||||
|
[[pop fourth not] pop third]
|
||||||
|
[[E'] cons infra]
|
||||||
|
] cond</code></pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<h3 id="Refactoring">Refactoring<a class="anchor-link" href="#Refactoring">¶</a></h3>
|
||||||
|
<pre><code>W.rightmost == [fourth] [fourth] while
|
||||||
|
W.unpack == uncons uncons pop
|
||||||
|
E.clear_stuff == roll> popop rest
|
||||||
|
E.delete == cons dipdd
|
||||||
|
W == dup W.rightmost W.unpack over
|
||||||
|
E.0 == E.clear_stuff [W] dip E.delete swap
|
||||||
|
E == [
|
||||||
|
[[pop third not] pop fourth]
|
||||||
|
[[pop fourth not] pop third]
|
||||||
|
[[E.0] cons infra]
|
||||||
|
] cond
|
||||||
|
T> == [dipd] cons infra
|
||||||
|
T< == [dipdd] cons infra
|
||||||
|
R0 == over first swap dup
|
||||||
|
R1 == cons roll> [T>] [E] [T<] cmp
|
||||||
|
BTree-Delete == [pop not] swap [R0] [R1] genrec
|
||||||
|
|
||||||
|
</code></pre>
|
||||||
|
<p>By the standards of the code I've written so far, this is a <em>huge</em> Joy program.</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
|
<div class="input">
|
||||||
|
<div class="prompt input_prompt">In [20]:</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="input_area">
|
||||||
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">DefinitionWrapper</span><span class="o">.</span><span class="n">add_definitions</span><span class="p">(</span><span class="s1">'''</span>
|
||||||
|
<span class="s1">first_two == uncons uncons pop</span>
|
||||||
|
<span class="s1">fourth == rest rest rest first</span>
|
||||||
|
<span class="s1">?fourth == [] [fourth] [] ifte</span>
|
||||||
|
<span class="s1">W.rightmost == [?fourth] [fourth] while</span>
|
||||||
|
<span class="s1">E.clear_stuff == roll> popop rest</span>
|
||||||
|
<span class="s1">E.delete == cons dipdd</span>
|
||||||
|
<span class="s1">W == dup W.rightmost first_two over</span>
|
||||||
|
<span class="s1">E.0 == E.clear_stuff [W] dip E.delete swap</span>
|
||||||
|
<span class="s1">E == [[[pop third not] pop fourth] [[pop fourth not] pop third] [[E.0] cons infra]] cond</span>
|
||||||
|
<span class="s1">T> == [dipd] cons infra</span>
|
||||||
|
<span class="s1">T< == [dipdd] cons infra</span>
|
||||||
|
<span class="s1">R0 == over first swap dup</span>
|
||||||
|
<span class="s1">R1 == cons roll> [T>] [E] [T<] cmp</span>
|
||||||
|
<span class="s1">BTree-Delete == [pop not] swap [R0] [R1] genrec'''</span><span class="p">,</span> <span class="n">D</span><span class="p">)</span>
|
||||||
|
</pre></div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
|
<div class="input">
|
||||||
|
<div class="prompt input_prompt">In [23]:</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="input_area">
|
||||||
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s2">"['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'c' ['Er'] BTree-Delete "</span><span class="p">)</span>
|
||||||
|
</pre></div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="output_wrapper">
|
||||||
|
<div class="output">
|
||||||
|
|
||||||
|
|
||||||
|
<div class="output_area">
|
||||||
|
|
||||||
|
<div class="prompt"></div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="output_subarea output_stream output_stdout output_text">
|
||||||
|
<pre>['a' 23 [] ['b' 88 [] []]]
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
|
<div class="input">
|
||||||
|
<div class="prompt input_prompt">In [24]:</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="input_area">
|
||||||
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s2">"['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'b' ['Er'] BTree-Delete "</span><span class="p">)</span>
|
||||||
|
</pre></div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="output_wrapper">
|
||||||
|
<div class="output">
|
||||||
|
|
||||||
|
|
||||||
|
<div class="output_area">
|
||||||
|
|
||||||
|
<div class="prompt"></div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="output_subarea output_stream output_stdout output_text">
|
||||||
|
<pre>['a' 23 [] ['c' 44 [] []]]
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
|
<div class="input">
|
||||||
|
<div class="prompt input_prompt">In [25]:</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="input_area">
|
||||||
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s2">"['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'a' ['Er'] BTree-Delete "</span><span class="p">)</span>
|
||||||
|
</pre></div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="output_wrapper">
|
||||||
|
<div class="output">
|
||||||
|
|
||||||
|
|
||||||
|
<div class="output_area">
|
||||||
|
|
||||||
|
<div class="prompt"></div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="output_subarea output_stream output_stdout output_text">
|
||||||
|
<pre>['b' 88 [] ['c' 44 [] []]]
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
|
<div class="input">
|
||||||
|
<div class="prompt input_prompt">In [26]:</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="input_area">
|
||||||
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s2">"['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'der' ['Er'] BTree-Delete "</span><span class="p">)</span>
|
||||||
|
</pre></div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="output_wrapper">
|
||||||
|
<div class="output">
|
||||||
|
|
||||||
|
|
||||||
|
<div class="output_area">
|
||||||
|
|
||||||
|
<div class="prompt"></div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="output_subarea output_stream output_stdout output_text">
|
||||||
|
<pre>['a' 23 [] ['b' 88 [] ['c' 44 [] 'Er' 'der' []]]]
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing code_cell rendered">
|
||||||
|
<div class="input">
|
||||||
|
<div class="prompt input_prompt">In [30]:</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="input_area">
|
||||||
|
<div class=" highlight hl-ipython2"><pre><span></span><span class="n">J</span><span class="p">(</span><span class="s2">"['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'der' [pop] BTree-Delete "</span><span class="p">)</span>
|
||||||
|
</pre></div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="output_wrapper">
|
||||||
|
<div class="output">
|
||||||
|
|
||||||
|
|
||||||
|
<div class="output_area">
|
||||||
|
|
||||||
|
<div class="prompt"></div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="output_subarea output_stream output_stdout output_text">
|
||||||
|
<pre>['a' 23 [] ['b' 88 [] ['c' 44 [] []]]]
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<p>One bug, I forgot to put <code>not</code> in the first two clauses of the <code>cond</code>.</p>
|
||||||
|
<p>The behavior of the <code>[Er]</code> function should maybe be different: either just silently fail, or maybe implement some sort of function that can grab the pending expression up to a sentinel value or something, allowing for a kind of "except"-ish control-flow?</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
|
||||||
|
</div>
|
||||||
|
<div class="inner_cell">
|
||||||
|
<div class="text_cell_render border-box-sizing rendered_html">
|
||||||
|
<p>Then, once we have add, get, and delete we can see about abstracting them.</p>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+353
-21
@@ -92,7 +92,7 @@ Ergo:
|
|||||||
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from notebook_preamble import J, V, define
|
from notebook_preamble import D, J, V, define, DefinitionWrapper
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
@@ -590,6 +590,22 @@ from notebook_preamble import D
|
|||||||
|
|
||||||
@FunctionWrapper
|
@FunctionWrapper
|
||||||
def cmp_(stack, expression, dictionary):
|
def cmp_(stack, expression, dictionary):
|
||||||
|
'''
|
||||||
|
cmp takes two values and three quoted programs on the stack and runs
|
||||||
|
one of the three depending on the results of comparing the two values:
|
||||||
|
|
||||||
|
a b [G] [E] [L] cmp
|
||||||
|
------------------------- a > b
|
||||||
|
G
|
||||||
|
|
||||||
|
a b [G] [E] [L] cmp
|
||||||
|
------------------------- a = b
|
||||||
|
E
|
||||||
|
|
||||||
|
a b [G] [E] [L] cmp
|
||||||
|
------------------------- a < b
|
||||||
|
L
|
||||||
|
'''
|
||||||
L, (E, (G, (b, (a, stack)))) = stack
|
L, (E, (G, (b, (a, stack)))) = stack
|
||||||
expression = pushback(G if a > b else L if a < b else E, expression)
|
expression = pushback(G if a > b else L if a < b else E, expression)
|
||||||
return stack, expression, dictionary
|
return stack, expression, dictionary
|
||||||
@@ -599,6 +615,51 @@ D['cmp'] = cmp_
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
from joy.library import FunctionWrapper, S_ifte
|
||||||
|
|
||||||
|
|
||||||
|
@FunctionWrapper
|
||||||
|
def cond(stack, expression, dictionary):
|
||||||
|
'''
|
||||||
|
like a case statement; works by rewriting into a chain of ifte.
|
||||||
|
|
||||||
|
[..[[Bi] Ti]..[D]] -> ...
|
||||||
|
|
||||||
|
|
||||||
|
[[[B0] T0] [[B1] T1] [D]] cond
|
||||||
|
-----------------------------------------
|
||||||
|
[B0] [T0] [[B1] [T1] [D] ifte] ifte
|
||||||
|
|
||||||
|
'''
|
||||||
|
conditions, stack = stack
|
||||||
|
if conditions:
|
||||||
|
expression = _cond(conditions, expression)
|
||||||
|
try:
|
||||||
|
# Attempt to preload the args to first ifte.
|
||||||
|
(P, (T, (E, expression))) = expression
|
||||||
|
except ValueError:
|
||||||
|
# If, for any reason, the argument to cond should happen to contain
|
||||||
|
# only the default clause then this optimization will fail.
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
stack = (E, (T, (P, stack)))
|
||||||
|
return stack, expression, dictionary
|
||||||
|
|
||||||
|
|
||||||
|
def _cond(conditions, expression):
|
||||||
|
(clause, rest) = conditions
|
||||||
|
if not rest: # clause is [D]
|
||||||
|
return clause
|
||||||
|
P, T = clause
|
||||||
|
return (P, (T, (_cond(rest, ()), (S_ifte, expression))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
D['cond'] = cond
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
J("1 0 ['G'] ['E'] ['L'] cmp")
|
J("1 0 ['G'] ['E'] ['L'] cmp")
|
||||||
```
|
```
|
||||||
@@ -913,40 +974,311 @@ J('''
|
|||||||
2
|
2
|
||||||
|
|
||||||
|
|
||||||
# TODO: BTree-delete
|
# BTree-delete
|
||||||
|
|
||||||
Then, once we have add, get, and delete we can see about abstracting them.
|
Now let's write a function that can return a tree datastructure with a key, value pair deleted:
|
||||||
|
|
||||||
tree key [E] BTree-delete
|
tree key BTree-delete
|
||||||
---------------------------- key in tree
|
---------------------------
|
||||||
tree
|
tree
|
||||||
|
|
||||||
tree key [E] BTree-delete
|
|
||||||
---------------------------- key not in tree
|
If the key is not in tree it just returns the tree unchanged.
|
||||||
tree key E
|
|
||||||
|
|
||||||
So:
|
So:
|
||||||
|
|
||||||
BTree-delete == [pop not] [] [R0] [R1] genrec
|
BTree-Delete == [pop not] swap [R0] [R1] genrec
|
||||||
|
|
||||||
And:
|
|
||||||
|
|
||||||
[n_key n_value left right] key R0 [BTree-get] R1
|
[Er] BTree-delete
|
||||||
[n_key n_value left right] key [dup first] dip [BTree-get] R1
|
-------------------------------------
|
||||||
[n_key n_value left right] n_key key [BTree-get] R1
|
[pop not] [Er] [R0] [R1] genrec
|
||||||
[n_key n_value left right] n_key key [BTree-get] roll> [T>] [E] [T<] cmp
|
|
||||||
[n_key n_value left right] [BTree-get] n_key key [T>] [E] [T<] cmp
|
|
||||||
|
|
||||||
BTree-delete == [pop not] swap [[dup first] dip] [roll> [T>] [E] [T<] cmp] genrec
|
|
||||||
|
|
||||||
[n_key n_value left right] [BTree-get] T>
|
|
||||||
[n_key n_value left right] [BTree-get] E
|
|
||||||
[n_key n_value left right] [BTree-get] T<
|
|
||||||
|
|
||||||
[n_key n_value left right] [BTree-get]
|
[n_key n_value left right] [BTree-get]
|
||||||
[n_key n_value left right] [BTree-get] E
|
[n_key n_value left right] [BTree-get] E
|
||||||
[n_key n_value left right] [BTree-get] T<
|
[n_key n_value left right] [BTree-get] T<
|
||||||
|
|
||||||
|
Now we get to figure out the recursive case:
|
||||||
|
|
||||||
|
w/ D == [pop not] [Er] [R0] [R1] genrec
|
||||||
|
|
||||||
|
[node_key node_value left right] key R0 [D] R1
|
||||||
|
[node_key node_value left right] key over first swap dup [D] R1
|
||||||
|
[node_key node_value left right] node_key key key [D] R1
|
||||||
|
|
||||||
|
And then:
|
||||||
|
|
||||||
|
[node_key node_value left right] node_key key key [D] R1
|
||||||
|
[node_key node_value left right] node_key key key [D] cons roll> [T>] [E] [T<] cmp
|
||||||
|
[node_key node_value left right] node_key key [key D] roll> [T>] [E] [T<] cmp
|
||||||
|
[node_key node_value left right] [key D] node_key key [T>] [E] [T<] cmp
|
||||||
|
|
||||||
|
Now this:;
|
||||||
|
|
||||||
|
[node_key node_value left right] [key D] node_key key [T>] [E] [T<] cmp
|
||||||
|
|
||||||
|
Becomes one of these three:;
|
||||||
|
|
||||||
|
[node_key node_value left right] [key D] T>
|
||||||
|
[node_key node_value left right] [key D] E
|
||||||
|
[node_key node_value left right] [key D] T<
|
||||||
|
|
||||||
|
### Greater than case and less than case
|
||||||
|
|
||||||
|
[node_key node_value left right] [key D] T>
|
||||||
|
-------------------------------------------------
|
||||||
|
[node_key node_value left key D right]
|
||||||
|
|
||||||
|
First:
|
||||||
|
|
||||||
|
right left node_value node_key [key D] dipd
|
||||||
|
right left key D node_value node_key
|
||||||
|
right left' node_value node_key
|
||||||
|
|
||||||
|
Ergo:
|
||||||
|
|
||||||
|
[node_key node_value left right] [key D] [dipd] cons infra
|
||||||
|
|
||||||
|
So:
|
||||||
|
|
||||||
|
T> == [dipd] cons infra
|
||||||
|
T< == [dipdd] cons infra
|
||||||
|
|
||||||
|
### The else case
|
||||||
|
|
||||||
|
[node_key node_value left right] [key D] E
|
||||||
|
|
||||||
|
We have to handle three cases, so let's use `cond`.
|
||||||
|
|
||||||
|
The first two cases are symmetrical, if we only have one non-empty child node return it.
|
||||||
|
|
||||||
|
E == [
|
||||||
|
[[pop third not] pop fourth]
|
||||||
|
[[pop fourth not] pop third]
|
||||||
|
[default]
|
||||||
|
] cond
|
||||||
|
|
||||||
|
(If both child nodes are empty return an empty node.)
|
||||||
|
|
||||||
|
The initial structure of the default function:
|
||||||
|
|
||||||
|
default == [E'] cons infra
|
||||||
|
|
||||||
|
[node_key node_value left right] [key D] default
|
||||||
|
[node_key node_value left right] [key D] [E'] cons infra
|
||||||
|
[node_key node_value left right] [[key D] E'] infra
|
||||||
|
|
||||||
|
right left node_value node_key [key D] E'
|
||||||
|
|
||||||
|
If both child nodes are non-empty, we find the highest node in our lower sub-tree, take its key and value to replace (delete) our own, then get rid of it by recursively calling delete() on our lower sub-node with our new key.
|
||||||
|
|
||||||
|
(We could also find the lowest node in our higher sub-tree and take its key and value and delete it. I only implemented one of these two symmetrical options. Over a lot of deletions this might make the tree more unbalanced. Oh well.)
|
||||||
|
|
||||||
|
First things first, we no longer need this node's key and value:
|
||||||
|
|
||||||
|
right left node_value node_key [key D] roll> popop E''
|
||||||
|
right left [key D] node_value node_key popop E''
|
||||||
|
right left [key D] E''
|
||||||
|
|
||||||
|
Then we have to we find the highest (right-most) node in our lower (left) sub-tree:
|
||||||
|
|
||||||
|
right left [key D] E''
|
||||||
|
|
||||||
|
Ditch the key:
|
||||||
|
|
||||||
|
right left [key D] rest E'''
|
||||||
|
right left [D] E'''
|
||||||
|
|
||||||
|
Find the right-most node:
|
||||||
|
|
||||||
|
right left [D] [dup W] dip E''''
|
||||||
|
right left dup W [D] E''''
|
||||||
|
right left left W [D] E''''
|
||||||
|
|
||||||
|
Consider:
|
||||||
|
|
||||||
|
left W
|
||||||
|
|
||||||
|
We know left is not empty:
|
||||||
|
|
||||||
|
[L_key L_value L_left L_right] W
|
||||||
|
|
||||||
|
We want to keep extracting the right node as long as it is not empty:
|
||||||
|
|
||||||
|
left [P] [B] while W'
|
||||||
|
|
||||||
|
The predicate:
|
||||||
|
|
||||||
|
[L_key L_value L_left L_right] P
|
||||||
|
[L_key L_value L_left L_right] fourth
|
||||||
|
L_right
|
||||||
|
|
||||||
|
(This has a bug, can run on `[]` so must be guarded:
|
||||||
|
|
||||||
|
if_not_empty == [] swap [] ifte
|
||||||
|
?fourth == [fourth] if_not_empty
|
||||||
|
W.rightmost == [?fourth] [fourth] while
|
||||||
|
|
||||||
|
The body is also `fourth`:
|
||||||
|
|
||||||
|
left [fourth] [fourth] while W'
|
||||||
|
rightest W'
|
||||||
|
|
||||||
|
We know rightest is not empty:
|
||||||
|
|
||||||
|
[R_key R_value R_left R_right] W'
|
||||||
|
[R_key R_value R_left R_right] uncons uncons pop
|
||||||
|
R_key [R_value R_left R_right] uncons pop
|
||||||
|
R_key R_value [R_left R_right] pop
|
||||||
|
R_key R_value
|
||||||
|
|
||||||
|
So:
|
||||||
|
|
||||||
|
W == [fourth] [fourth] while uncons uncons pop
|
||||||
|
|
||||||
|
And:
|
||||||
|
|
||||||
|
right left left W [D] E''''
|
||||||
|
right left R_key R_value [D] E''''
|
||||||
|
|
||||||
|
Final stretch. We want to end up with something like:
|
||||||
|
|
||||||
|
right left [R_key D] i R_value R_key
|
||||||
|
right left R_key D R_value R_key
|
||||||
|
right left' R_value R_key
|
||||||
|
|
||||||
|
If we adjust our definition of `W` to include `over` at the end:
|
||||||
|
|
||||||
|
W == [fourth] [fourth] while uncons uncons pop over
|
||||||
|
|
||||||
|
That will give us:
|
||||||
|
|
||||||
|
right left R_key R_value R_key [D] E''''
|
||||||
|
|
||||||
|
right left R_key R_value R_key [D] cons dipdd E'''''
|
||||||
|
right left R_key R_value [R_key D] dipdd E'''''
|
||||||
|
right left R_key D R_key R_value E'''''
|
||||||
|
right left' R_key R_value E'''''
|
||||||
|
right left' R_key R_value swap
|
||||||
|
right left' R_value R_key
|
||||||
|
|
||||||
|
So:
|
||||||
|
|
||||||
|
E' == roll> popop E''
|
||||||
|
|
||||||
|
E'' == rest E'''
|
||||||
|
|
||||||
|
E''' == [dup W] dip E''''
|
||||||
|
|
||||||
|
E'''' == cons dipdd swap
|
||||||
|
|
||||||
|
Substituting:
|
||||||
|
|
||||||
|
W == [fourth] [fourth] while uncons uncons pop over
|
||||||
|
E' == roll> popop rest [dup W] dip cons dipdd swap
|
||||||
|
E == [
|
||||||
|
[[pop third not] pop fourth]
|
||||||
|
[[pop fourth not] pop third]
|
||||||
|
[[E'] cons infra]
|
||||||
|
] cond
|
||||||
|
|
||||||
|
Minor rearrangement:
|
||||||
|
|
||||||
|
W == dup [fourth] [fourth] while uncons uncons pop over
|
||||||
|
E' == roll> popop rest [W] dip cons dipdd swap
|
||||||
|
E == [
|
||||||
|
[[pop third not] pop fourth]
|
||||||
|
[[pop fourth not] pop third]
|
||||||
|
[[E'] cons infra]
|
||||||
|
] cond
|
||||||
|
|
||||||
|
### Refactoring
|
||||||
|
|
||||||
|
W.rightmost == [fourth] [fourth] while
|
||||||
|
W.unpack == uncons uncons pop
|
||||||
|
E.clear_stuff == roll> popop rest
|
||||||
|
E.delete == cons dipdd
|
||||||
|
W == dup W.rightmost W.unpack over
|
||||||
|
E.0 == E.clear_stuff [W] dip E.delete swap
|
||||||
|
E == [
|
||||||
|
[[pop third not] pop fourth]
|
||||||
|
[[pop fourth not] pop third]
|
||||||
|
[[E.0] cons infra]
|
||||||
|
] cond
|
||||||
|
T> == [dipd] cons infra
|
||||||
|
T< == [dipdd] cons infra
|
||||||
|
R0 == over first swap dup
|
||||||
|
R1 == cons roll> [T>] [E] [T<] cmp
|
||||||
|
BTree-Delete == [pop not] swap [R0] [R1] genrec
|
||||||
|
|
||||||
|
By the standards of the code I've written so far, this is a *huge* Joy program.
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
DefinitionWrapper.add_definitions('''
|
||||||
|
first_two == uncons uncons pop
|
||||||
|
fourth == rest rest rest first
|
||||||
|
?fourth == [] [fourth] [] ifte
|
||||||
|
W.rightmost == [?fourth] [fourth] while
|
||||||
|
E.clear_stuff == roll> popop rest
|
||||||
|
E.delete == cons dipdd
|
||||||
|
W == dup W.rightmost first_two over
|
||||||
|
E.0 == E.clear_stuff [W] dip E.delete swap
|
||||||
|
E == [[[pop third not] pop fourth] [[pop fourth not] pop third] [[E.0] cons infra]] cond
|
||||||
|
T> == [dipd] cons infra
|
||||||
|
T< == [dipdd] cons infra
|
||||||
|
R0 == over first swap dup
|
||||||
|
R1 == cons roll> [T>] [E] [T<] cmp
|
||||||
|
BTree-Delete == [pop not] swap [R0] [R1] genrec''', D)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'c' ['Er'] BTree-Delete ")
|
||||||
|
```
|
||||||
|
|
||||||
|
['a' 23 [] ['b' 88 [] []]]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'b' ['Er'] BTree-Delete ")
|
||||||
|
```
|
||||||
|
|
||||||
|
['a' 23 [] ['c' 44 [] []]]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'a' ['Er'] BTree-Delete ")
|
||||||
|
```
|
||||||
|
|
||||||
|
['b' 88 [] ['c' 44 [] []]]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'der' ['Er'] BTree-Delete ")
|
||||||
|
```
|
||||||
|
|
||||||
|
['a' 23 [] ['b' 88 [] ['c' 44 [] 'Er' 'der' []]]]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'der' [pop] BTree-Delete ")
|
||||||
|
```
|
||||||
|
|
||||||
|
['a' 23 [] ['b' 88 [] ['c' 44 [] []]]]
|
||||||
|
|
||||||
|
|
||||||
|
One bug, I forgot to put `not` in the first two clauses of the `cond`.
|
||||||
|
|
||||||
|
The behavior of the `[Er]` function should maybe be different: either just silently fail, or maybe implement some sort of function that can grab the pending expression up to a sentinel value or something, allowing for a kind of "except"-ish control-flow?
|
||||||
|
|
||||||
|
Then, once we have add, get, and delete we can see about abstracting them.
|
||||||
|
|
||||||
|
|
||||||
# Tree with node and list of trees.
|
# Tree with node and list of trees.
|
||||||
Let's consider a tree structure, similar to one described ["Why functional programming matters" by John Hughes](https://www.cs.kent.ac.uk/people/staff/dat/miranda/whyfp90.pdf), that consists of a node value and a sequence of zero or more child trees. (The asterisk is meant to indicate the [Kleene star](https://en.wikipedia.org/wiki/Kleene_star).)
|
Let's consider a tree structure, similar to one described ["Why functional programming matters" by John Hughes](https://www.cs.kent.ac.uk/people/staff/dat/miranda/whyfp90.pdf), that consists of a node value and a sequence of zero or more child trees. (The asterisk is meant to indicate the [Kleene star](https://en.wikipedia.org/wiki/Kleene_star).)
|
||||||
|
|
||||||
|
|||||||
+441
-26
@@ -149,7 +149,7 @@ Ergo:
|
|||||||
|
|
||||||
.. code:: ipython2
|
.. code:: ipython2
|
||||||
|
|
||||||
from notebook_preamble import J, V, define
|
from notebook_preamble import D, J, V, define, DefinitionWrapper
|
||||||
|
|
||||||
.. code:: ipython2
|
.. code:: ipython2
|
||||||
|
|
||||||
@@ -774,6 +774,22 @@ to understand:
|
|||||||
|
|
||||||
@FunctionWrapper
|
@FunctionWrapper
|
||||||
def cmp_(stack, expression, dictionary):
|
def cmp_(stack, expression, dictionary):
|
||||||
|
'''
|
||||||
|
cmp takes two values and three quoted programs on the stack and runs
|
||||||
|
one of the three depending on the results of comparing the two values:
|
||||||
|
|
||||||
|
a b [G] [E] [L] cmp
|
||||||
|
------------------------- a > b
|
||||||
|
G
|
||||||
|
|
||||||
|
a b [G] [E] [L] cmp
|
||||||
|
------------------------- a = b
|
||||||
|
E
|
||||||
|
|
||||||
|
a b [G] [E] [L] cmp
|
||||||
|
------------------------- a < b
|
||||||
|
L
|
||||||
|
'''
|
||||||
L, (E, (G, (b, (a, stack)))) = stack
|
L, (E, (G, (b, (a, stack)))) = stack
|
||||||
expression = pushback(G if a > b else L if a < b else E, expression)
|
expression = pushback(G if a > b else L if a < b else E, expression)
|
||||||
return stack, expression, dictionary
|
return stack, expression, dictionary
|
||||||
@@ -781,6 +797,50 @@ to understand:
|
|||||||
|
|
||||||
D['cmp'] = cmp_
|
D['cmp'] = cmp_
|
||||||
|
|
||||||
|
.. code:: ipython2
|
||||||
|
|
||||||
|
from joy.library import FunctionWrapper, S_ifte
|
||||||
|
|
||||||
|
|
||||||
|
@FunctionWrapper
|
||||||
|
def cond(stack, expression, dictionary):
|
||||||
|
'''
|
||||||
|
like a case statement; works by rewriting into a chain of ifte.
|
||||||
|
|
||||||
|
[..[[Bi] Ti]..[D]] -> ...
|
||||||
|
|
||||||
|
|
||||||
|
[[[B0] T0] [[B1] T1] [D]] cond
|
||||||
|
-----------------------------------------
|
||||||
|
[B0] [T0] [[B1] [T1] [D] ifte] ifte
|
||||||
|
|
||||||
|
'''
|
||||||
|
conditions, stack = stack
|
||||||
|
if conditions:
|
||||||
|
expression = _cond(conditions, expression)
|
||||||
|
try:
|
||||||
|
# Attempt to preload the args to first ifte.
|
||||||
|
(P, (T, (E, expression))) = expression
|
||||||
|
except ValueError:
|
||||||
|
# If, for any reason, the argument to cond should happen to contain
|
||||||
|
# only the default clause then this optimization will fail.
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
stack = (E, (T, (P, stack)))
|
||||||
|
return stack, expression, dictionary
|
||||||
|
|
||||||
|
|
||||||
|
def _cond(conditions, expression):
|
||||||
|
(clause, rest) = conditions
|
||||||
|
if not rest: # clause is [D]
|
||||||
|
return clause
|
||||||
|
P, T = clause
|
||||||
|
return (P, (T, (_cond(rest, ()), (S_ifte, expression))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
D['cond'] = cond
|
||||||
|
|
||||||
.. code:: ipython2
|
.. code:: ipython2
|
||||||
|
|
||||||
J("1 0 ['G'] ['E'] ['L'] cmp")
|
J("1 0 ['G'] ['E'] ['L'] cmp")
|
||||||
@@ -1207,45 +1267,31 @@ So:
|
|||||||
2
|
2
|
||||||
|
|
||||||
|
|
||||||
TODO: BTree-delete
|
BTree-delete
|
||||||
==================
|
============
|
||||||
|
|
||||||
Then, once we have add, get, and delete we can see about abstracting
|
Now let's write a function that can return a tree datastructure with a
|
||||||
them.
|
key, value pair deleted:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
tree key [E] BTree-delete
|
tree key BTree-delete
|
||||||
---------------------------- key in tree
|
---------------------------
|
||||||
tree
|
tree
|
||||||
|
|
||||||
tree key [E] BTree-delete
|
If the key is not in tree it just returns the tree unchanged.
|
||||||
---------------------------- key not in tree
|
|
||||||
tree key E
|
|
||||||
|
|
||||||
So:
|
So:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
BTree-delete == [pop not] [] [R0] [R1] genrec
|
BTree-Delete == [pop not] swap [R0] [R1] genrec
|
||||||
|
|
||||||
And:
|
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
[n_key n_value left right] key R0 [BTree-get] R1
|
[Er] BTree-delete
|
||||||
[n_key n_value left right] key [dup first] dip [BTree-get] R1
|
-------------------------------------
|
||||||
[n_key n_value left right] n_key key [BTree-get] R1
|
[pop not] [Er] [R0] [R1] genrec
|
||||||
[n_key n_value left right] n_key key [BTree-get] roll> [T>] [E] [T<] cmp
|
|
||||||
[n_key n_value left right] [BTree-get] n_key key [T>] [E] [T<] cmp
|
|
||||||
|
|
||||||
BTree-delete == [pop not] swap [[dup first] dip] [roll> [T>] [E] [T<] cmp] genrec
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
[n_key n_value left right] [BTree-get] T>
|
|
||||||
[n_key n_value left right] [BTree-get] E
|
|
||||||
[n_key n_value left right] [BTree-get] T<
|
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
@@ -1253,6 +1299,375 @@ And:
|
|||||||
[n_key n_value left right] [BTree-get] E
|
[n_key n_value left right] [BTree-get] E
|
||||||
[n_key n_value left right] [BTree-get] T<
|
[n_key n_value left right] [BTree-get] T<
|
||||||
|
|
||||||
|
Now we get to figure out the recursive case:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
w/ D == [pop not] [Er] [R0] [R1] genrec
|
||||||
|
|
||||||
|
[node_key node_value left right] key R0 [D] R1
|
||||||
|
[node_key node_value left right] key over first swap dup [D] R1
|
||||||
|
[node_key node_value left right] node_key key key [D] R1
|
||||||
|
|
||||||
|
And then:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[node_key node_value left right] node_key key key [D] R1
|
||||||
|
[node_key node_value left right] node_key key key [D] cons roll> [T>] [E] [T<] cmp
|
||||||
|
[node_key node_value left right] node_key key [key D] roll> [T>] [E] [T<] cmp
|
||||||
|
[node_key node_value left right] [key D] node_key key [T>] [E] [T<] cmp
|
||||||
|
|
||||||
|
Now this:;
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[node_key node_value left right] [key D] node_key key [T>] [E] [T<] cmp
|
||||||
|
|
||||||
|
Becomes one of these three:;
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[node_key node_value left right] [key D] T>
|
||||||
|
[node_key node_value left right] [key D] E
|
||||||
|
[node_key node_value left right] [key D] T<
|
||||||
|
|
||||||
|
Greater than case and less than case
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[node_key node_value left right] [key D] T>
|
||||||
|
-------------------------------------------------
|
||||||
|
[node_key node_value left key D right]
|
||||||
|
|
||||||
|
First:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
right left node_value node_key [key D] dipd
|
||||||
|
right left key D node_value node_key
|
||||||
|
right left' node_value node_key
|
||||||
|
|
||||||
|
Ergo:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[node_key node_value left right] [key D] [dipd] cons infra
|
||||||
|
|
||||||
|
So:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
T> == [dipd] cons infra
|
||||||
|
T< == [dipdd] cons infra
|
||||||
|
|
||||||
|
The else case
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[node_key node_value left right] [key D] E
|
||||||
|
|
||||||
|
We have to handle three cases, so let's use ``cond``.
|
||||||
|
|
||||||
|
The first two cases are symmetrical, if we only have one non-empty child
|
||||||
|
node return it.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
E == [
|
||||||
|
[[pop third not] pop fourth]
|
||||||
|
[[pop fourth not] pop third]
|
||||||
|
[default]
|
||||||
|
] cond
|
||||||
|
|
||||||
|
(If both child nodes are empty return an empty node.)
|
||||||
|
|
||||||
|
The initial structure of the default function:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
default == [E'] cons infra
|
||||||
|
|
||||||
|
[node_key node_value left right] [key D] default
|
||||||
|
[node_key node_value left right] [key D] [E'] cons infra
|
||||||
|
[node_key node_value left right] [[key D] E'] infra
|
||||||
|
|
||||||
|
right left node_value node_key [key D] E'
|
||||||
|
|
||||||
|
If both child nodes are non-empty, we find the highest node in our lower
|
||||||
|
sub-tree, take its key and value to replace (delete) our own, then get
|
||||||
|
rid of it by recursively calling delete() on our lower sub-node with our
|
||||||
|
new key.
|
||||||
|
|
||||||
|
(We could also find the lowest node in our higher sub-tree and take its
|
||||||
|
key and value and delete it. I only implemented one of these two
|
||||||
|
symmetrical options. Over a lot of deletions this might make the tree
|
||||||
|
more unbalanced. Oh well.)
|
||||||
|
|
||||||
|
First things first, we no longer need this node's key and value:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
right left node_value node_key [key D] roll> popop E''
|
||||||
|
right left [key D] node_value node_key popop E''
|
||||||
|
right left [key D] E''
|
||||||
|
|
||||||
|
Then we have to we find the highest (right-most) node in our lower
|
||||||
|
(left) sub-tree:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
right left [key D] E''
|
||||||
|
|
||||||
|
Ditch the key:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
right left [key D] rest E'''
|
||||||
|
right left [D] E'''
|
||||||
|
|
||||||
|
Find the right-most node:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
right left [D] [dup W] dip E''''
|
||||||
|
right left dup W [D] E''''
|
||||||
|
right left left W [D] E''''
|
||||||
|
|
||||||
|
Consider:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
left W
|
||||||
|
|
||||||
|
We know left is not empty:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[L_key L_value L_left L_right] W
|
||||||
|
|
||||||
|
We want to keep extracting the right node as long as it is not empty:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
left [P] [B] while W'
|
||||||
|
|
||||||
|
The predicate:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[L_key L_value L_left L_right] P
|
||||||
|
[L_key L_value L_left L_right] fourth
|
||||||
|
L_right
|
||||||
|
|
||||||
|
|
||||||
|
(This has a bug, can run on ``[]`` so must be guarded:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
if_not_empty == [] swap [] ifte
|
||||||
|
?fourth == [fourth] if_not_empty
|
||||||
|
W.rightmost == [?fourth] [fourth] while
|
||||||
|
|
||||||
|
The body is also ``fourth``:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
left [fourth] [fourth] while W'
|
||||||
|
rightest W'
|
||||||
|
|
||||||
|
We know rightest is not empty:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[R_key R_value R_left R_right] W'
|
||||||
|
[R_key R_value R_left R_right] uncons uncons pop
|
||||||
|
R_key [R_value R_left R_right] uncons pop
|
||||||
|
R_key R_value [R_left R_right] pop
|
||||||
|
R_key R_value
|
||||||
|
|
||||||
|
So:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
W == [fourth] [fourth] while uncons uncons pop
|
||||||
|
|
||||||
|
And:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
right left left W [D] E''''
|
||||||
|
right left R_key R_value [D] E''''
|
||||||
|
|
||||||
|
Final stretch. We want to end up with something like:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
right left [R_key D] i R_value R_key
|
||||||
|
right left R_key D R_value R_key
|
||||||
|
right left' R_value R_key
|
||||||
|
|
||||||
|
If we adjust our definition of ``W`` to include ``over`` at the end:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
W == [fourth] [fourth] while uncons uncons pop over
|
||||||
|
|
||||||
|
That will give us:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
right left R_key R_value R_key [D] E''''
|
||||||
|
|
||||||
|
right left R_key R_value R_key [D] cons dipdd E'''''
|
||||||
|
right left R_key R_value [R_key D] dipdd E'''''
|
||||||
|
right left R_key D R_key R_value E'''''
|
||||||
|
right left' R_key R_value E'''''
|
||||||
|
right left' R_key R_value swap
|
||||||
|
right left' R_value R_key
|
||||||
|
|
||||||
|
So:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
E' == roll> popop E''
|
||||||
|
|
||||||
|
E'' == rest E'''
|
||||||
|
|
||||||
|
E''' == [dup W] dip E''''
|
||||||
|
|
||||||
|
E'''' == cons dipdd swap
|
||||||
|
|
||||||
|
Substituting:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
W == [fourth] [fourth] while uncons uncons pop over
|
||||||
|
E' == roll> popop rest [dup W] dip cons dipdd swap
|
||||||
|
E == [
|
||||||
|
[[pop third not] pop fourth]
|
||||||
|
[[pop fourth not] pop third]
|
||||||
|
[[E'] cons infra]
|
||||||
|
] cond
|
||||||
|
|
||||||
|
Minor rearrangement:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
W == dup [fourth] [fourth] while uncons uncons pop over
|
||||||
|
E' == roll> popop rest [W] dip cons dipdd swap
|
||||||
|
E == [
|
||||||
|
[[pop third not] pop fourth]
|
||||||
|
[[pop fourth not] pop third]
|
||||||
|
[[E'] cons infra]
|
||||||
|
] cond
|
||||||
|
|
||||||
|
Refactoring
|
||||||
|
~~~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
W.rightmost == [fourth] [fourth] while
|
||||||
|
W.unpack == uncons uncons pop
|
||||||
|
E.clear_stuff == roll> popop rest
|
||||||
|
E.delete == cons dipdd
|
||||||
|
W == dup W.rightmost W.unpack over
|
||||||
|
E.0 == E.clear_stuff [W] dip E.delete swap
|
||||||
|
E == [
|
||||||
|
[[pop third not] pop fourth]
|
||||||
|
[[pop fourth not] pop third]
|
||||||
|
[[E.0] cons infra]
|
||||||
|
] cond
|
||||||
|
T> == [dipd] cons infra
|
||||||
|
T< == [dipdd] cons infra
|
||||||
|
R0 == over first swap dup
|
||||||
|
R1 == cons roll> [T>] [E] [T<] cmp
|
||||||
|
BTree-Delete == [pop not] swap [R0] [R1] genrec
|
||||||
|
|
||||||
|
By the standards of the code I've written so far, this is a *huge* Joy
|
||||||
|
program.
|
||||||
|
|
||||||
|
.. code:: ipython2
|
||||||
|
|
||||||
|
DefinitionWrapper.add_definitions('''
|
||||||
|
first_two == uncons uncons pop
|
||||||
|
fourth == rest rest rest first
|
||||||
|
?fourth == [] [fourth] [] ifte
|
||||||
|
W.rightmost == [?fourth] [fourth] while
|
||||||
|
E.clear_stuff == roll> popop rest
|
||||||
|
E.delete == cons dipdd
|
||||||
|
W == dup W.rightmost first_two over
|
||||||
|
E.0 == E.clear_stuff [W] dip E.delete swap
|
||||||
|
E == [[[pop third not] pop fourth] [[pop fourth not] pop third] [[E.0] cons infra]] cond
|
||||||
|
T> == [dipd] cons infra
|
||||||
|
T< == [dipdd] cons infra
|
||||||
|
R0 == over first swap dup
|
||||||
|
R1 == cons roll> [T>] [E] [T<] cmp
|
||||||
|
BTree-Delete == [pop not] swap [R0] [R1] genrec''', D)
|
||||||
|
|
||||||
|
.. code:: ipython2
|
||||||
|
|
||||||
|
J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'c' ['Er'] BTree-Delete ")
|
||||||
|
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
['a' 23 [] ['b' 88 [] []]]
|
||||||
|
|
||||||
|
|
||||||
|
.. code:: ipython2
|
||||||
|
|
||||||
|
J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'b' ['Er'] BTree-Delete ")
|
||||||
|
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
['a' 23 [] ['c' 44 [] []]]
|
||||||
|
|
||||||
|
|
||||||
|
.. code:: ipython2
|
||||||
|
|
||||||
|
J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'a' ['Er'] BTree-Delete ")
|
||||||
|
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
['b' 88 [] ['c' 44 [] []]]
|
||||||
|
|
||||||
|
|
||||||
|
.. code:: ipython2
|
||||||
|
|
||||||
|
J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'der' ['Er'] BTree-Delete ")
|
||||||
|
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
['a' 23 [] ['b' 88 [] ['c' 44 [] 'Er' 'der' []]]]
|
||||||
|
|
||||||
|
|
||||||
|
.. code:: ipython2
|
||||||
|
|
||||||
|
J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'der' [pop] BTree-Delete ")
|
||||||
|
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
['a' 23 [] ['b' 88 [] ['c' 44 [] []]]]
|
||||||
|
|
||||||
|
|
||||||
|
One bug, I forgot to put ``not`` in the first two clauses of the
|
||||||
|
``cond``.
|
||||||
|
|
||||||
|
The behavior of the ``[Er]`` function should maybe be different: either
|
||||||
|
just silently fail, or maybe implement some sort of function that can
|
||||||
|
grab the pending expression up to a sentinel value or something,
|
||||||
|
allowing for a kind of "except"-ish control-flow?
|
||||||
|
|
||||||
|
Then, once we have add, get, and delete we can see about abstracting
|
||||||
|
them.
|
||||||
|
|
||||||
Tree with node and list of trees.
|
Tree with node and list of trees.
|
||||||
=================================
|
=================================
|
||||||
|
|
||||||
|
|||||||
+13048
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,499 @@
|
|||||||
|
|
||||||
|
# Treating Trees II
|
||||||
|
Let's consider a tree structure, similar to one described ["Why functional programming matters" by John Hughes](https://www.cs.kent.ac.uk/people/staff/dat/miranda/whyfp90.pdf), that consists of a node value followed by a sequence of zero or more child trees. (The asterisk is meant to indicate the [Kleene star](https://en.wikipedia.org/wiki/Kleene_star).)
|
||||||
|
|
||||||
|
tree = [] | [node tree*]
|
||||||
|
|
||||||
|
## `treestep`
|
||||||
|
In the spirit of `step` we are going to define a combinator `treestep` which expects a tree and three additional items: a base-case function `[B]`, and two quoted programs `[N]` and `[C]`.
|
||||||
|
|
||||||
|
tree [B] [N] [C] treestep
|
||||||
|
|
||||||
|
If the current tree node is empty then just execute `B`:
|
||||||
|
|
||||||
|
[] [B] [N] [C] treestep
|
||||||
|
---------------------------
|
||||||
|
[] B
|
||||||
|
|
||||||
|
Otherwise, evaluate `N` on the node value, `map` the whole function (abbreviated here as `K`) over the child trees recursively, and then combine the result with `C`.
|
||||||
|
|
||||||
|
[node tree*] [B] [N] [C] treestep
|
||||||
|
--------------------------------------- w/ K == [B] [N] [C] treestep
|
||||||
|
node N [tree*] [K] map C
|
||||||
|
|
||||||
|
(Later on we'll experiment with making `map` part of `C` so you can use other combinators.)
|
||||||
|
|
||||||
|
## Derive the recursive function.
|
||||||
|
We can begin to derive it by finding the `ifte` stage that `genrec` will produce.
|
||||||
|
|
||||||
|
K == [not] [B] [R0] [R1] genrec
|
||||||
|
== [not] [B] [R0 [K] R1] ifte
|
||||||
|
|
||||||
|
So we just have to derive `J`:
|
||||||
|
|
||||||
|
J == R0 [K] R1
|
||||||
|
|
||||||
|
The behavior of `J` is to accept a (non-empty) tree node and arrive at the desired outcome.
|
||||||
|
|
||||||
|
[node tree*] J
|
||||||
|
------------------------------
|
||||||
|
node N [tree*] [K] map C
|
||||||
|
|
||||||
|
So `J` will have some form like:
|
||||||
|
|
||||||
|
J == ... [N] ... [K] ... [C] ...
|
||||||
|
|
||||||
|
Let's dive in. First, unquote the node and `dip` `N`.
|
||||||
|
|
||||||
|
[node tree*] uncons [N] dip
|
||||||
|
node [tree*] [N] dip
|
||||||
|
node N [tree*]
|
||||||
|
|
||||||
|
Next, `map` `K` over the child trees and combine with `C`.
|
||||||
|
|
||||||
|
node N [tree*] [K] map C
|
||||||
|
node N [tree*] [K] map C
|
||||||
|
node N [K.tree*] C
|
||||||
|
|
||||||
|
So:
|
||||||
|
|
||||||
|
J == uncons [N] dip [K] map C
|
||||||
|
|
||||||
|
Plug it in and convert to `genrec`:
|
||||||
|
|
||||||
|
K == [not] [B] [J ] ifte
|
||||||
|
== [not] [B] [uncons [N] dip [K] map C] ifte
|
||||||
|
== [not] [B] [uncons [N] dip] [map C] genrec
|
||||||
|
|
||||||
|
## Extract the givens to parameterize the program.
|
||||||
|
Working backwards:
|
||||||
|
|
||||||
|
[not] [B] [uncons [N] dip] [map C] genrec
|
||||||
|
[B] [not] swap [uncons [N] dip] [map C] genrec
|
||||||
|
[B] [uncons [N] dip] [[not] swap] dip [map C] genrec
|
||||||
|
^^^^^^^^^^^^^^^^
|
||||||
|
[B] [[N] dip] [uncons] swoncat [[not] swap] dip [map C] genrec
|
||||||
|
[B] [N] [dip] cons [uncons] swoncat [[not] swap] dip [map C] genrec
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Extract a couple of auxiliary definitions:
|
||||||
|
|
||||||
|
TS.0 == [[not] swap] dip
|
||||||
|
TS.1 == [dip] cons [uncons] swoncat
|
||||||
|
|
||||||
|
[B] [N] TS.1 TS.0 [map C] genrec
|
||||||
|
[B] [N] [map C] [TS.1 TS.0] dip genrec
|
||||||
|
[B] [N] [C] [map] swoncat [TS.1 TS.0] dip genrec
|
||||||
|
|
||||||
|
The givens are all to the left so we have our definition.
|
||||||
|
|
||||||
|
### (alternate) Extract the givens to parameterize the program.
|
||||||
|
Working backwards:
|
||||||
|
|
||||||
|
[not] [B] [uncons [N] dip] [map C] genrec
|
||||||
|
[not] [B] [N] [dip] cons [uncons] swoncat [map C] genrec
|
||||||
|
[B] [N] [not] roll> [dip] cons [uncons] swoncat [map C] genrec
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
## Define `treestep`
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
from notebook_preamble import D, J, V, define, DefinitionWrapper
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
DefinitionWrapper.add_definitions('''
|
||||||
|
|
||||||
|
_treestep_0 == [[not] swap] dip
|
||||||
|
_treestep_1 == [dip] cons [uncons] swoncat
|
||||||
|
treegrind == [_treestep_1 _treestep_0] dip genrec
|
||||||
|
treestep == [map] swoncat treegrind
|
||||||
|
|
||||||
|
''', D)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
Consider trees, the nodes of which are integers. We can find the sum of all nodes in a tree with this function:
|
||||||
|
|
||||||
|
sumtree == [pop 0] [] [sum +] treestep
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
define('sumtree == [pop 0] [] [sum +] treestep')
|
||||||
|
```
|
||||||
|
|
||||||
|
Running this function on an empty tree value gives zero:
|
||||||
|
|
||||||
|
[] [pop 0] [] [sum +] treestep
|
||||||
|
------------------------------------
|
||||||
|
0
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
J('[] sumtree') # Empty tree.
|
||||||
|
```
|
||||||
|
|
||||||
|
0
|
||||||
|
|
||||||
|
|
||||||
|
Running it on a non-empty node:
|
||||||
|
|
||||||
|
[n tree*] [pop 0] [] [sum +] treestep
|
||||||
|
n [tree*] [[pop 0] [] [sum +] treestep] map sum +
|
||||||
|
n [ ... ] sum +
|
||||||
|
n m +
|
||||||
|
n+m
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
J('[23] sumtree') # No child trees.
|
||||||
|
```
|
||||||
|
|
||||||
|
23
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
J('[23 []] sumtree') # Child tree, empty.
|
||||||
|
```
|
||||||
|
|
||||||
|
23
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
J('[23 [2 [4]] [3]] sumtree') # Non-empty child trees.
|
||||||
|
```
|
||||||
|
|
||||||
|
32
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
J('[23 [2 [8] [9]] [3] [4 []]] sumtree') # Etc...
|
||||||
|
```
|
||||||
|
|
||||||
|
49
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
J('[23 [2 [8] [9]] [3] [4 []]] [pop 0] [] [cons sum] treestep') # Alternate "spelling".
|
||||||
|
```
|
||||||
|
|
||||||
|
49
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
J('[23 [2 [8] [9]] [3] [4 []]] [] [pop 23] [cons] treestep') # Replace each node.
|
||||||
|
```
|
||||||
|
|
||||||
|
[23 [23 [23] [23]] [23] [23 []]]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
J('[23 [2 [8] [9]] [3] [4 []]] [] [pop 1] [cons] treestep')
|
||||||
|
```
|
||||||
|
|
||||||
|
[1 [1 [1] [1]] [1] [1 []]]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
J('[23 [2 [8] [9]] [3] [4 []]] [] [pop 1] [cons] treestep sumtree')
|
||||||
|
```
|
||||||
|
|
||||||
|
6
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
J('[23 [2 [8] [9]] [3] [4 []]] [pop 0] [pop 1] [sum +] treestep') # Combine replace and sum into one function.
|
||||||
|
```
|
||||||
|
|
||||||
|
6
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
J('[4 [3 [] [7]]] [pop 0] [pop 1] [sum +] treestep') # Combine replace and sum into one function.
|
||||||
|
```
|
||||||
|
|
||||||
|
3
|
||||||
|
|
||||||
|
|
||||||
|
## Redefining the Ordered Binary Tree in terms of `treestep`.
|
||||||
|
|
||||||
|
Tree = [] | [[key value] left right]
|
||||||
|
|
||||||
|
What kind of functions can we write for this with our `treestep`?
|
||||||
|
|
||||||
|
The pattern for processing a non-empty node is:
|
||||||
|
|
||||||
|
node N [tree*] [K] map C
|
||||||
|
|
||||||
|
Plugging in our BTree structure:
|
||||||
|
|
||||||
|
[key value] N [left right] [K] map C
|
||||||
|
|
||||||
|
### Traversal
|
||||||
|
[key value] first [left right] [K] map i
|
||||||
|
key [value] [left right] [K] map i
|
||||||
|
key [left right] [K] map i
|
||||||
|
key [lkey rkey ] i
|
||||||
|
key lkey rkey
|
||||||
|
|
||||||
|
This doesn't quite work:
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
J('[[3 0] [[2 0] [][]] [[9 0] [[5 0] [[4 0] [][]] [[8 0] [[6 0] [] [[7 0] [][]]][]]][]]] ["B"] [first] [i] treestep')
|
||||||
|
```
|
||||||
|
|
||||||
|
3 'B' 'B'
|
||||||
|
|
||||||
|
|
||||||
|
Doesn't work because `map` extracts the `first` item of whatever its mapped function produces. We have to return a list, rather than depositing our results directly on the stack.
|
||||||
|
|
||||||
|
|
||||||
|
[key value] N [left right] [K] map C
|
||||||
|
|
||||||
|
[key value] first [left right] [K] map flatten cons
|
||||||
|
key [left right] [K] map flatten cons
|
||||||
|
key [[lk] [rk] ] flatten cons
|
||||||
|
key [ lk rk ] cons
|
||||||
|
[key lk rk ]
|
||||||
|
|
||||||
|
So:
|
||||||
|
|
||||||
|
[] [first] [flatten cons] treestep
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [] [first] [flatten cons] treestep')
|
||||||
|
```
|
||||||
|
|
||||||
|
[3 2 9 5 4 8 6 7]
|
||||||
|
|
||||||
|
|
||||||
|
There we go.
|
||||||
|
|
||||||
|
### In-order traversal
|
||||||
|
|
||||||
|
From here:
|
||||||
|
|
||||||
|
key [[lk] [rk]] C
|
||||||
|
key [[lk] [rk]] i
|
||||||
|
key [lk] [rk] roll<
|
||||||
|
[lk] [rk] key swons concat
|
||||||
|
[lk] [key rk] concat
|
||||||
|
[lk key rk]
|
||||||
|
|
||||||
|
So:
|
||||||
|
|
||||||
|
[] [i roll< swons concat] [first] treestep
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [] [uncons pop] [i roll< swons concat] treestep')
|
||||||
|
```
|
||||||
|
|
||||||
|
[2 3 4 5 6 7 8 9]
|
||||||
|
|
||||||
|
|
||||||
|
## With `treegrind`?
|
||||||
|
The `treegrind` function doesn't include the `map` combinator, so the `[C]` function must arrange to use some combinator on the quoted recursive copy `[K]`. With this function, the pattern for processing a non-empty node is:
|
||||||
|
|
||||||
|
node N [tree*] [K] C
|
||||||
|
|
||||||
|
Plugging in our BTree structure:
|
||||||
|
|
||||||
|
[key value] N [left right] [K] C
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
J('[["key" "value"] ["left"] ["right"] ] ["B"] ["N"] ["C"] treegrind')
|
||||||
|
```
|
||||||
|
|
||||||
|
['key' 'value'] 'N' [['left'] ['right']] [[not] ['B'] [uncons ['N'] dip] ['C'] genrec] 'C'
|
||||||
|
|
||||||
|
|
||||||
|
## `treegrind` with `step`
|
||||||
|
|
||||||
|
Iteration through the nodes
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [pop] ["N"] [step] treegrind')
|
||||||
|
```
|
||||||
|
|
||||||
|
[3 0] 'N' [2 0] 'N' [9 0] 'N' [5 0] 'N' [4 0] 'N' [8 0] 'N' [6 0] 'N' [7 0] 'N'
|
||||||
|
|
||||||
|
|
||||||
|
Sum the nodes' keys.
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
J('0 [[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [pop] [first +] [step] treegrind')
|
||||||
|
```
|
||||||
|
|
||||||
|
44
|
||||||
|
|
||||||
|
|
||||||
|
Rebuild the tree using `map` (imitating `treestep`.)
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [] [[100 +] infra] [map cons] treegrind')
|
||||||
|
```
|
||||||
|
|
||||||
|
[[103 0] [[102 0] [] []] [[109 0] [[105 0] [[104 0] [] []] [[108 0] [[106 0] [] [[107 0] [] []]] []]] []]]
|
||||||
|
|
||||||
|
|
||||||
|
## Do we have the flexibility to reimplement `Tree-get`?
|
||||||
|
I think we do:
|
||||||
|
|
||||||
|
[B] [N] [C] treegrind
|
||||||
|
|
||||||
|
We'll start by saying that the base-case (the key is not in the tree) is user defined, and the per-node function is just the query key literal:
|
||||||
|
|
||||||
|
[B] [query_key] [C] treegrind
|
||||||
|
|
||||||
|
This means we just have to define `C` from:
|
||||||
|
|
||||||
|
[key value] query_key [left right] [K] C
|
||||||
|
|
||||||
|
|
||||||
|
Let's try `cmp`:
|
||||||
|
|
||||||
|
C == P [T>] [E] [T<] cmp
|
||||||
|
|
||||||
|
[key value] query_key [left right] [K] P [T>] [E] [T<] cmp
|
||||||
|
|
||||||
|
### The predicate `P`
|
||||||
|
Seems pretty easy (we must preserve the value in case the keys are equal):
|
||||||
|
|
||||||
|
[key value] query_key [left right] [K] P
|
||||||
|
[key value] query_key [left right] [K] roll<
|
||||||
|
[key value] [left right] [K] query_key [roll< uncons swap] dip
|
||||||
|
|
||||||
|
[key value] [left right] [K] roll< uncons swap query_key
|
||||||
|
[left right] [K] [key value] uncons swap query_key
|
||||||
|
[left right] [K] key [value] swap query_key
|
||||||
|
[left right] [K] [value] key query_key
|
||||||
|
|
||||||
|
P == roll< [roll< uncons swap] dip
|
||||||
|
|
||||||
|
(Possibly with a swap at the end? Or just swap `T<` and `T>`.)
|
||||||
|
|
||||||
|
So now:
|
||||||
|
|
||||||
|
[left right] [K] [value] key query_key [T>] [E] [T<] cmp
|
||||||
|
|
||||||
|
Becomes one of these three:
|
||||||
|
|
||||||
|
[left right] [K] [value] T>
|
||||||
|
[left right] [K] [value] E
|
||||||
|
[left right] [K] [value] T<
|
||||||
|
|
||||||
|
|
||||||
|
### `E`
|
||||||
|
Easy.
|
||||||
|
|
||||||
|
E == roll> popop first
|
||||||
|
|
||||||
|
### `T<` and `T>`
|
||||||
|
|
||||||
|
T< == pop [first] dip i
|
||||||
|
T> == pop [second] dip i
|
||||||
|
|
||||||
|
## Putting it together
|
||||||
|
|
||||||
|
|
||||||
|
T> == pop [first] dip i
|
||||||
|
T< == pop [second] dip i
|
||||||
|
E == roll> popop first
|
||||||
|
P == roll< [roll< uncons swap] dip
|
||||||
|
|
||||||
|
Tree-get == [P [T>] [E] [T<] cmp] treegrind
|
||||||
|
|
||||||
|
To me, that seems simpler than the `genrec` version.
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
DefinitionWrapper.add_definitions('''
|
||||||
|
|
||||||
|
T> == pop [first] dip i
|
||||||
|
T< == pop [second] dip i
|
||||||
|
E == roll> popop first
|
||||||
|
P == roll< [roll< uncons swap] dip
|
||||||
|
|
||||||
|
Tree-get == [P [T>] [E] [T<] cmp] treegrind
|
||||||
|
|
||||||
|
''', D)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
from joy.library import FunctionWrapper
|
||||||
|
from joy.utils.stack import pushback
|
||||||
|
|
||||||
|
|
||||||
|
@FunctionWrapper
|
||||||
|
def cmp_(stack, expression, dictionary):
|
||||||
|
'''
|
||||||
|
cmp takes two values and three quoted programs on the stack and runs
|
||||||
|
one of the three depending on the results of comparing the two values:
|
||||||
|
|
||||||
|
a b [G] [E] [L] cmp
|
||||||
|
------------------------- a > b
|
||||||
|
G
|
||||||
|
|
||||||
|
a b [G] [E] [L] cmp
|
||||||
|
------------------------- a = b
|
||||||
|
E
|
||||||
|
|
||||||
|
a b [G] [E] [L] cmp
|
||||||
|
------------------------- a < b
|
||||||
|
L
|
||||||
|
'''
|
||||||
|
L, (E, (G, (b, (a, stack)))) = stack
|
||||||
|
expression = pushback(G if a > b else L if a < b else E, expression)
|
||||||
|
return stack, expression, dictionary
|
||||||
|
|
||||||
|
|
||||||
|
D['cmp'] = cmp_
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
J('''\
|
||||||
|
|
||||||
|
[[3 13] [[2 12] [] []] [[9 19] [[5 15] [[4 14] [] []] [[8 18] [[6 16] [] [[7 17] [] []]] []]] []]]
|
||||||
|
|
||||||
|
[] [5] Tree-get
|
||||||
|
|
||||||
|
''')
|
||||||
|
```
|
||||||
|
|
||||||
|
15
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
J('''\
|
||||||
|
|
||||||
|
[[3 13] [[2 12] [] []] [[9 19] [[5 15] [[4 14] [] []] [[8 18] [[6 16] [] [[7 17] [] []]] []]] []]]
|
||||||
|
|
||||||
|
[pop "nope"] [25] Tree-get
|
||||||
|
|
||||||
|
''')
|
||||||
|
```
|
||||||
|
|
||||||
|
'nope'
|
||||||
|
|
||||||
@@ -0,0 +1,655 @@
|
|||||||
|
|
||||||
|
Treating Trees II
|
||||||
|
=================
|
||||||
|
|
||||||
|
Let's consider a tree structure, similar to one described `"Why
|
||||||
|
functional programming matters" by John
|
||||||
|
Hughes <https://www.cs.kent.ac.uk/people/staff/dat/miranda/whyfp90.pdf>`__,
|
||||||
|
that consists of a node value followed by a sequence of zero or more
|
||||||
|
child trees. (The asterisk is meant to indicate the `Kleene
|
||||||
|
star <https://en.wikipedia.org/wiki/Kleene_star>`__.)
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
tree = [] | [node tree*]
|
||||||
|
|
||||||
|
``treestep``
|
||||||
|
------------
|
||||||
|
|
||||||
|
In the spirit of ``step`` we are going to define a combinator
|
||||||
|
``treestep`` which expects a tree and three additional items: a
|
||||||
|
base-case function ``[B]``, and two quoted programs ``[N]`` and ``[C]``.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
tree [B] [N] [C] treestep
|
||||||
|
|
||||||
|
If the current tree node is empty then just execute ``B``:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[] [B] [N] [C] treestep
|
||||||
|
---------------------------
|
||||||
|
[] B
|
||||||
|
|
||||||
|
Otherwise, evaluate ``N`` on the node value, ``map`` the whole function
|
||||||
|
(abbreviated here as ``K``) over the child trees recursively, and then
|
||||||
|
combine the result with ``C``.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[node tree*] [B] [N] [C] treestep
|
||||||
|
--------------------------------------- w/ K == [B] [N] [C] treestep
|
||||||
|
node N [tree*] [K] map C
|
||||||
|
|
||||||
|
(Later on we'll experiment with making ``map`` part of ``C`` so you can
|
||||||
|
use other combinators.)
|
||||||
|
|
||||||
|
Derive the recursive function.
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
We can begin to derive it by finding the ``ifte`` stage that ``genrec``
|
||||||
|
will produce.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
K == [not] [B] [R0] [R1] genrec
|
||||||
|
== [not] [B] [R0 [K] R1] ifte
|
||||||
|
|
||||||
|
So we just have to derive ``J``:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
J == R0 [K] R1
|
||||||
|
|
||||||
|
The behavior of ``J`` is to accept a (non-empty) tree node and arrive at
|
||||||
|
the desired outcome.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[node tree*] J
|
||||||
|
------------------------------
|
||||||
|
node N [tree*] [K] map C
|
||||||
|
|
||||||
|
So ``J`` will have some form like:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
J == ... [N] ... [K] ... [C] ...
|
||||||
|
|
||||||
|
Let's dive in. First, unquote the node and ``dip`` ``N``.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[node tree*] uncons [N] dip
|
||||||
|
node [tree*] [N] dip
|
||||||
|
node N [tree*]
|
||||||
|
|
||||||
|
Next, ``map`` ``K`` over the child trees and combine with ``C``.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
node N [tree*] [K] map C
|
||||||
|
node N [tree*] [K] map C
|
||||||
|
node N [K.tree*] C
|
||||||
|
|
||||||
|
So:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
J == uncons [N] dip [K] map C
|
||||||
|
|
||||||
|
Plug it in and convert to ``genrec``:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
K == [not] [B] [J ] ifte
|
||||||
|
== [not] [B] [uncons [N] dip [K] map C] ifte
|
||||||
|
== [not] [B] [uncons [N] dip] [map C] genrec
|
||||||
|
|
||||||
|
Extract the givens to parameterize the program.
|
||||||
|
-----------------------------------------------
|
||||||
|
|
||||||
|
Working backwards:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[not] [B] [uncons [N] dip] [map C] genrec
|
||||||
|
[B] [not] swap [uncons [N] dip] [map C] genrec
|
||||||
|
[B] [uncons [N] dip] [[not] swap] dip [map C] genrec
|
||||||
|
^^^^^^^^^^^^^^^^
|
||||||
|
[B] [[N] dip] [uncons] swoncat [[not] swap] dip [map C] genrec
|
||||||
|
[B] [N] [dip] cons [uncons] swoncat [[not] swap] dip [map C] genrec
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Extract a couple of auxiliary definitions:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
TS.0 == [[not] swap] dip
|
||||||
|
TS.1 == [dip] cons [uncons] swoncat
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[B] [N] TS.1 TS.0 [map C] genrec
|
||||||
|
[B] [N] [map C] [TS.1 TS.0] dip genrec
|
||||||
|
[B] [N] [C] [map] swoncat [TS.1 TS.0] dip genrec
|
||||||
|
|
||||||
|
The givens are all to the left so we have our definition.
|
||||||
|
|
||||||
|
(alternate) Extract the givens to parameterize the program.
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Working backwards:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[not] [B] [uncons [N] dip] [map C] genrec
|
||||||
|
[not] [B] [N] [dip] cons [uncons] swoncat [map C] genrec
|
||||||
|
[B] [N] [not] roll> [dip] cons [uncons] swoncat [map C] genrec
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Define ``treestep``
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
.. code:: ipython2
|
||||||
|
|
||||||
|
from notebook_preamble import D, J, V, define, DefinitionWrapper
|
||||||
|
|
||||||
|
.. code:: ipython2
|
||||||
|
|
||||||
|
DefinitionWrapper.add_definitions('''
|
||||||
|
|
||||||
|
_treestep_0 == [[not] swap] dip
|
||||||
|
_treestep_1 == [dip] cons [uncons] swoncat
|
||||||
|
treegrind == [_treestep_1 _treestep_0] dip genrec
|
||||||
|
treestep == [map] swoncat treegrind
|
||||||
|
|
||||||
|
''', D)
|
||||||
|
|
||||||
|
Examples
|
||||||
|
--------
|
||||||
|
|
||||||
|
Consider trees, the nodes of which are integers. We can find the sum of
|
||||||
|
all nodes in a tree with this function:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
sumtree == [pop 0] [] [sum +] treestep
|
||||||
|
|
||||||
|
.. code:: ipython2
|
||||||
|
|
||||||
|
define('sumtree == [pop 0] [] [sum +] treestep')
|
||||||
|
|
||||||
|
Running this function on an empty tree value gives zero:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[] [pop 0] [] [sum +] treestep
|
||||||
|
------------------------------------
|
||||||
|
0
|
||||||
|
|
||||||
|
.. code:: ipython2
|
||||||
|
|
||||||
|
J('[] sumtree') # Empty tree.
|
||||||
|
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
0
|
||||||
|
|
||||||
|
|
||||||
|
Running it on a non-empty node:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[n tree*] [pop 0] [] [sum +] treestep
|
||||||
|
n [tree*] [[pop 0] [] [sum +] treestep] map sum +
|
||||||
|
n [ ... ] sum +
|
||||||
|
n m +
|
||||||
|
n+m
|
||||||
|
|
||||||
|
.. code:: ipython2
|
||||||
|
|
||||||
|
J('[23] sumtree') # No child trees.
|
||||||
|
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
23
|
||||||
|
|
||||||
|
|
||||||
|
.. code:: ipython2
|
||||||
|
|
||||||
|
J('[23 []] sumtree') # Child tree, empty.
|
||||||
|
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
23
|
||||||
|
|
||||||
|
|
||||||
|
.. code:: ipython2
|
||||||
|
|
||||||
|
J('[23 [2 [4]] [3]] sumtree') # Non-empty child trees.
|
||||||
|
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
32
|
||||||
|
|
||||||
|
|
||||||
|
.. code:: ipython2
|
||||||
|
|
||||||
|
J('[23 [2 [8] [9]] [3] [4 []]] sumtree') # Etc...
|
||||||
|
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
49
|
||||||
|
|
||||||
|
|
||||||
|
.. code:: ipython2
|
||||||
|
|
||||||
|
J('[23 [2 [8] [9]] [3] [4 []]] [pop 0] [] [cons sum] treestep') # Alternate "spelling".
|
||||||
|
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
49
|
||||||
|
|
||||||
|
|
||||||
|
.. code:: ipython2
|
||||||
|
|
||||||
|
J('[23 [2 [8] [9]] [3] [4 []]] [] [pop 23] [cons] treestep') # Replace each node.
|
||||||
|
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
[23 [23 [23] [23]] [23] [23 []]]
|
||||||
|
|
||||||
|
|
||||||
|
.. code:: ipython2
|
||||||
|
|
||||||
|
J('[23 [2 [8] [9]] [3] [4 []]] [] [pop 1] [cons] treestep')
|
||||||
|
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
[1 [1 [1] [1]] [1] [1 []]]
|
||||||
|
|
||||||
|
|
||||||
|
.. code:: ipython2
|
||||||
|
|
||||||
|
J('[23 [2 [8] [9]] [3] [4 []]] [] [pop 1] [cons] treestep sumtree')
|
||||||
|
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
6
|
||||||
|
|
||||||
|
|
||||||
|
.. code:: ipython2
|
||||||
|
|
||||||
|
J('[23 [2 [8] [9]] [3] [4 []]] [pop 0] [pop 1] [sum +] treestep') # Combine replace and sum into one function.
|
||||||
|
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
6
|
||||||
|
|
||||||
|
|
||||||
|
.. code:: ipython2
|
||||||
|
|
||||||
|
J('[4 [3 [] [7]]] [pop 0] [pop 1] [sum +] treestep') # Combine replace and sum into one function.
|
||||||
|
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
3
|
||||||
|
|
||||||
|
|
||||||
|
Redefining the Ordered Binary Tree in terms of ``treestep``.
|
||||||
|
------------------------------------------------------------
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
Tree = [] | [[key value] left right]
|
||||||
|
|
||||||
|
What kind of functions can we write for this with our ``treestep``?
|
||||||
|
|
||||||
|
The pattern for processing a non-empty node is:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
node N [tree*] [K] map C
|
||||||
|
|
||||||
|
Plugging in our BTree structure:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[key value] N [left right] [K] map C
|
||||||
|
|
||||||
|
Traversal
|
||||||
|
~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[key value] first [left right] [K] map i
|
||||||
|
key [value] [left right] [K] map i
|
||||||
|
key [left right] [K] map i
|
||||||
|
key [lkey rkey ] i
|
||||||
|
key lkey rkey
|
||||||
|
|
||||||
|
This doesn't quite work:
|
||||||
|
|
||||||
|
.. code:: ipython2
|
||||||
|
|
||||||
|
J('[[3 0] [[2 0] [][]] [[9 0] [[5 0] [[4 0] [][]] [[8 0] [[6 0] [] [[7 0] [][]]][]]][]]] ["B"] [first] [i] treestep')
|
||||||
|
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
3 'B' 'B'
|
||||||
|
|
||||||
|
|
||||||
|
Doesn't work because ``map`` extracts the ``first`` item of whatever its
|
||||||
|
mapped function produces. We have to return a list, rather than
|
||||||
|
depositing our results directly on the stack.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[key value] N [left right] [K] map C
|
||||||
|
|
||||||
|
[key value] first [left right] [K] map flatten cons
|
||||||
|
key [left right] [K] map flatten cons
|
||||||
|
key [[lk] [rk] ] flatten cons
|
||||||
|
key [ lk rk ] cons
|
||||||
|
[key lk rk ]
|
||||||
|
|
||||||
|
So:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[] [first] [flatten cons] treestep
|
||||||
|
|
||||||
|
.. code:: ipython2
|
||||||
|
|
||||||
|
J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [] [first] [flatten cons] treestep')
|
||||||
|
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
[3 2 9 5 4 8 6 7]
|
||||||
|
|
||||||
|
|
||||||
|
There we go.
|
||||||
|
|
||||||
|
In-order traversal
|
||||||
|
~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
From here:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
key [[lk] [rk]] C
|
||||||
|
key [[lk] [rk]] i
|
||||||
|
key [lk] [rk] roll<
|
||||||
|
[lk] [rk] key swons concat
|
||||||
|
[lk] [key rk] concat
|
||||||
|
[lk key rk]
|
||||||
|
|
||||||
|
So:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[] [i roll< swons concat] [first] treestep
|
||||||
|
|
||||||
|
.. code:: ipython2
|
||||||
|
|
||||||
|
J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [] [uncons pop] [i roll< swons concat] treestep')
|
||||||
|
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
[2 3 4 5 6 7 8 9]
|
||||||
|
|
||||||
|
|
||||||
|
With ``treegrind``?
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
The ``treegrind`` function doesn't include the ``map`` combinator, so
|
||||||
|
the ``[C]`` function must arrange to use some combinator on the quoted
|
||||||
|
recursive copy ``[K]``. With this function, the pattern for processing a
|
||||||
|
non-empty node is:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
node N [tree*] [K] C
|
||||||
|
|
||||||
|
Plugging in our BTree structure:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[key value] N [left right] [K] C
|
||||||
|
|
||||||
|
.. code:: ipython2
|
||||||
|
|
||||||
|
J('[["key" "value"] ["left"] ["right"] ] ["B"] ["N"] ["C"] treegrind')
|
||||||
|
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
['key' 'value'] 'N' [['left'] ['right']] [[not] ['B'] [uncons ['N'] dip] ['C'] genrec] 'C'
|
||||||
|
|
||||||
|
|
||||||
|
``treegrind`` with ``step``
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
Iteration through the nodes
|
||||||
|
|
||||||
|
.. code:: ipython2
|
||||||
|
|
||||||
|
J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [pop] ["N"] [step] treegrind')
|
||||||
|
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
[3 0] 'N' [2 0] 'N' [9 0] 'N' [5 0] 'N' [4 0] 'N' [8 0] 'N' [6 0] 'N' [7 0] 'N'
|
||||||
|
|
||||||
|
|
||||||
|
Sum the nodes' keys.
|
||||||
|
|
||||||
|
.. code:: ipython2
|
||||||
|
|
||||||
|
J('0 [[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [pop] [first +] [step] treegrind')
|
||||||
|
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
44
|
||||||
|
|
||||||
|
|
||||||
|
Rebuild the tree using ``map`` (imitating ``treestep``.)
|
||||||
|
|
||||||
|
.. code:: ipython2
|
||||||
|
|
||||||
|
J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [] [[100 +] infra] [map cons] treegrind')
|
||||||
|
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
[[103 0] [[102 0] [] []] [[109 0] [[105 0] [[104 0] [] []] [[108 0] [[106 0] [] [[107 0] [] []]] []]] []]]
|
||||||
|
|
||||||
|
|
||||||
|
Do we have the flexibility to reimplement ``Tree-get``?
|
||||||
|
-------------------------------------------------------
|
||||||
|
|
||||||
|
I think we do:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[B] [N] [C] treegrind
|
||||||
|
|
||||||
|
We'll start by saying that the base-case (the key is not in the tree) is
|
||||||
|
user defined, and the per-node function is just the query key literal:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[B] [query_key] [C] treegrind
|
||||||
|
|
||||||
|
This means we just have to define ``C`` from:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[key value] query_key [left right] [K] C
|
||||||
|
|
||||||
|
Let's try ``cmp``:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
C == P [T>] [E] [T<] cmp
|
||||||
|
|
||||||
|
[key value] query_key [left right] [K] P [T>] [E] [T<] cmp
|
||||||
|
|
||||||
|
The predicate ``P``
|
||||||
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Seems pretty easy (we must preserve the value in case the keys are
|
||||||
|
equal):
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[key value] query_key [left right] [K] P
|
||||||
|
[key value] query_key [left right] [K] roll<
|
||||||
|
[key value] [left right] [K] query_key [roll< uncons swap] dip
|
||||||
|
|
||||||
|
[key value] [left right] [K] roll< uncons swap query_key
|
||||||
|
[left right] [K] [key value] uncons swap query_key
|
||||||
|
[left right] [K] key [value] swap query_key
|
||||||
|
[left right] [K] [value] key query_key
|
||||||
|
|
||||||
|
P == roll< [roll< uncons swap] dip
|
||||||
|
|
||||||
|
(Possibly with a swap at the end? Or just swap ``T<`` and ``T>``.)
|
||||||
|
|
||||||
|
So now:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[left right] [K] [value] key query_key [T>] [E] [T<] cmp
|
||||||
|
|
||||||
|
Becomes one of these three:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[left right] [K] [value] T>
|
||||||
|
[left right] [K] [value] E
|
||||||
|
[left right] [K] [value] T<
|
||||||
|
|
||||||
|
``E``
|
||||||
|
~~~~~
|
||||||
|
|
||||||
|
Easy.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
E == roll> popop first
|
||||||
|
|
||||||
|
``T<`` and ``T>``
|
||||||
|
~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
T< == pop [first] dip i
|
||||||
|
T> == pop [second] dip i
|
||||||
|
|
||||||
|
Putting it together
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
T> == pop [first] dip i
|
||||||
|
T< == pop [second] dip i
|
||||||
|
E == roll> popop first
|
||||||
|
P == roll< [roll< uncons swap] dip
|
||||||
|
|
||||||
|
Tree-get == [P [T>] [E] [T<] cmp] treegrind
|
||||||
|
|
||||||
|
To me, that seems simpler than the ``genrec`` version.
|
||||||
|
|
||||||
|
.. code:: ipython2
|
||||||
|
|
||||||
|
DefinitionWrapper.add_definitions('''
|
||||||
|
|
||||||
|
T> == pop [first] dip i
|
||||||
|
T< == pop [second] dip i
|
||||||
|
E == roll> popop first
|
||||||
|
P == roll< [roll< uncons swap] dip
|
||||||
|
|
||||||
|
Tree-get == [P [T>] [E] [T<] cmp] treegrind
|
||||||
|
|
||||||
|
''', D)
|
||||||
|
|
||||||
|
.. code:: ipython2
|
||||||
|
|
||||||
|
from joy.library import FunctionWrapper
|
||||||
|
from joy.utils.stack import pushback
|
||||||
|
|
||||||
|
|
||||||
|
@FunctionWrapper
|
||||||
|
def cmp_(stack, expression, dictionary):
|
||||||
|
'''
|
||||||
|
cmp takes two values and three quoted programs on the stack and runs
|
||||||
|
one of the three depending on the results of comparing the two values:
|
||||||
|
|
||||||
|
a b [G] [E] [L] cmp
|
||||||
|
------------------------- a > b
|
||||||
|
G
|
||||||
|
|
||||||
|
a b [G] [E] [L] cmp
|
||||||
|
------------------------- a = b
|
||||||
|
E
|
||||||
|
|
||||||
|
a b [G] [E] [L] cmp
|
||||||
|
------------------------- a < b
|
||||||
|
L
|
||||||
|
'''
|
||||||
|
L, (E, (G, (b, (a, stack)))) = stack
|
||||||
|
expression = pushback(G if a > b else L if a < b else E, expression)
|
||||||
|
return stack, expression, dictionary
|
||||||
|
|
||||||
|
|
||||||
|
D['cmp'] = cmp_
|
||||||
|
|
||||||
|
.. code:: ipython2
|
||||||
|
|
||||||
|
J('''\
|
||||||
|
|
||||||
|
[[3 13] [[2 12] [] []] [[9 19] [[5 15] [[4 14] [] []] [[8 18] [[6 16] [] [[7 17] [] []]] []]] []]]
|
||||||
|
|
||||||
|
[] [5] Tree-get
|
||||||
|
|
||||||
|
''')
|
||||||
|
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
15
|
||||||
|
|
||||||
|
|
||||||
|
.. code:: ipython2
|
||||||
|
|
||||||
|
J('''\
|
||||||
|
|
||||||
|
[[3 13] [[2 12] [] []] [[9 19] [[5 15] [[4 14] [] []] [[8 18] [[6 16] [] [[7 17] [] []]] []]] []]]
|
||||||
|
|
||||||
|
[pop "nope"] [25] Tree-get
|
||||||
|
|
||||||
|
''')
|
||||||
|
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
'nope'
|
||||||
|
|
||||||
Binary file not shown.
Reference in New Issue
Block a user