WIP docs update
This commit is contained in:
parent
0a76eea3e2
commit
b05f13fc90
|
|
@ -609,6 +609,212 @@
|
|||
"However, this creates (and destroys) an intermediate list, which is a waste."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Variations\n",
|
||||
"\n",
|
||||
"Let's review the operation of the hylomorphism:\n",
|
||||
"\n",
|
||||
" [P] c [G] [Q] H₁ == [P] [pop c] [G] [dip Q] genrec\n",
|
||||
"\n",
|
||||
" ... a G [H₁] dip Q\n",
|
||||
" ... a′ b [H₁] dip Q\n",
|
||||
" ... a′ H₁ b Q\n",
|
||||
" <predicate omitted>\n",
|
||||
" ... a′ G [H₁] dip Q b Q\n",
|
||||
" ... a″ b′ [H₁] dip Q b Q\n",
|
||||
" ... a″ H₁ b′ Q b Q\n",
|
||||
" <predicate omitted>\n",
|
||||
" ... a″ G [H₁] dip Q b′ Q b Q\n",
|
||||
" ... a‴ b″ [H₁] dip Q b′ Q b Q\n",
|
||||
" ... a‴ H₁ b″ Q b′ Q b Q\n",
|
||||
" <predicate omitted>\n",
|
||||
" ... a‴ pop c b″ Q b′ Q b Q\n",
|
||||
" ... c b″ Q b′ Q b Q\n",
|
||||
" ... c′ b′ Q b Q\n",
|
||||
" ... c″ b Q\n",
|
||||
" ... c‴\n",
|
||||
"\n",
|
||||
"Notice that `b` values and the `Q` combiner function get pushed into the pending expression (\"continuation\")."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### A tail-recursive version\n",
|
||||
"\n",
|
||||
"Now let's try a version that doesn't do that. When you can start with the identity value `c` on the stack and the combiner `Q` can operate as you go using the intermediate results immediately rather than queuing them up, we can do this:\n",
|
||||
"\n",
|
||||
" [P] c [G] [Q] H₂ == c [pop P] [popd] [[G] dip Q] tailrec\n",
|
||||
"\n",
|
||||
"An important difference is that the combiner function `Q` must accept its arguments in the reverse order and take into account the presence of the `a` value:\n",
|
||||
"\n",
|
||||
" ... a c [G] dip Q H₂\n",
|
||||
" ... a G c Q H₂\n",
|
||||
" ... a′ b c Q H₂\n",
|
||||
" ... a′ c′ H₂\n",
|
||||
" <predicate omitted>\n",
|
||||
" ... a′ c′ [G] dip Q H₂\n",
|
||||
" ... a′ G c′ Q H₂\n",
|
||||
" ... a″ b c′ Q H₂\n",
|
||||
" ... a″ c″ H₂\n",
|
||||
" <predicate omitted>\n",
|
||||
" ... a″ c″ [G] dip Q H₂\n",
|
||||
" ... a″ G c″ Q H₂\n",
|
||||
" ... a‴ b c″ Q H₂\n",
|
||||
" ... a‴ c‴ H₂\n",
|
||||
" <predicate omitted>\n",
|
||||
" ... a‴ c‴ popd\n",
|
||||
" ... c‴"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Note that the `c` values are processed by the `Q` combiner function in reverse order as compared to the original version.\n",
|
||||
"\n",
|
||||
"#### `range` with `H₂`\n",
|
||||
"\n",
|
||||
"For example, if we reimplement the `range` function in the tail-recursive style it generates the list with $0$ at the head rather than $n - 1$:\n",
|
||||
"\n",
|
||||
" range_reverse == [] [pop 0 <=] [popd] [[-- dup] dip cons] tailrec\n",
|
||||
" "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": []
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"clear "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": []
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"[range_reverse [] [pop 0 <=] [popd] [[-- dup] dip cons] tailrec] inscribe"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"metadata": {
|
||||
"scrolled": true
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"[4 3 2 1 0] [0 1 2 3 4]"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"5 [range] [range_reverse] cleave"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Instead of making `Q` take account of the `c` value we could do this:\n",
|
||||
"\n",
|
||||
" ... a′ b c [Q] ccons dip swap H₂\n",
|
||||
" ... a′ [b c Q] dip swap H₂\n",
|
||||
" ... b c Q a′ swap H₂\n",
|
||||
" ... c′ a′ swap H₂\n",
|
||||
" ... a′ c′ H₂\n",
|
||||
"\n",
|
||||
"This shows that any function `Q` can be converted to `[Q] ccons dip swap` to deal with that `a` value on the stack."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### the old version\n",
|
||||
"\n",
|
||||
"Now let's try a version that doesn't do that. When you can start with the identity value `c` on the stack and the combiner `Q` can operate as you go using the intermediate results immediately rather than queuing them up, we can do this:\n",
|
||||
"\n",
|
||||
" [P] c [G] [Q] H₂ == c swap [P] [pop] [G [Q] dip] tailrec\n",
|
||||
"\n",
|
||||
"An important difference is that the generator function must return its results in the reverse order, and both `Q` and `G` have to take into account the presence of the `c` value:\n",
|
||||
"\n",
|
||||
" ... c a G [Q] dip H₂\n",
|
||||
" ... c b a′ [Q] dip H₂\n",
|
||||
" ... c b Q a′ H₂\n",
|
||||
" ... c′ a′ H₂\n",
|
||||
" <predicate omitted>\n",
|
||||
" ... c′ a′ G [Q] dip H₂\n",
|
||||
" ... c′ b′ a″ [Q] dip H₂\n",
|
||||
" ... c′ b′ Q a″ H₂\n",
|
||||
" ... c″ a″ H₂\n",
|
||||
" <predicate omitted>\n",
|
||||
" ... c″ a″ G [Q] dip H₂\n",
|
||||
" ... c″ b″ a‴ [Q] dip H₂\n",
|
||||
" ... c″ b″ Q a‴ H₂\n",
|
||||
" ... c‴ a‴ H₂\n",
|
||||
" <predicate omitted>\n",
|
||||
" ... c‴ a‴ pop\n",
|
||||
" ... c‴\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
|
|||
|
|
@ -2654,21 +2654,21 @@
|
|||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 2",
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python2"
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 2
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython2",
|
||||
"version": "2.7.12"
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.7.10"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
|
|
|||
|
|
@ -470,7 +470,6 @@
|
|||
"source": [
|
||||
"### Traversal\n",
|
||||
" [key value] first [left right] [K] map i\n",
|
||||
" key [value] [left right] [K] map i\n",
|
||||
" key [left right] [K] map i\n",
|
||||
" key [lkey rkey ] i\n",
|
||||
" key lkey rkey"
|
||||
|
|
@ -873,21 +872,21 @@
|
|||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 2",
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python2"
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 2
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython2",
|
||||
"version": "2.7.12"
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.7.10"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
|
|
|||
Loading…
Reference in New Issue