Switch to Joy kernel.

This commit is contained in:
Simon Forman 2021-11-30 21:00:26 -08:00
parent fcd4c613e4
commit 384d391175
1 changed files with 375 additions and 226 deletions

View File

@ -1,21 +1,20 @@
{ {
"cells": [ "cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"from notebook_preamble import D, DefinitionWrapper, J, V, define"
]
},
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": {}, "metadata": {},
"source": [ "source": [
"# Recursion Combinators\n", "# Recursion Combinators\n",
"\n", "\n",
"This article describes the `genrec` combinator, how to use it, and several generic specializations.\n", "This article describes the `genrec` combinator and how to use it, then several generic specializations.\n",
"\n",
"## General Recursive Function\n",
"\n",
"In Joy recursive functions are defined by four quoted programs and the `genrec` combinator.\n",
"\n",
" F == [if] [then] [rec1] [rec2] genrec\n",
"\n",
"This can be thought of as transforming into an \"if..then..else\" expression using the `ifte` combinator and containing a quoted copy of itself in the \"else\" branch:\n",
"\n", "\n",
" [if] [then] [rec1] [rec2] genrec\n", " [if] [then] [rec1] [rec2] genrec\n",
" ---------------------------------------------------------------------\n", " ---------------------------------------------------------------------\n",
@ -33,130 +32,123 @@
"the combinator are again pushed onto the stack bundled up in a quoted\n", "the combinator are again pushed onto the stack bundled up in a quoted\n",
"form. Then the rec2-part is executed, where it will find the bundled\n", "form. Then the rec2-part is executed, where it will find the bundled\n",
"form. Typically it will then execute the bundled form, either with i or\n", "form. Typically it will then execute the bundled form, either with i or\n",
"with app2, or some other combinator.\"" "with app2, or some other combinator.\"\n",
] "\n",
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Designing Recursive Functions\n", "## Designing Recursive Functions\n",
"The way to design one of these is to fix your base case and \n", "\n",
"test and then treat `R1` and `R2` as an else-part \"sandwiching\"\n", "Fix your base case and test functions and then treat `R1` and `R2` as an else-part \"sandwiching\" a quotation of the whole function.\n",
"a quotation of the whole function.\n",
"\n", "\n",
"For example, given a (general recursive) function `F`:\n", "For example, given a (general recursive) function `F`:\n",
"\n", "\n",
" F == [I] [T] [R1] [R2] genrec\n", " F == [P] [T] [R1] [R2] genrec\n",
" == [I] [T] [R1 [F] R2] ifte\n", " == [P] [T] [R1 [F] R2] ifte\n",
"\n", "\n",
"If the `[I]` predicate is false you must derive `R1` and `R2` from:\n", "Derive `R1` and `R2` from:\n",
"\n", "\n",
" ... R1 [F] R2\n", " ... R1 [F] R2\n",
"\n", "\n",
"Set the stack arguments in front and figure out what `R1` and `R2`\n", "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.\n",
"have to do to apply the quoted `[F]` in the proper way."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Primitive Recursive Functions\n",
"Primitive recursive functions are those where `R2 == i`.\n",
"\n", "\n",
" P == [I] [T] [R] primrec\n",
" == [I] [T] [R [P] i] ifte\n",
" == [I] [T] [R P] ifte"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## [Hylomorphism](https://en.wikipedia.org/wiki/Hylomorphism_%28computer_science%29)\n", "## [Hylomorphism](https://en.wikipedia.org/wiki/Hylomorphism_%28computer_science%29)\n",
"A [hylomorphism](https://en.wikipedia.org/wiki/Hylomorphism_%28computer_science%29) is a recursive function `H :: A -> C` that converts a value of type `A` into a value of type `C` by means of:\n",
"\n", "\n",
"- A generator `G :: A -> (B, A)`\n", "A [hylomorphism](https://en.wikipedia.org/wiki/Hylomorphism_%28computer_science%29) is a recursive function `H` that converts a value of type `A` into a value of type `C` by means of:\n",
"- A combiner `F :: (B, C) -> C`\n", "\n",
"- A predicate `P :: A -> Bool` to detect the base case\n", "- A generator `G` from `A` to `(B, A)`\n",
"- A base case value `c :: C`\n", "- A combiner `Q` from `(B, C)` to `C`\n",
"- A predicate `P` from `A` to `Bool` to detect the base case\n",
"- A base case value `c` of type `C`, and\n",
"- Recursive calls (zero or more); it has a \"call stack in the form of a cons list\".\n", "- Recursive calls (zero or more); it has a \"call stack in the form of a cons list\".\n",
"\n", "\n",
"It may be helpful to see this function implemented in imperative Python code." "It may be helpful to see this function implemented in pseudocode (Python).\n",
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"def hylomorphism(c, F, P, G):\n",
" '''Return a hylomorphism function H.'''\n",
"\n", "\n",
" def H(a):\n", " def hylomorphism(c, Q, P, G):\n",
" if P(a):\n", " '''Return a hylomorphism function H.'''\n",
" result = c\n", "\n",
" else:\n", " def H(a):\n",
" if P(a):\n",
" return c\n",
" b, aa = G(a)\n", " b, aa = G(a)\n",
" result = F(b, H(aa)) # b is stored in the stack frame during recursive call to H().\n", " return Q(b, H(aa))\n",
" return result\n", "\n",
" return H\n",
"\n", "\n",
" return H"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Cf. [\"Bananas, Lenses, & Barbed Wire\"](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.41.125)\n", "Cf. [\"Bananas, Lenses, & Barbed Wire\"](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.41.125)\n",
"\n", "\n",
"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\"." "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\".\n",
] "\n",
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Hylomorphism in Joy\n", "## Hylomorphism in Joy\n",
"\n",
" a H\n",
" ---------\n",
" c\n",
"\n",
"We can define a combinator `hylomorphism` that will make a hylomorphism combinator `H` from constituent parts.\n", "We can define a combinator `hylomorphism` that will make a hylomorphism combinator `H` from constituent parts.\n",
"\n", "\n",
" H == [P] c [G] [F] hylomorphism\n", " H == [P] c [G] [Q] hylomorphism\n",
"\n", "\n",
"The function `H` is recursive, so we start with `ifte` and set the else-part to\n", "The function `H` is recursive, so we start with `ifte` and set the else-part to\n",
"some function `J` that will contain a quoted copy of `H`. (The then-part just\n", "some function `J` that will contain a quoted copy of `H`.\n",
"discards the leftover `a` and replaces it with the base case value `c`.)\n", "The then-part just discards the leftover `a` and replaces it with the base case value `c`:\n",
"\n", "\n",
" H == [P] [pop c] [J] ifte\n", " H == [P] [pop c] [J] ifte\n",
"\n", "\n",
"The else-part `J` gets just the argument `a` on the stack.\n", "The else-part `J` gets just the argument `a` on the stack.\n",
"\n", "\n",
" a J\n", " a J\n",
" a G The first thing to do is use the generator G\n",
" aa b which produces b and a new aa\n",
" aa b [H] dip we recur with H on the new aa\n",
" aa H b F and run F on the result.\n",
"\n", "\n",
"This gives us a definition for `J`.\n", "The first thing to do is use the generator `G` which produces values `b` and a new `aa`:\n",
"\n", "\n",
" J == G [H] dip F\n", " a G\n",
" ----------\n",
" aa b\n",
"\n", "\n",
"Plug it in and convert to genrec.\n", "So:\n",
"\n", "\n",
" H == [P] [pop c] [G [H] dip F] ifte\n", " J == G J\n",
" H == [P] [pop c] [G] [dip F] genrec\n", "\n",
"Then we recur with `H` on `aa`:\n",
"\n",
" aa b [H] dip\n",
" ------------------\n",
" aa H b\n",
" ------------------\n",
" cc b\n",
"\n",
"So:\n",
"\n",
" J == [H] dip J″\n",
"\n",
"And run `Q` on the result:\n",
"\n",
" cc b Q\n",
" ------------\n",
" c\n",
"So:\n",
"\n",
" J″ == Q\n",
"\n",
"Summing up:\n",
"\n",
" J == G J\n",
" J == [H] dip J″\n",
" J″ == Q\n",
"\n",
"This gives us a definition for `J`:\n",
"\n",
" J == G [H] dip Q\n",
"\n",
"Plug it in and convert to genrec:\n",
"\n",
" H == [P] [pop c] [ J ] ifte\n",
" [P] [pop c] [G [H] dip Q] ifte\n",
" [P] [pop c] [G] [dip Q] genrec\n",
"\n", "\n",
"This is the form of a hylomorphism in Joy, which nicely illustrates that\n", "This is the form of a hylomorphism in Joy, which nicely illustrates that\n",
"it is a simple specialization of the general recursion combinator.\n", "it is a simple specialization of the general recursion combinator.\n",
"\n", "\n",
" H == [P] c [G] [F] hylomorphism == [P] [pop c] [G] [dip F] genrec" " [P] c [G] [Q] hylomorphism\n",
] " [P] [pop c] [G] [dip Q] genrec\n",
}, "\n",
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Derivation of `hylomorphism` combinator\n", "## Derivation of `hylomorphism` combinator\n",
"\n", "\n",
"Now we just need to derive a definition that builds the `genrec` arguments\n", "Now we just need to derive a definition that builds the `genrec` arguments\n",
@ -172,8 +164,6 @@
"- Use `unit` to dequote `c`.\n", "- Use `unit` to dequote `c`.\n",
"- Use `dipd` to untangle `[unit [pop] swoncat]` from the givens.\n", "- Use `dipd` to untangle `[unit [pop] swoncat]` from the givens.\n",
"\n", "\n",
"So:\n",
"\n",
" H == [P] [pop c] [G] [dip F] genrec\n", " H == [P] [pop c] [G] [dip F] genrec\n",
" [P] [c] [pop] swoncat [G] [F] [dip] swoncat genrec\n", " [P] [c] [pop] swoncat [G] [F] [dip] swoncat genrec\n",
" [P] c unit [pop] swoncat [G] [F] [dip] swoncat genrec\n", " [P] c unit [pop] swoncat [G] [F] [dip] swoncat genrec\n",
@ -187,11 +177,17 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 3, "execution_count": 1,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": []
}
],
"source": [ "source": [
"define('hylomorphism == [unit [pop] swoncat] dipd [dip] swoncat genrec')" "[hylomorphism [unit [pop] swoncat] dipd [dip] swoncat genrec] inscribe"
] ]
}, },
{ {
@ -211,11 +207,17 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 4, "execution_count": 2,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": []
}
],
"source": [ "source": [
"define('triangular_number == [1 <=] 0 [-- dup] [+] hylomorphism')" "[triangular_number [1 <=] 0 [-- dup] [+] hylomorphism] inscribe"
] ]
}, },
{ {
@ -227,36 +229,45 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 5, "execution_count": 3,
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"10\n" "10"
] ]
} }
], ],
"source": [ "source": [
"J('5 triangular_number')" "5 triangular_number"
] ]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 6, "execution_count": 4,
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"[0 0 1 3 6 10 15]\n" "[0 0 1 3 6 10 15 21]"
] ]
} }
], ],
"source": [ "source": [
"J('[0 1 2 3 4 5 6] [triangular_number] map')" "clear\n",
"\n",
"[0 1 2 3 4 5 6 7] [triangular_number] map"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Neat!"
] ]
}, },
{ {
@ -407,6 +418,7 @@
"metadata": {}, "metadata": {},
"source": [ "source": [
"### `range` et. al.\n", "### `range` et. al.\n",
"\n",
"An example of an anamorphism is the `range` function which generates the list of integers from 0 to *n* - 1 given *n*.\n", "An example of an anamorphism is the `range` function which generates the list of integers from 0 to *n* - 1 given *n*.\n",
"\n", "\n",
"Each of the above variations can be used to make four slightly different `range` functions." "Each of the above variations can be used to make four slightly different `range` functions."
@ -423,16 +435,37 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 7, "execution_count": 5,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": []
}
],
"source": [ "source": [
"define('range == [0 <=] [] [-- dup] [swons] hylomorphism')" "clear "
] ]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 8, "execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": []
}
],
"source": [
"[range [0 <=] [] [-- dup] [swons] hylomorphism] inscribe"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": { "metadata": {
"scrolled": false "scrolled": false
}, },
@ -441,12 +474,12 @@
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"[4 3 2 1 0]\n" "[4 3 2 1 0]"
] ]
} }
], ],
"source": [ "source": [
"J('5 range')" "5 range"
] ]
}, },
{ {
@ -454,17 +487,38 @@
"metadata": {}, "metadata": {},
"source": [ "source": [
"#### `range` with `H2`\n", "#### `range` with `H2`\n",
" H2 == c swap [P] [pop] [G [F] dip] primrec\n", " H2 == c swap [P] [pop] [G [F] dip] tailrec\n",
" == [] swap [0 <=] [pop] [-- dup [swons] dip] primrec" " == [] swap [0 <=] [pop] [-- dup [swons] dip] tailrec"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": []
}
],
"source": [
"clear "
] ]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 9, "execution_count": 9,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": []
}
],
"source": [ "source": [
"define('range_reverse == [] swap [0 <=] [pop] [-- dup [swons] dip] primrec')" "[range_reverse [] swap [0 <=] [pop] [-- dup [swons] dip] tailrec] inscribe"
] ]
}, },
{ {
@ -478,12 +532,12 @@
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"[0 1 2 3 4]\n" "[0 1 2 3 4]"
] ]
} }
], ],
"source": [ "source": [
"J('5 range_reverse')" "5 range_reverse"
] ]
}, },
{ {
@ -499,14 +553,35 @@
"cell_type": "code", "cell_type": "code",
"execution_count": 11, "execution_count": 11,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": []
}
],
"source": [ "source": [
"define('ranger == [0 <=] [pop []] [[--] dupdip] [dip swons] genrec')" "clear "
] ]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 12, "execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": []
}
],
"source": [
"[ranger [0 <=] [pop []] [[--] dupdip] [dip swons] genrec] inscribe"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": { "metadata": {
"scrolled": true "scrolled": true
}, },
@ -515,12 +590,12 @@
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"[5 4 3 2 1]\n" "[5 4 3 2 1]"
] ]
} }
], ],
"source": [ "source": [
"J('5 ranger')" "5 ranger"
] ]
}, },
{ {
@ -534,16 +609,37 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 13, "execution_count": 14,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": []
}
],
"source": [ "source": [
"define('ranger_reverse == [] swap [0 <=] [pop] [[swons] dupdip --] primrec')" "clear "
] ]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 14, "execution_count": 15,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": []
}
],
"source": [
"[ranger_reverse [] swap [0 <=] [pop] [[swons] dupdip --] tailrec] inscribe"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": { "metadata": {
"scrolled": true "scrolled": true
}, },
@ -552,19 +648,12 @@
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"[1 2 3 4 5]\n" "[1 2 3 4 5]"
] ]
} }
], ],
"source": [ "source": [
"J('5 ranger_reverse')" "5 ranger_reverse"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Hopefully this illustrates the workings of the variations. For more insight you can run the cells using the `V()` function instead of the `J()` function to get a trace of the Joy evaluation."
] ]
}, },
{ {
@ -572,54 +661,77 @@
"metadata": {}, "metadata": {},
"source": [ "source": [
"## Catamorphism\n", "## Catamorphism\n",
"A catamorphism can be defined as a hylomorphism that uses `[uncons swap]` for `[G]`\n", "A catamorphic function tears down a list term-by-term and makes some new value.\n",
"and `[[] =]` (or just `[not]`) for the predicate `[P]`. A catamorphic function tears down a list term-by-term and makes some new value.\n", "It can be defined as a hylomorphism that uses `[uncons swap]` for `[G]`\n",
"and `[[] =]` (or just `[not]`) for the predicate `[P]`.\n",
"\n",
" C == [not] c [uncons swap] [F] hylomorphism\n",
"\n", "\n",
" C == [not] c [uncons swap] [F] hylomorphism"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [],
"source": [
"define('swuncons == uncons swap') # Awkward name."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"An example of a catamorphism is the sum function.\n", "An example of a catamorphism is the sum function.\n",
"\n", "\n",
" sum == [not] 0 [swuncons] [+] hylomorphism" " sum == [not] 0 [uncons swap] [+] hylomorphism"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [],
"source": [
"define('sum == [not] 0 [swuncons] [+] hylomorphism')"
] ]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 17, "execution_count": 17,
"metadata": {}, "metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": []
}
],
"source": [
"clear "
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": []
}
],
"source": [
"[sum [not] 0 [uncons swap] [+] hylomorphism] inscribe"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [ "outputs": [
{ {
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"15\n" "15"
] ]
} }
], ],
"source": [ "source": [
"J('[5 4 3 2 1] sum')" "[5 4 3 2 1] sum"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": []
}
],
"source": [
"clear "
] ]
}, },
{ {
@ -632,64 +744,76 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 18, "execution_count": 21,
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"\n",
"==== Help on step ====\n",
"\n",
"Run a quoted program on each item in a sequence.\n", "Run a quoted program on each item in a sequence.\n",
"::\n", "::\n",
"\n", "\n",
" ... [] [Q] . step\n", " ... [] [Q] . step\n",
" -----------------------\n", " -----------------------\n",
" ... .\n", " ... .\n",
"\n", "\n",
"\n", "\n",
" ... [a] [Q] . step\n", " ... [a] [Q] . step\n",
" ------------------------\n", " ------------------------\n",
" ... a . Q\n", " ... a . Q\n",
"\n", "\n",
"\n", "\n",
" ... [a b c] [Q] . step\n", " ... [a b c] [Q] . step\n",
" ----------------------------------------\n", " ----------------------------------------\n",
" ... a . Q [b c] [Q] step\n", " ... a . Q [b c] [Q] step\n",
"\n", "\n",
"The step combinator executes the quotation on each member of the list\n", "The step combinator executes the quotation on each member of the list\n",
"on top of the stack.\n", "on top of the stack.\n",
"\n",
"---- end (step)\n",
"\n",
"\n" "\n"
] ]
} }
], ],
"source": [ "source": [
"J('[step] help')" "[step] help"
] ]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 19, "execution_count": 22,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": []
}
],
"source": [ "source": [
"define('sum == 0 swap [+] step')" "[sum 0 swap [+] step] inscribe"
] ]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 20, "execution_count": 23,
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"15\n" "15"
] ]
} }
], ],
"source": [ "source": [
"J('[5 4 3 2 1] sum')" "[5 4 3 2 1] sum"
] ]
}, },
{ {
@ -712,16 +836,37 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 21, "execution_count": 24,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": []
}
],
"source": [ "source": [
"define('factorial == 1 swap [1 <=] [pop] [[*] dupdip --] primrec')" "clear"
] ]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 22, "execution_count": 25,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": []
}
],
"source": [
"[factorial 1 swap [1 <=] [pop] [[*] dupdip --] tailrec] inscribe"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": { "metadata": {
"scrolled": false "scrolled": false
}, },
@ -730,12 +875,12 @@
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"120\n" "120"
] ]
} }
], ],
"source": [ "source": [
"J('5 factorial')" "5 factorial"
] ]
}, },
{ {
@ -748,54 +893,65 @@
" [1 2 3] tails\n", " [1 2 3] tails\n",
" --------------------\n", " --------------------\n",
" [[] [3] [2 3]]\n", " [[] [3] [2 3]]\n",
" " " \n",
] "\n",
}, "We can build as we go, and we want `Q` to run after `G`, so we use pattern `H2`:\n",
{ "\n",
"cell_type": "markdown", " H2 == c swap [P] [pop] [G [Q] dip] tailrec\n",
"metadata": {},
"source": [
"We can build as we go, and we want `F` to run after `G`, so we use pattern `H2`:\n",
"\n", "\n",
" H2 == c swap [P] [pop] [G [F] dip] primrec"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We would use:\n", "We would use:\n",
"\n", "\n",
" c == []\n", " c == []\n",
" F == swons\n", " Q == swons\n",
" G == rest dup\n", " G == rest dup\n",
" P == not" " P == not"
] ]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 23, "execution_count": 27,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": []
}
],
"source": [ "source": [
"define('tails == [] swap [not] [pop] [rest dup [swons] dip] primrec')" "clear"
] ]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 24, "execution_count": 28,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": []
}
],
"source": [
"[tails [] swap [not] [pop] [rest dup [swons] dip] tailrec] inscribe"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"[[] [3] [2 3]]\n" "[[] [3] [2 3]]"
] ]
} }
], ],
"source": [ "source": [
"J('[1 2 3] tails')" "[1 2 3] tails"
] ]
}, },
{ {
@ -837,21 +993,14 @@
], ],
"metadata": { "metadata": {
"kernelspec": { "kernelspec": {
"display_name": "Python 2", "display_name": "Joypy",
"language": "python", "language": "",
"name": "python2" "name": "thun"
}, },
"language_info": { "language_info": {
"codemirror_mode": { "file_extension": ".joy",
"name": "ipython", "mimetype": "text/plain",
"version": 2 "name": "Joy"
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.15"
} }
}, },
"nbformat": 4, "nbformat": 4,