Regenerated docs.
This commit is contained in:
parent
9a04534b05
commit
be6387f1f6
|
|
@ -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``
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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,13 +99,11 @@ 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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,19 +121,16 @@ 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
733
docs/Trees.html
733
docs/Trees.html
|
|
@ -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>
|
||||||
|
|
|
||||||
374
docs/Trees.md
374
docs/Trees.md
|
|
@ -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).)
|
||||||
|
|
||||||
|
|
|
||||||
467
docs/Trees.rst
467
docs/Trees.rst
|
|
@ -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.
|
||||||
=================================
|
=================================
|
||||||
|
|
||||||
|
|
|
||||||
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.
Loading…
Reference in New Issue