Rebuild docs

This commit is contained in:
Simon Forman
2020-05-17 16:40:58 -07:00
parent ef6411205d
commit 56da4690d0
84 changed files with 7456 additions and 7972 deletions
+164 -168
View File
@@ -10,44 +10,43 @@ several generic specializations.
::
[if] [then] [rec1] [rec2] genrec
---------------------------------------------------------------------
[if] [then] [rec1 [[if] [then] [rec1] [rec2] genrec] rec2] ifte
[if] [then] [rec1] [rec2] genrec
---------------------------------------------------------------------
[if] [then] [rec1 [[if] [then] [rec1] [rec2] genrec] rec2] ifte
From "Recursion Theory and Joy" (j05cmp.html) by Manfred von Thun:
From Recursion Theory and Joy (j05cmp.html) by Manfred von Thun:
"The genrec combinator takes four program parameters in addition to
whatever data parameters it needs. Fourth from the top is an
if-part, followed by a then-part. If the if-part yields true, then
the then-part is executed and the combinator terminates. The other
two parameters are the rec1-part and the rec2-part. If the if-part
yields false, the rec1-part is executed. Following that the four
program parameters and the combinator are again pushed onto the
stack bundled up in a quoted form. Then the rec2-part is executed,
where it will find the bundled form. Typically it will then execute
the bundled form, either with i or with app2, or some other
combinator."
The genrec combinator takes four program parameters in addition to
whatever data parameters it needs. Fourth from the top is an if-part,
followed by a then-part. If the if-part yields true, then the
then-part is executed and the combinator terminates. The other two
parameters are the rec1-part and the rec2-part. If the if-part yields
false, the rec1-part is executed. Following that the four program
parameters and the combinator are again pushed onto the stack bundled
up in a quoted form. Then the rec2-part is executed, where it will
find the bundled form. Typically it will then execute the bundled
form, either with i or with app2, or some other combinator.”
Designing Recursive Functions
-----------------------------
The way to design one of these is to fix your base case and test and
then treat ``R1`` and ``R2`` as an else-part "sandwiching" a quotation
then treat ``R1`` and ``R2`` as an else-part sandwiching a quotation
of the whole function.
For example, given a (general recursive) function ``F``:
::
F == [I] [T] [R1] [R2] genrec
== [I] [T] [R1 [F] R2] ifte
F == [I] [T] [R1] [R2] genrec
== [I] [T] [R1 [F] R2] ifte
If the ``[I]`` predicate is false you must derive ``R1`` and ``R2``
from:
::
... R1 [F] R2
... R1 [F] R2
Set the stack arguments in front and figure out what ``R1`` and ``R2``
have to do to apply the quoted ``[F]`` in the proper way.
@@ -59,9 +58,9 @@ Primitive recursive functions are those where ``R2 == i``.
::
P == [I] [T] [R] primrec
== [I] [T] [R [P] i] ifte
== [I] [T] [R P] ifte
P == [I] [T] [R] primrec
== [I] [T] [R [P] i] ifte
== [I] [T] [R P] ifte
`Hylomorphism <https://en.wikipedia.org/wiki/Hylomorphism_%28computer_science%29>`__
------------------------------------------------------------------------------------
@@ -75,8 +74,8 @@ is a recursive function ``H :: A -> C`` that converts a value of type
- A combiner ``F :: (B, C) -> C``
- A predicate ``P :: A -> Bool`` to detect the base case
- A base case value ``c :: C``
- Recursive calls (zero or more); it has a "call stack in the form of a
cons list".
- Recursive calls (zero or more); it has a call stack in the form of a
cons list.
It may be helpful to see this function implemented in imperative Python
code.
@@ -96,12 +95,12 @@ code.
return H
Cf. `"Bananas, Lenses, & Barbed
Wire" <http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.41.125>`__
Cf. `Bananas, Lenses, & Barbed
Wire <http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.41.125>`__
Note that during evaluation of ``H()`` the intermediate ``b`` values are
stored in the Python call stack. This is what is meant by "call stack in
the form of a cons list".
stored in the Python call stack. This is what is meant by call stack in
the form of a cons list.
Hylomorphism in Joy
-------------------
@@ -111,7 +110,7 @@ hylomorphism combinator ``H`` from constituent parts.
::
H == [P] c [G] [F] hylomorphism
H == [P] c [G] [F] hylomorphism
The function ``H`` is recursive, so we start with ``ifte`` and set the
else-part to some function ``J`` that will contain a quoted copy of
@@ -120,37 +119,37 @@ with the base case value ``c``.)
::
H == [P] [pop c] [J] ifte
H == [P] [pop c] [J] ifte
The else-part ``J`` gets just the argument ``a`` on the stack.
::
a J
a G The first thing to do is use the generator G
aa b which produces b and a new aa
aa b [H] dip we recur with H on the new aa
aa H b F and run F on the result.
a J
a G The first thing to do is use the generator G
aa b which produces b and a new aa
aa b [H] dip we recur with H on the new aa
aa H b F and run F on the result.
This gives us a definition for ``J``.
::
J == G [H] dip F
J == G [H] dip F
Plug it in and convert to genrec.
::
H == [P] [pop c] [G [H] dip F] ifte
H == [P] [pop c] [G] [dip F] genrec
H == [P] [pop c] [G [H] dip F] ifte
H == [P] [pop c] [G] [dip F] genrec
This is the form of a hylomorphism in Joy, which nicely illustrates that
it is a simple specialization of the general recursion combinator.
::
H == [P] c [G] [F] hylomorphism == [P] [pop c] [G] [dip F] genrec
H == [P] c [G] [F] hylomorphism == [P] [pop c] [G] [dip F] genrec
Derivation of ``hylomorphism`` combinator
-----------------------------------------
@@ -160,9 +159,9 @@ arguments out of the pieces given to the ``hylomorphism`` combinator.
::
[P] c [G] [F] hylomorphism
------------------------------------------
[P] [pop c] [G] [dip F] genrec
[P] c [G] [F] hylomorphism
------------------------------------------
[P] [pop c] [G] [dip F] genrec
Working in reverse:
@@ -174,17 +173,17 @@ So:
::
H == [P] [pop c] [G] [dip F] genrec
[P] [c] [pop] swoncat [G] [F] [dip] swoncat genrec
[P] c unit [pop] swoncat [G] [F] [dip] swoncat genrec
[P] c [G] [F] [unit [pop] swoncat] dipd [dip] swoncat genrec
H == [P] [pop c] [G] [dip F] genrec
[P] [c] [pop] swoncat [G] [F] [dip] swoncat genrec
[P] c unit [pop] swoncat [G] [F] [dip] swoncat genrec
[P] c [G] [F] [unit [pop] swoncat] dipd [dip] swoncat genrec
At this point all of the arguments (givens) to the hylomorphism are to
the left so we have a definition for ``hylomorphism``:
::
hylomorphism == [unit [pop] swoncat] dipd [dip] swoncat genrec
hylomorphism == [unit [pop] swoncat] dipd [dip] swoncat genrec
.. code:: ipython2
@@ -193,7 +192,7 @@ the left so we have a definition for ``hylomorphism``:
Example: Finding `Triangular Numbers <https://en.wikipedia.org/wiki/Triangular_number>`__
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Let's write a function that, given a positive integer, returns the sum
Lets write a function that, given a positive integer, returns the sum
of all positive integers less than that one. (In this case the types
``A``, ``B`` and ``C`` are all ``int``.)
@@ -208,7 +207,7 @@ To sum a range of integers from 0 to *n* - 1:
define('triangular_number == [1 <=] 0 [-- dup] [+] hylomorphism')
Let's try it:
Lets try it:
.. code:: ipython2
@@ -236,30 +235,30 @@ Four Specializations
There are at least four kinds of recursive combinator, depending on two
choices. The first choice is whether the combiner function ``F`` should
be evaluated during the recursion or pushed into the pending expression
to be "collapsed" at the end. The second choice is whether the combiner
to be collapsed at the end. The second choice is whether the combiner
needs to operate on the current value of the datastructure or the
generator's output, in other words, whether ``F`` or ``G`` should run
generators output, in other words, whether ``F`` or ``G`` should run
first in the recursive branch.
::
H1 == [P] [pop c] [G ] [dip F] genrec
H2 == c swap [P] [pop] [G [F] dip ] [i] genrec
H3 == [P] [pop c] [ [G] dupdip ] [dip F] genrec
H4 == c swap [P] [pop] [ [F] dupdip G] [i] genrec
H1 == [P] [pop c] [G ] [dip F] genrec
H2 == c swap [P] [pop] [G [F] dip ] [i] genrec
H3 == [P] [pop c] [ [G] dupdip ] [dip F] genrec
H4 == c swap [P] [pop] [ [F] dupdip G] [i] genrec
The working of the generator function ``G`` differs slightly for each.
Consider the recursive branches:
::
... a G [H1] dip F w/ a G == a b
... a G [H1] dip F w/ a G == a b
... c a G [F] dip H2 a G == b a
... c a G [F] dip H2 a G == b a
... a [G] dupdip [H3] dip F a G == a
... a [G] dupdip [H3] dip F a G == a
... c a [F] dupdip G H4 a G == a
... c a [F] dupdip G H4 a G == a
The following four sections illustrate how these work, omitting the
predicate evaluation.
@@ -269,31 +268,31 @@ predicate evaluation.
::
H1 == [P] [pop c] [G] [dip F] genrec
H1 == [P] [pop c] [G] [dip F] genrec
Iterate n times.
::
... a G [H1] dip F
... a b [H1] dip F
... a H1 b F
... a G [H1] dip F b F
... a″ b [H1] dip F b F
... a″ H1 b F b F
... a″ G [H1] dip F b F b F
... a‴ b″ [H1] dip F b F b F
... a‴ H1 b″ F b F b F
... a‴ pop c b″ F b F b F
... c b″ F b F b F
... d b F b F
... d b F
... d″
... a G [H1] dip F
... a b [H1] dip F
... a H1 b F
... a G [H1] dip F b F
... a″ b [H1] dip F b F
... a″ H1 b F b F
... a″ G [H1] dip F b F b F
... a‴ b″ [H1] dip F b F b F
... a‴ H1 b″ F b F b F
... a‴ pop c b″ F b F b F
... c b″ F b F b F
... d b F b F
... d b F
... d″
This form builds up a pending expression (continuation) that contains
the intermediate results along with the pending combiner functions. When
the base case is reached the last term is replaced by the identity value
``c`` and the continuation "collapses" into the final result using the
``c`` and the continuation collapses into the final result using the
combiner ``F``.
``H2``
@@ -307,53 +306,53 @@ reverse order.
::
H2 == c swap [P] [pop] [G [F] dip] primrec
H2 == c swap [P] [pop] [G [F] dip] primrec
... c a G [F] dip H2
... c b a [F] dip H2
... c b F a H2
... d a H2
... d a G [F] dip H2
... d b a″ [F] dip H2
... d b F a″ H2
... d a″ H2
... d a″ G [F] dip H2
... d b″ a‴ [F] dip H2
... d b″ F a‴ H2
... d″ a‴ H2
... d″ a‴ pop
... d″
... c a G [F] dip H2
... c b a [F] dip H2
... c b F a H2
... d a H2
... d a G [F] dip H2
... d b a″ [F] dip H2
... d b F a″ H2
... d a″ H2
... d a″ G [F] dip H2
... d b″ a‴ [F] dip H2
... d b″ F a‴ H2
... d″ a‴ H2
... d″ a‴ pop
... d″
``H3``
~~~~~~
If you examine the traces above you'll see that the combiner ``F`` only
gets to operate on the results of ``G``, it never "sees" the first value
If you examine the traces above youll see that the combiner ``F`` only
gets to operate on the results of ``G``, it never sees the first value
``a``. If the combiner and the generator both need to work on the
current value then ``dup`` must be used, and the generator must produce
one item instead of two (the b is instead the duplicate of a.)
::
H3 == [P] [pop c] [[G] dupdip] [dip F] genrec
H3 == [P] [pop c] [[G] dupdip] [dip F] genrec
... a [G] dupdip [H3] dip F
... a G a [H3] dip F
... a a [H3] dip F
... a H3 a F
... a [G] dupdip [H3] dip F a F
... a G a [H3] dip F a F
... a″ a [H3] dip F a F
... a″ H3 a F a F
... a″ [G] dupdip [H3] dip F a F a F
... a″ G a″ [H3] dip F a F a F
... a‴ a″ [H3] dip F a F a F
... a‴ H3 a″ F a F a F
... a‴ pop c a″ F a F a F
... c a″ F a F a F
... d a F a F
... d a F
... d″
... a [G] dupdip [H3] dip F
... a G a [H3] dip F
... a a [H3] dip F
... a H3 a F
... a [G] dupdip [H3] dip F a F
... a G a [H3] dip F a F
... a″ a [H3] dip F a F
... a″ H3 a F a F
... a″ [G] dupdip [H3] dip F a F a F
... a″ G a″ [H3] dip F a F a F
... a‴ a″ [H3] dip F a F a F
... a‴ H3 a″ F a F a F
... a‴ pop c a″ F a F a F
... c a″ F a F a F
... d a F a F
... d a F
... d″
``H4``
~~~~~~
@@ -364,22 +363,22 @@ the form:
::
H4 == c swap [P] [pop] [[F] dupdip G] primrec
H4 == c swap [P] [pop] [[F] dupdip G] primrec
... c a [F] dupdip G H4
... c a F a G H4
... d a G H4
... d a H4
... d a [F] dupdip G H4
... d a F a G H4
... d a G H4
... d a″ H4
... d a″ [F] dupdip G H4
... d a″ F a″ G H4
... d″ a″ G H4
... d″ a‴ H4
... d″ a‴ pop
... d″
... c a [F] dupdip G H4
... c a F a G H4
... d a G H4
... d a H4
... d a [F] dupdip G H4
... d a F a G H4
... d a G H4
... d a″ H4
... d a″ [F] dupdip G H4
... d a″ F a″ G H4
... d″ a″ G H4
... d″ a‴ H4
... d″ a‴ pop
... d″
Anamorphism
-----------
@@ -390,13 +389,10 @@ values.
::
A == [P] [] [G] [swons] hylomorphism
A == [P] [] [G] [swons] hylomorphism
``range`` et. al.
~~~~~~~~~~~~~~~~~
An example of an anamorphism is the ``range`` function which generates
the list of integers from 0 to *n* - 1 given *n*.
``range`` et. al. An example of an anamorphism is the ``range`` function which generates the list of integers from 0 to *n* - 1 given *n*.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Each of the above variations can be used to make four slightly different
``range`` functions.
@@ -406,8 +402,8 @@ Each of the above variations can be used to make four slightly different
::
H1 == [P] [pop c] [G] [dip F] genrec
== [0 <=] [pop []] [-- dup] [dip swons] genrec
H1 == [P] [pop c] [G] [dip F] genrec
== [0 <=] [pop []] [-- dup] [dip swons] genrec
.. code:: ipython2
@@ -428,8 +424,8 @@ Each of the above variations can be used to make four slightly different
::
H2 == c swap [P] [pop] [G [F] dip] primrec
== [] swap [0 <=] [pop] [-- dup [swons] dip] primrec
H2 == c swap [P] [pop] [G [F] dip] primrec
== [] swap [0 <=] [pop] [-- dup [swons] dip] primrec
.. code:: ipython2
@@ -450,8 +446,8 @@ Each of the above variations can be used to make four slightly different
::
H3 == [P] [pop c] [[G] dupdip] [dip F] genrec
== [0 <=] [pop []] [[--] dupdip] [dip swons] genrec
H3 == [P] [pop c] [[G] dupdip] [dip F] genrec
== [0 <=] [pop []] [[--] dupdip] [dip swons] genrec
.. code:: ipython2
@@ -472,8 +468,8 @@ Each of the above variations can be used to make four slightly different
::
H4 == c swap [P] [pop] [[F] dupdip G ] primrec
== [] swap [0 <=] [pop] [[swons] dupdip --] primrec
H4 == c swap [P] [pop] [[F] dupdip G ] primrec
== [] swap [0 <=] [pop] [[swons] dupdip --] primrec
.. code:: ipython2
@@ -503,7 +499,7 @@ and makes some new value.
::
C == [not] c [uncons swap] [F] hylomorphism
C == [not] c [uncons swap] [F] hylomorphism
.. code:: ipython2
@@ -513,7 +509,7 @@ An example of a catamorphism is the sum function.
::
sum == [not] 0 [swuncons] [+] hylomorphism
sum == [not] 0 [swuncons] [+] hylomorphism
.. code:: ipython2
@@ -585,16 +581,16 @@ For the Factorial function:
::
H4 == c swap [P] [pop] [[F] dupdip G] primrec
H4 == c swap [P] [pop] [[F] dupdip G] primrec
With:
::
c == 1
F == *
G == --
P == 1 <=
c == 1
F == *
G == --
P == 1 <=
.. code:: ipython2
@@ -613,31 +609,31 @@ With:
Example: ``tails``
------------------
An example of a paramorphism for lists given in the `"Bananas..."
An example of a paramorphism for lists given in the `Bananas…”
paper <http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.41.125>`__
is ``tails`` which returns the list of "tails" of a list.
is ``tails`` which returns the list of tails of a list.
::
[1 2 3] tails
--------------------
[[] [3] [2 3]]
[1 2 3] tails
--------------------
[[] [3] [2 3]]
We can build as we go, and we want ``F`` to run after ``G``, so we use
pattern ``H2``:
::
H2 == c swap [P] [pop] [G [F] dip] primrec
H2 == c swap [P] [pop] [G [F] dip] primrec
We would use:
::
c == []
F == swons
G == rest dup
P == not
c == []
F == swons
G == rest dup
P == not
.. code:: ipython2
@@ -656,39 +652,39 @@ We would use:
Conclusion: Patterns of Recursion
---------------------------------
Our story so far...
Our story so far
Hylo-, Ana-, Cata-
~~~~~~~~~~~~~~~~~~
::
H == [P ] [pop c ] [G ] [dip F ] genrec
A == [P ] [pop []] [G ] [dip swap cons] genrec
C == [not] [pop c ] [uncons swap] [dip F ] genrec
H == [P ] [pop c ] [G ] [dip F ] genrec
A == [P ] [pop []] [G ] [dip swap cons] genrec
C == [not] [pop c ] [uncons swap] [dip F ] genrec
Para-, ?-, ?-
~~~~~~~~~~~~~
::
P == c swap [P ] [pop] [[F ] dupdip G ] primrec
? == [] swap [P ] [pop] [[swap cons] dupdip G ] primrec
? == c swap [not] [pop] [[F ] dupdip uncons swap] primrec
P == c swap [P ] [pop] [[F ] dupdip G ] primrec
? == [] swap [P ] [pop] [[swap cons] dupdip G ] primrec
? == c swap [not] [pop] [[F ] dupdip uncons swap] primrec
Appendix: Fun with Symbols
--------------------------
::
|[ (c, F), (G, P) ]| == (|c, F|) • [(G, P)]
|[ (c, F), (G, P) ]| == (|c, F|) • [(G, P)]
`"Bananas, Lenses, & Barbed
Wire" <http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.41.125>`__
`Bananas, Lenses, & Barbed
Wire <http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.41.125>`__
::
(|...|) [(...)] [<...>]
(|...|) [(...)] [<...>]
I think they are having slightly too much fun with the symbols. However,
"Too much is always better than not enough."
Too much is always better than not enough.