OSDN Git Service

WIP docs update
authorSimon Forman <sforman@hushmail.com>
Sat, 15 Jan 2022 23:22:17 +0000 (15:22 -0800)
committerSimon Forman <sforman@hushmail.com>
Sat, 15 Jan 2022 23:22:17 +0000 (15:22 -0800)
docs/Recursion_Combinators.ipynb
docs/Trees.ipynb
docs/Treestep.ipynb

index 214f8a0..a55f79e 100644 (file)
    "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": {},
+   "source": [
     "## Four Specializations\n",
     "There are (at least) four kinds of recursive combinator, depending on two choices.  The first choice is whether the combiner function `Q` 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 needs to operate on the current value of the datastructure or the generator's output, in other words, whether `Q` or `G` should run first in the recursive branch.\n",
     "\n",
index 8baf723..7acf67d 100644 (file)
  ],
  "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,
index 0929064..d7fef34 100644 (file)
    "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"
  ],
  "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,