Rebuild docs
This commit is contained in:
+109
-109
@@ -1,8 +1,8 @@
|
||||
Treating Trees II: ``treestep``
|
||||
===============================
|
||||
|
||||
Let's consider a tree structure, similar to one described `"Why
|
||||
functional programming matters" by John
|
||||
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 zero or more child trees. (The
|
||||
asterisk is meant to indicate the `Kleene
|
||||
@@ -10,7 +10,7 @@ star <https://en.wikipedia.org/wiki/Kleene_star>`__.)
|
||||
|
||||
::
|
||||
|
||||
tree = [] | [node tree*]
|
||||
tree = [] | [node tree*]
|
||||
|
||||
In the spirit of ``step`` we are going to define a combinator
|
||||
``treestep`` which expects a tree and three additional items: a
|
||||
@@ -18,15 +18,15 @@ base-case function ``[B]``, and two quoted programs ``[N]`` and ``[C]``.
|
||||
|
||||
::
|
||||
|
||||
tree [B] [N] [C] treestep
|
||||
tree [B] [N] [C] treestep
|
||||
|
||||
If the current tree node is empty then just execute ``B``:
|
||||
|
||||
::
|
||||
|
||||
[] [B] [N] [C] treestep
|
||||
---------------------------
|
||||
[] 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
|
||||
@@ -34,11 +34,11 @@ combine the result with ``C``.
|
||||
|
||||
::
|
||||
|
||||
[node tree*] [B] [N] [C] treestep
|
||||
--------------------------------------- w/ K == [B] [N] [C] treestep
|
||||
node N [tree*] [K] map 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
|
||||
(Later on we’ll experiment with making ``map`` part of ``C`` so you can
|
||||
use other combinators.)
|
||||
|
||||
Derive the recursive function.
|
||||
@@ -49,59 +49,59 @@ will produce.
|
||||
|
||||
::
|
||||
|
||||
K == [not] [B] [R0] [R1] genrec
|
||||
== [not] [B] [R0 [K] R1] ifte
|
||||
K == [not] [B] [R0] [R1] genrec
|
||||
== [not] [B] [R0 [K] R1] ifte
|
||||
|
||||
So we just have to derive ``J``:
|
||||
|
||||
::
|
||||
|
||||
J == R0 [K] R1
|
||||
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
|
||||
[node tree*] J
|
||||
------------------------------
|
||||
node N [tree*] [K] map C
|
||||
|
||||
So ``J`` will have some form like:
|
||||
|
||||
::
|
||||
|
||||
J == ... [N] ... [K] ... [C] ...
|
||||
J == ... [N] ... [K] ... [C] ...
|
||||
|
||||
Let's dive in. First, unquote the node and ``dip`` ``N``.
|
||||
Let’s dive in. First, unquote the node and ``dip`` ``N``.
|
||||
|
||||
::
|
||||
|
||||
[node tree*] uncons [N] dip
|
||||
node [tree*] [N] dip
|
||||
node N [tree*]
|
||||
[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
|
||||
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
|
||||
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
|
||||
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.
|
||||
-----------------------------------------------
|
||||
@@ -110,26 +110,26 @@ 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
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
[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
|
||||
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
|
||||
[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.
|
||||
|
||||
@@ -140,10 +140,10 @@ 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
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
[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``
|
||||
-------------------
|
||||
@@ -171,7 +171,7 @@ all nodes in a tree with this function:
|
||||
|
||||
::
|
||||
|
||||
sumtree == [pop 0] [] [sum +] treestep
|
||||
sumtree == [pop 0] [] [sum +] treestep
|
||||
|
||||
.. code:: ipython2
|
||||
|
||||
@@ -181,9 +181,9 @@ Running this function on an empty tree value gives zero:
|
||||
|
||||
::
|
||||
|
||||
[] [pop 0] [] [sum +] treestep
|
||||
------------------------------------
|
||||
0
|
||||
[] [pop 0] [] [sum +] treestep
|
||||
------------------------------------
|
||||
0
|
||||
|
||||
.. code:: ipython2
|
||||
|
||||
@@ -199,11 +199,11 @@ 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
|
||||
[n tree*] [pop 0] [] [sum +] treestep
|
||||
n [tree*] [[pop 0] [] [sum +] treestep] map sum +
|
||||
n [ ... ] sum +
|
||||
n m +
|
||||
n+m
|
||||
|
||||
.. code:: ipython2
|
||||
|
||||
@@ -310,7 +310,7 @@ Redefining the Ordered Binary Tree in terms of ``treestep``.
|
||||
|
||||
::
|
||||
|
||||
Tree = [] | [[key value] left right]
|
||||
Tree = [] | [[key value] left right]
|
||||
|
||||
What kind of functions can we write for this with our ``treestep``?
|
||||
|
||||
@@ -318,26 +318,26 @@ The pattern for processing a non-empty node is:
|
||||
|
||||
::
|
||||
|
||||
node N [tree*] [K] map C
|
||||
node N [tree*] [K] map C
|
||||
|
||||
Plugging in our BTree structure:
|
||||
|
||||
::
|
||||
|
||||
[key value] N [left right] [K] map C
|
||||
[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
|
||||
[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:
|
||||
This doesn’t quite work:
|
||||
|
||||
.. code:: ipython2
|
||||
|
||||
@@ -349,25 +349,25 @@ This doesn't quite work:
|
||||
3 'B' 'B'
|
||||
|
||||
|
||||
Doesn't work because ``map`` extracts the ``first`` item of whatever its
|
||||
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] 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 ]
|
||||
[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
|
||||
[] [first] [flatten cons] treestep
|
||||
|
||||
.. code:: ipython2
|
||||
|
||||
@@ -388,18 +388,18 @@ 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]
|
||||
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
|
||||
[] [i roll< swons concat] [first] treestep
|
||||
|
||||
.. code:: ipython2
|
||||
|
||||
@@ -414,20 +414,20 @@ So:
|
||||
With ``treegrind``?
|
||||
-------------------
|
||||
|
||||
The ``treegrind`` function doesn't include the ``map`` combinator, so
|
||||
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
|
||||
node N [tree*] [K] C
|
||||
|
||||
Plugging in our BTree structure:
|
||||
|
||||
::
|
||||
|
||||
[key value] N [left right] [K] C
|
||||
[key value] N [left right] [K] C
|
||||
|
||||
.. code:: ipython2
|
||||
|
||||
@@ -454,7 +454,7 @@ Iteration through the nodes
|
||||
[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.
|
||||
Sum the nodes’ keys.
|
||||
|
||||
.. code:: ipython2
|
||||
|
||||
@@ -485,28 +485,28 @@ I think we do:
|
||||
|
||||
::
|
||||
|
||||
[B] [N] [C] treegrind
|
||||
[B] [N] [C] treegrind
|
||||
|
||||
We'll start by saying that the base-case (the key is not in the tree) is
|
||||
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
|
||||
[B] [query_key] [C] treegrind
|
||||
|
||||
This means we just have to define ``C`` from:
|
||||
|
||||
::
|
||||
|
||||
[key value] query_key [left right] [K] C
|
||||
[key value] query_key [left right] [K] C
|
||||
|
||||
Let's try ``cmp``:
|
||||
Let’s try ``cmp``:
|
||||
|
||||
::
|
||||
|
||||
C == P [T>] [E] [T<] cmp
|
||||
C == P [T>] [E] [T<] cmp
|
||||
|
||||
[key value] query_key [left right] [K] P [T>] [E] [T<] cmp
|
||||
[key value] query_key [left right] [K] P [T>] [E] [T<] cmp
|
||||
|
||||
The predicate ``P``
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
@@ -516,16 +516,16 @@ 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] 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
|
||||
[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
|
||||
P == roll< [roll< uncons swap] dip
|
||||
|
||||
(Possibly with a swap at the end? Or just swap ``T<`` and ``T>``.)
|
||||
|
||||
@@ -533,15 +533,15 @@ So now:
|
||||
|
||||
::
|
||||
|
||||
[left right] [K] [value] key query_key [T>] [E] [T<] cmp
|
||||
[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<
|
||||
[left right] [K] [value] T>
|
||||
[left right] [K] [value] E
|
||||
[left right] [K] [value] T<
|
||||
|
||||
``E``
|
||||
~~~~~
|
||||
@@ -550,27 +550,27 @@ Easy.
|
||||
|
||||
::
|
||||
|
||||
E == roll> popop first
|
||||
E == roll> popop first
|
||||
|
||||
``T<`` and ``T>``
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
T< == pop [first] dip i
|
||||
T> == pop [second] dip i
|
||||
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
|
||||
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
|
||||
Tree-get == [P [T>] [E] [T<] cmp] treegrind
|
||||
|
||||
To me, that seems simpler than the ``genrec`` version.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user