OSDN Git Service

Some work on docs.
authorSimon Forman <sforman@hushmail.com>
Fri, 24 Dec 2021 03:08:30 +0000 (19:08 -0800)
committerSimon Forman <sforman@hushmail.com>
Fri, 24 Dec 2021 03:08:30 +0000 (19:08 -0800)
docs/Advent_of_Code_2017_December_2nd.ipynb
docs/Quadratic.ipynb
docs/Recursion_Combinators.ipynb
docs/Remove-Function.ipynb [new file with mode: 0644]

index 12093a2..d20964d 100644 (file)
     "* The second row's largest and smallest values are 7 and 3, and their difference is 4.\n",
     "* The third row's difference is 6.\n",
     "\n",
-    "In this example, the spreadsheet's checksum would be 8 + 4 + 6 = 18."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 1,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "from notebook_preamble import J, V, define"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
+    "In this example, the spreadsheet's checksum would be 8 + 4 + 6 = 18.\n",
+    "\n",
     "I'll assume the input is a Joy sequence of sequences of integers.\n",
     "\n",
     "    [[5 1 9 5]\n",
     "\n",
     "So, obviously, the initial form will be a `step` function:\n",
     "\n",
-    "    AoC2017.2 == 0 swap [F +] step"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
+    "    AoC2017.2 == 0 swap [F +] step\n",
+    "\n",
     "This function `F` must get the `max` and `min` of a row of numbers and subtract.  We can define a helper function `maxmin` which does this:"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 2,
+   "execution_count": 1,
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": []
+    }
+   ],
    "source": [
-    "define('maxmin [max] [min] cleave')"
+    "[maxmin [max] [min] cleave] inscribe"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 3,
+   "execution_count": 2,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "3 1\n"
+      "3 1"
      ]
     }
    ],
    "source": [
-    "J('[1 2 3] maxmin')"
+    "[1 2 3] maxmin"
    ]
   },
   {
   },
   {
    "cell_type": "code",
-   "execution_count": 4,
+   "execution_count": 3,
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "3 1"
+     ]
+    }
+   ],
    "source": [
-    "define('AoC2017.2 [maxmin - +] step_zero')"
+    "[AoC2017.2 [maxmin - +] step_zero] inscribe"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 5,
+   "execution_count": 4,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "18\n"
+      "18"
      ]
     }
    ],
    "source": [
-    "J('''\n",
+    "clear\n",
     "\n",
     "[[5 1 9 5]\n",
     " [7 5 3]\n",
-    " [2 4 6 8]] AoC2017.2\n",
-    "\n",
-    "''')"
+    " [2 4 6 8]] AoC2017.2"
    ]
   },
   {
   },
   {
    "cell_type": "code",
-   "execution_count": 6,
+   "execution_count": 24,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": []
+    }
+   ],
+   "source": [
+    "clear"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 25,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[2 5 8 9]"
+     ]
+    }
+   ],
+   "source": [
+    "[5 9 2 8] sort"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 26,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[5 8 9] [2 mod not]"
+     ]
+    }
+   ],
+   "source": [
+    "uncons swap [mod not] cons"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 23,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[false true false]"
+     ]
+    }
+   ],
+   "source": [
+    "map"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 27,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "false true false"
+     ]
+    }
+   ],
+   "source": [
+    "step"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 28,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "false true false"
+     ]
+    }
+   ],
+   "source": [
+    "[P 2 mod not] inscribe"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 31,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[4 5 6 7]"
+     ]
+    }
+   ],
+   "source": [
+    "clear\n",
+    "[4 5 6 7]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 30,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[true false true false]"
+     ]
+    }
+   ],
+   "source": [
+    "[P] map"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 32,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[] [4 5 6 7]"
+     ]
+    }
+   ],
+   "source": [
+    "[] swap"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 33,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[] 4"
+     ]
+    }
+   ],
+   "source": [
+    "first"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 34,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[4]"
+     ]
+    }
+   ],
+   "source": [
+    "[P][swons][pop]ifte"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 35,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[4] 5"
+     ]
+    }
+   ],
+   "source": [
+    "5"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 36,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[4]"
+     ]
+    }
+   ],
+   "source": [
+    "[P][swons][pop]ifte"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 37,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[4 5 6 7]"
+     ]
+    }
+   ],
+   "source": [
+    "clear\n",
+    "[4 5 6 7]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 38,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "[9 8 5 2]\n"
+      "[6 4]"
      ]
     }
    ],
    "source": [
-    "J('[5 9 2 8] sort reverse')"
+    "[] swap [[P][swons][pop]ifte] step"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "           [...] [P] filter\n",
+    "    -----------------------------------------\n",
+    "       [] [...] [[P][swons][pop]ifte] step\n",
+    "\n",
+    "But that `[]` could get in the way of `P`, no?"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 7,
+   "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": "code",
+   "execution_count": 9,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "[8 5 2] [9 divmod] [8 5 2]\n"
+      "[8 5 2] [9 divmod] [8 5 2]"
      ]
     }
    ],
    "source": [
-    "J('[9 8 5 2] uncons [swap [divmod] cons] dupdip')"
+    "uncons [swap [divmod] cons] dupdip"
    ]
   },
   {
  ],
  "metadata": {
   "kernelspec": {
-   "display_name": "Python 2",
-   "language": "python",
-   "name": "python2"
+   "display_name": "Joypy",
+   "language": "",
+   "name": "thun"
   },
   "language_info": {
-   "codemirror_mode": {
-    "name": "ipython",
-    "version": 3
-   },
-   "file_extension": ".py",
-   "mimetype": "text/x-python",
-   "name": "python",
-   "nbconvert_exporter": "python",
-   "pygments_lexer": "ipython3",
-   "version": "3.8.3"
+   "file_extension": ".joy",
+   "mimetype": "text/plain",
+   "name": "Joy"
   }
  },
  "nbformat": 4,
index ac93fd1..d98a26f 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.15"
+   "pygments_lexer": "ipython3",
+   "version": "3.7.10"
   }
  },
  "nbformat": 4,
index bfa97db..214f8a0 100644 (file)
@@ -6,22 +6,25 @@
    "source": [
     "# Recursion Combinators\n",
     "\n",
-    "This article describes the `genrec` combinator and how to use it, then several generic specializations.\n",
-    "\n",
+    "This article describes the `genrec` combinator and how to use it, and then gives several specializations.\n",
+    "The `genrec` combinator isn't the only way to make recursive functions in Joy, you can also use the `x` combinator with a `branch` to create recursive functions.  (Because definitions aren't checked for self-reference you can also define recursive functions directly in definitions, but this, I believe, should be considered bad form.)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
     "## General Recursive Function\n",
     "\n",
-    "In Joy recursive functions are defined by four quoted programs and the `genrec` combinator.\n",
+    "In Joy recursive functions are defined by the `genrec` combinator which accepts four quoted programs:\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",
-    "                          [if] [then] [rec1] [rec2] genrec\n",
-    "    ---------------------------------------------------------------------\n",
-    "       [if] [then] [rec1 [[if] [then] [rec1] [rec2] genrec] rec2] ifte\n",
-    "\n",
+    "    F == [if] [then] [rec1 [F] rec2] ifte\n",
     "\n",
-    "From \"Recursion Theory and Joy\" (j05cmp.html) by Manfred von Thun:\n",
+    "From [\"Recursion Theory and Joy\"](https://www.kevinalbrecht.com/code/joy-mirror/j05cmp.html) by Manfred von Thun:\n",
     "\n",
     "> \"The genrec combinator takes four program parameters in addition to\n",
     "whatever data parameters it needs. Fourth from the top is an if-part,\n",
     "form. Typically it will then execute the bundled form, either with i or\n",
     "with app2, or some other combinator.\"\n",
     "\n",
-    "## Designing Recursive Functions\n",
-    "\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",
-    "\n",
-    "For example, given a (general recursive) function `F`:\n",
-    "\n",
-    "    F == [P] [T] [R1]   [R2] genrec\n",
-    "      == [P] [T] [R1 [F] R2] ifte\n",
-    "\n",
-    "Derive `R1` and `R2` from:\n",
-    "\n",
-    "    ... R1 [F] R2\n",
-    "\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",
-    "\n",
+    "It's a fantastic paper and if you like this you should really go read that.\n",
+    "This notebook is much lighter.\n",
+    "We're going to look at things from the point-of-view of the [\"Bananas, Lenses, & Barbed Wire\"](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.41.125) paper, all about hylomorphisms, anamorphisms, catamorphisms, etc."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
     "## [Hylomorphism](https://en.wikipedia.org/wiki/Hylomorphism_%28computer_science%29)\n",
     "\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 [hylomorphism](https://en.wikipedia.org/wiki/Hylomorphism_%28computer_science%29) is a recursive function `H` that converts a value of type `𝔸` into a value of type `ℂ` by means of:\n",
     "\n",
-    "- A generator `G` from `A` to `(B, A)`\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",
+    "- A generator `G` from `𝔸` to `(𝔹, 𝔸)`\n",
+    "- A combiner `Q` from `(𝔹, ℂ)` to `ℂ`\n",
+    "- A predicate `P` from `𝔸` to `Bool` to detect the base case\n",
+    "- A base case value `c` of type ``, and\n",
     "- Recursive calls (zero or more); it has a \"call stack in the form of a cons list\".\n",
     "\n",
     "It may be helpful to see this function implemented in pseudocode (Python).\n",
     "\n",
     "        return H\n",
     "\n",
-    "Cf. [\"Bananas, Lenses, & Barbed Wire\"](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.41.125)\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\".\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\"."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
     "## 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. (The reason for the order of the parameters will become clear below):\n",
     "\n",
     "    H == [P] c [G] [Q] hylomorphism\n",
     "\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`.\n",
+    "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 `H`.\n",
     "The then-part just discards the leftover `a` and replaces it with the base case value `c`:\n",
     "\n",
     "    H == [P] [pop c] [J] ifte\n",
     "\n",
     "    a J\n",
     "\n",
-    "The first thing to do is use the generator `G` which produces values `b` and a new `aa`:\n",
+    "The first thing to do is use the generator `G` which produces values `b` and a new `a`:\n",
     "\n",
     "        a G\n",
     "    ----------\n",
-    "       aa b\n",
+    "       a b\n",
     "\n",
     "So:\n",
     "\n",
     "    J == G J′\n",
     "\n",
-    "Then we recur with `H` on `aa`:\n",
+    "Then we recur with `H` on `a`:\n",
     "\n",
-    "       aa b [H] dip\n",
+    "       a b [H] dip\n",
     "    ------------------\n",
-    "         aa H b\n",
+    "         a H b\n",
     "    ------------------\n",
-    "          cc b\n",
+    "          c b\n",
     "\n",
     "So:\n",
     "\n",
     "\n",
     "And run `Q` on the result:\n",
     "\n",
-    "       cc b Q\n",
+    "       c b Q\n",
     "    ------------\n",
     "         c\n",
     "So:\n",
     "it is a simple specialization of the general recursion combinator.\n",
     "\n",
     "    [P]      c  [G]     [Q] hylomorphism\n",
-    "    [P] [pop c] [G] [dip Q] genrec\n",
-    "\n",
+    "    [P] [pop c] [G] [dip Q] genrec"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
     "## Derivation of `hylomorphism` combinator\n",
     "\n",
-    "Now we just need to derive a definition that builds the `genrec` arguments\n",
-    "out of the pieces given to the `hylomorphism` combinator.\n",
+    "Now we just need to derive a definition that builds the `genrec` arguments out of the pieces given to the `hylomorphism` combinator.\n",
     "\n",
-    "       [P]      c  [G]     [F] hylomorphism\n",
+    "       [P]      c  [G]     [Q] hylomorphism\n",
     "    ------------------------------------------\n",
-    "       [P] [pop c] [G] [dip F] genrec\n",
+    "       [P] [pop c] [G] [dip Q] genrec\n",
     "\n",
     "Working in reverse:\n",
     "\n",
-    "- Use `swoncat` twice to decouple `[c]` and `[F]`.\n",
+    "- Use `swoncat` twice to decouple `[c]` and `[Q]`.\n",
     "- Use `unit` to dequote `c`.\n",
     "- Use `dipd` to untangle `[unit [pop] swoncat]` from the givens.\n",
     "\n",
-    "    H == [P] [pop c]              [G]                  [dip F] 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 [G] [F] [unit [pop] swoncat] dipd [dip] swoncat genrec\n",
+    "    H == [P] [pop c]              [G]                  [dip Q] genrec\n",
+    "         [P] [c]    [pop] swoncat [G]        [Q] [dip] swoncat genrec\n",
+    "         [P] c unit [pop] swoncat [G]        [Q] [dip] swoncat genrec\n",
+    "         [P] c [G] [Q] [unit [pop] swoncat] dipd [dip] swoncat genrec\n",
     "\n",
-    "At this point all of the arguments (givens) to the hylomorphism are to the left so we have\n",
-    "a definition for `hylomorphism`:\n",
+    "At this point all of the parameters of the hylomorphism are to the left so we have a definition for `hylomorphism`:\n",
     "\n",
     "    hylomorphism == [unit [pop] swoncat] dipd [dip] swoncat genrec"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 1,
+   "execution_count": 1,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": []
+    }
+   ],
+   "source": [
+    "[hylomorphism [unit [pop] swoncat] dipd [dip] swoncat genrec] inscribe"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Example: Finding [Triangular Numbers](https://en.wikipedia.org/wiki/Triangular_number)\n",
+    "Let's write a function that, given a positive integer, returns the sum of all positive integers less than that one.  (In this case the types `𝔸`, `𝔹` and `ℂ` are all `int`.)\n",
+    "\n",
+    "To sum a range of integers from 0 to *n* - 1:\n",
+    "\n",
+    "- `[P]` is `[1 <=]`\n",
+    "- `c` is `0`\n",
+    "- `[G]` is `[-- dup]`\n",
+    "- `[Q]` is `[+]`"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": []
+    }
+   ],
+   "source": [
+    "[triangular_number [1 <=] 0 [-- dup] [+] hylomorphism] inscribe"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Let's try it:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "10"
+     ]
+    }
+   ],
+   "source": [
+    "5 triangular_number"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[0 0 1 3 6 10 15 21]"
+     ]
+    }
+   ],
+   "source": [
+    "clear\n",
+    "\n",
+    "[0 1 2 3 4 5 6 7] [triangular_number] map"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Neat!"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "In the Wikipedia entry for [hylomorphism](https://en.wikipedia.org/wiki/Hylomorphism_%28computer_science%29) it says:\n",
+    "\n",
+    "> a hylomorphism is a recursive function, corresponding to the composition of an [anamorphism](https://en.wikipedia.org/wiki/Anamorphism) (which first builds a set of results; also known as 'unfolding') followed by a [catamorphism](https://en.wikipedia.org/wiki/Catamorphism) (which then folds these results into a final return value).\n",
+    "\n",
+    "\n",
+    "\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Anamorphism\n",
+    "An anamorphism can be defined as a hylomorphism that uses `[]` for `c` and\n",
+    "`swons` for `Q`.  An anamorphic function builds a list of values.\n",
+    "\n",
+    "    A == [P] [] [G] [swons] hylomorphism\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",
+    "    range == [0 <=] [] [-- dup] [swons] hylomorphism"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 16,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": []
+    }
+   ],
+   "source": [
+    "clear "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "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": {
+    "scrolled": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[4 3 2 1 0]"
+     ]
+    }
+   ],
+   "source": [
+    "5 range"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Catamorphism\n",
+    "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] [Q] hylomorphism\n",
+    "\n",
+    "An example of a catamorphism is the sum function.\n",
+    "\n",
+    "    sum == [not] 0 [uncons swap] [+] hylomorphism"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": []
+    }
+   ],
+   "source": [
+    "clear "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": []
+    }
+   ],
+   "source": [
+    "[sum [not] 0 [uncons swap] [+] hylomorphism] inscribe"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "15"
+     ]
+    }
+   ],
+   "source": [
+    "[5 4 3 2 1] sum"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": []
+    }
+   ],
+   "source": [
+    "clear "
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The [\"Bananas, Lenses, & Barbed Wire\"](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.41.125) paper mentions the\n",
+    "\n",
+    "### \"Fusion Law\" for catamorphisms\n",
+    "\n",
+    "    f . (| b, (+) |) = (| c, (x) |)  <==  f b = c /\\ f( a (+) as ) = a (x) (f as)\n",
+    "\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The [\"Bananas, Lenses, & Barbed Wire\"](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.41.125) paper mentions the\n",
+    "\n",
+    "### \"Fusion Law\" for catamorphisms\n",
+    "\n",
+    "    f ∘ ⦇b,⨁⦈ = ⦇c,⨂⦈  ⇐  f b = c ∧ f(a ⨁ as) = a ⨂ (f as)\n",
+    "\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "    b [⨁] catamorphism f == c [⨂] catamorphism\n",
+    "    \n",
+    "    f == 10 *\n",
+    "    \n",
+    "    0 [+] catamorphism f\n",
+    "    \n",
+    "    0 f == 0\n",
+    "    \n",
+    "    as a + f  ==  as f a ⨂\n",
+    "    \n",
+    "    ⨂ = f +\n",
+    "    \n",
+    "    0 [+] catamorphism f  = 0 [f +] catamorphism\n",
+    "    "
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "⨁ ⨂ ∘ ∧ ⦇ ⦈ ⇐"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### The `step` combinator\n",
+    "The `step` combinator will often be easier to use than `catamorphism`."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 21,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "\n",
+      "==== Help on step ====\n",
+      "\n",
+      "Run a quoted program on each item in a sequence.\n",
+      "::\n",
+      "\n",
+      "       ... [] [Q] . step\n",
+      "    -----------------------\n",
+      "          ... .\n",
+      "\n",
+      "\n",
+      "       ... [a] [Q] . step\n",
+      "    ------------------------\n",
+      "         ... a . Q\n",
+      "\n",
+      "\n",
+      "       ... [a b c] [Q] . step\n",
+      "    ----------------------------------------\n",
+      "             ... a . Q [b c] [Q] step\n",
+      "\n",
+      "The step combinator executes the quotation on each member of the list\n",
+      "on top of the stack.\n",
+      "\n",
+      "---- end (step)\n",
+      "\n",
+      "\n"
+     ]
+    }
+   ],
+   "source": [
+    "[step] help"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 22,
    "metadata": {},
    "outputs": [
     {
     }
    ],
    "source": [
-    "[hylomorphism [unit [pop] swoncat] dipd [dip] swoncat genrec] inscribe"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "### Example: Finding [Triangular Numbers](https://en.wikipedia.org/wiki/Triangular_number)\n",
-    "Let's 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`.)\n",
-    "\n",
-    "To sum a range of integers from 0 to *n* - 1:\n",
-    "\n",
-    "- `[P]` is `[1 <=]`\n",
-    "- `c` is `0`\n",
-    "- `[G]` is `[-- dup]`\n",
-    "- `[F]` is `[+]`"
+    "[sum 0 swap [+] step] inscribe"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 2,
+   "execution_count": 23,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
-     "text": []
+     "text": [
+      "15"
+     ]
     }
    ],
    "source": [
-    "[triangular_number [1 <=] 0 [-- dup] [+] hylomorphism] inscribe"
+    "[5 4 3 2 1] sum"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Let's try it:"
+    "## Hylo- is Ana- then Cata-\n",
+    "\n",
+    "    anamorphism == [] swap [swons] hylomorphism\n",
+    "    \n",
+    "    catamorphism == [[not] swap [uncons swap]] dip hylomorphism\n",
+    "\n",
+    "A hylomorphism can be thought of as the composition of an anamorphism and a catamorphism:\n",
+    "\n",
+    "    [P] [G] anamorphism c [Q] catamorphism == [P] c [G] [Q] hylomorphism\n"
    ]
   },
   {
-   "cell_type": "code",
-   "execution_count": 3,
+   "cell_type": "markdown",
    "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "10"
-     ]
-    }
-   ],
    "source": [
-    "5 triangular_number"
+    "For example, `triangular_number` could be defined as the composition of the `range` and `sum` functions:\n",
+    "\n",
+    "    triangular_number == range sum"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 4,
+   "execution_count": 15,
    "metadata": {},
    "outputs": [
     {
    "source": [
     "clear\n",
     "\n",
-    "[0 1 2 3 4 5 6 7] [triangular_number] map"
+    "[0 1 2 3 4 5 6 7] [range sum] map"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Neat!"
+    "However, this creates (and destroys) an intermediate list, which is a waste."
    ]
   },
   {
    "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 `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 needs to operate on the current value of the datastructure or the generator's output, in other words, whether `F` or `G` should run first in the recursive branch.\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",
-    "    H1 ==        [P] [pop c] [G             ] [dip F] genrec\n",
-    "    H2 == c swap [P] [pop]   [G [F]    dip  ] [i]     genrec\n",
-    "    H3 ==        [P] [pop c] [  [G] dupdip  ] [dip F] genrec\n",
-    "    H4 == c swap [P] [pop]   [  [F] dupdip G] [i]     genrec\n",
+    "    H1 ==        [P] [pop c] [G             ] [dip Q] genrec\n",
+    "    H2 == c swap [P] [pop]   [G [Q]    dip  ] [i]     genrec\n",
+    "    H3 ==        [P] [pop c] [  [G] dupdip  ] [dip Q] genrec\n",
+    "    H4 == c swap [P] [pop]   [  [Q] dupdip G] [i]     genrec\n",
     "\n",
     "The working of the generator function `G` differs slightly for each.  Consider the recursive branches:\n",
     "\n",
-    "    ... a G [H1] dip F                w/ a G == a′ b\n",
+    "    ... a G [H1] dip Q                w/ a G == a′ b\n",
     "    \n",
-    "    ... c a G [F] dip H2                 a G == b  a′\n",
+    "    ... c a G [Q] dip H2                 a G == b  a′\n",
     "    \n",
-    "    ... a [G] dupdip [H3] dip F          a G == a′\n",
+    "    ... a [G] dupdip [H3] dip Q          a G == a′\n",
     "    \n",
-    "    ... c a [F] dupdip G H4              a G == a′\n",
+    "    ... c a [Q] dupdip G H4              a G == a′\n",
     "\n",
     "The following four sections illustrate how these work, omitting the predicate evaluation."
    ]
    "source": [
     "### `H1`\n",
     "\n",
-    "    H1 == [P] [pop c] [G] [dip F] genrec\n",
-    "\n",
-    "Iterate n times.\n",
-    "\n",
-    "    ... a  G [H1] dip F\n",
-    "    ... a′ b [H1] dip F\n",
-    "    ... a′ H1 b F\n",
-    "    ... a′ G [H1] dip F b F\n",
-    "    ... a″ b′ [H1] dip F b F\n",
-    "    ... a″ H1 b′ F b F\n",
-    "    ... a″ G [H1] dip F b′ F b F\n",
-    "    ... a‴ b″ [H1] dip F b′ F b F\n",
-    "    ... a‴ H1 b″ F b′ F b F\n",
-    "    ... a‴ pop c b″ F b′ F b F\n",
-    "    ... c b″ F b′ F b F\n",
-    "    ... d      b′ F b F\n",
-    "    ... d′          b F\n",
-    "    ... d″\n",
-    "\n",
-    "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 combiner `F`."
+    "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 combiner `Q`.\n",
+    "\n",
+    "    H1 == [P] [pop c] [G] [dip Q] genrec\n",
+    "\n",
+    "    ... a G [H1] dip Q\n",
+    "    ... a′ b [H1] dip Q\n",
+    "    ... a′ H1 b Q\n",
+    "       <predicate omitted>\n",
+    "    ... a′ G [H1] dip Q b Q\n",
+    "    ... a″ b′ [H1] dip Q b Q\n",
+    "    ... a″ H1 b′ Q b Q\n",
+    "       <predicate omitted>\n",
+    "    ... a″ G [H1] dip Q b′ Q b Q\n",
+    "    ... a‴ b″ [H1] dip Q b′ Q b Q\n",
+    "    ... a‴ H1 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‴"
    ]
   },
   {
    "metadata": {},
    "source": [
     "### `H2`\n",
-    "When you can start with the identity value `c` on the stack and the combiner `F` can operate as you go using the intermediate results immediately rather than queuing them up, use this form.  An important difference is that the generator function must return its results in the reverse order.\n",
     "\n",
-    "    H2 == c swap [P] [pop] [G [F] dip] primrec\n",
+    "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, use this form.\n",
+    "An important difference is that the generator function must return its results in the reverse order,\n",
+    "and both `Q` and `G` have to take into account the presence of the `c` value:\n",
     "\n",
-    "    ... c a G  [F] dip H2\n",
-    "    ... c b a′ [F] dip H2\n",
-    "    ... c b F a′ H2\n",
-    "    ... d     a′ H2\n",
-    "    ... d a′ G  [F] dip H2\n",
-    "    ... d b′ a″ [F] dip H2\n",
-    "    ... d b′ F a″ H2\n",
-    "    ... d′     a″ H2\n",
-    "    ... d′ a″ G  [F] dip H2\n",
-    "    ... d′ b″ a‴ [F] dip H2\n",
-    "    ... d′ b″ F a‴ H2\n",
-    "    ... d″      a‴ H2\n",
-    "    ... d″ a‴ pop\n",
-    "    ... d″\n"
+    "    H2 == c swap [P] [pop] [G [Q] dip] tailrec\n",
+    "\n",
+    "    ... c a G [Q] dip H2\n",
+    "    ... c b a′ [Q] dip H2\n",
+    "    ... c b Q a′ H2\n",
+    "    ... c′ a′ H2\n",
+    "       <predicate omitted>\n",
+    "    ... c′ a′ G [Q] dip H2\n",
+    "    ... c′ b′ a″ [Q] dip H2\n",
+    "    ... c′ b′ Q a″ H2\n",
+    "    ... c″ a″ H2\n",
+    "       <predicate omitted>\n",
+    "    ... c″ a″ G [Q] dip H2\n",
+    "    ... c″ b″ a‴ [Q] dip H2\n",
+    "    ... c″ b″ Q a‴ H2\n",
+    "    ... c‴ a‴ H2\n",
+    "       <predicate omitted>\n",
+    "    ... c‴ a‴ pop\n",
+    "    ... c‴\n"
    ]
   },
   {
    "metadata": {},
    "source": [
     "### `H3`\n",
-    "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 `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.)\n",
-    "\n",
-    "\n",
-    "    H3 == [P] [pop c] [[G] dupdip] [dip F] genrec\n",
     "\n",
-    "    ... a [G] dupdip [H3] dip F\n",
-    "    ... a  G  a      [H3] dip F\n",
-    "    ... a′    a      [H3] dip F\n",
-    "    ... a′ H3 a               F\n",
-    "    ... a′ [G] dupdip [H3] dip F a F\n",
-    "    ... a′  G  a′     [H3] dip F a F\n",
-    "    ... a″     a′     [H3] dip F a F\n",
-    "    ... a″ H3  a′              F a F\n",
-    "    ... a″ [G] dupdip [H3] dip F a′ F a F\n",
-    "    ... a″  G    a″   [H3] dip F a′ F a F\n",
-    "    ... a‴       a″   [H3] dip F a′ F a F\n",
-    "    ... a‴ H3    a″            F a′ F a F\n",
-    "    ... a‴ pop c a″ F a′ F a F\n",
-    "    ...        c a″ F a′ F a F\n",
-    "    ...        d      a′ F a F\n",
-    "    ...        d′          a F\n",
-    "    ...        d″"
+    "If you examine the traces above you'll see that the combiner `Q` 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.)\n",
+    "\n",
+    "\n",
+    "    H3 == [P] [pop c] [[G] dupdip] [dip Q] genrec\n",
+    "\n",
+    "    ... a [G] dupdip [H3] dip Q\n",
+    "    ... a G a [H3] dip Q\n",
+    "    ... a′ a [H3] dip Q\n",
+    "    ... a′ H3 a Q\n",
+    "       <predicate omitted>\n",
+    "    ... a′ [G] dupdip [H3] dip Q a Q\n",
+    "    ... a′ G a′ [H3] dip Q a Q\n",
+    "    ... a″ a′ [H3] dip Q a Q\n",
+    "    ... a″ H3 a′ Q a Q\n",
+    "       <predicate omitted>\n",
+    "    ... a″ [G] dupdip [H3] dip Q a′ Q a Q\n",
+    "    ... a″ G a″ [H3] dip Q a′ Q a Q\n",
+    "    ... a‴ a″ [H3] dip Q a′ Q a Q\n",
+    "    ... a‴ H3 a″ Q a′ Q a Q\n",
+    "       <predicate omitted>\n",
+    "    ... a‴ pop c a″ Q a′ Q a Q\n",
+    "    ... c a″ Q a′ Q a Q\n",
+    "    ... c′ a′ Q a Q\n",
+    "    ... c‴ a Q\n",
+    "    ... c‴"
    ]
   },
   {
    "metadata": {},
    "source": [
     "### `H4`\n",
-    "And, last but not least, if you can combine as you go, starting with `c`, and the combiner `F` needs to work on the current item, this is the form:\n",
-    "\n",
-    "    H4 == c swap [P] [pop] [[F] dupdip G] primrec\n",
-    "\n",
-    "    ... c  a  [F] dupdip G H4\n",
-    "    ... c  a   F  a      G H4\n",
-    "    ... d         a      G H4\n",
-    "    ... d  a′              H4\n",
-    "    ... d  a′ [F] dupdip G H4\n",
-    "    ... d  a′  F  a′     G H4\n",
-    "    ... d′        a′     G H4\n",
-    "    ... d′ a″              H4\n",
-    "    ... d′ a″ [F] dupdip G H4\n",
-    "    ... d′ a″  F  a″     G H4\n",
-    "    ... d″        a″     G H4\n",
-    "    ... d″ a‴              H4\n",
-    "    ... d″ a‴ pop\n",
-    "    ... d″"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "## Anamorphism\n",
-    "An anamorphism can be defined as a hylomorphism that uses `[]` for `c` and\n",
-    "`swons` for `F`.  An anamorphic function builds a list of values.\n",
     "\n",
-    "    A == [P] [] [G] [swons] hylomorphism"
+    "And, last but not least, if you can combine as you go, starting with `c`, and the combiner `Q` needs to work on the current item, this is the form:\n",
+    "\n",
+    "    H4 == c swap [P] [pop] [[Q] dupdip G] primrec\n",
+    "\n",
+    "    ... c a [Q] dupdip G H4\n",
+    "    ... c a Q a G H4\n",
+    "    ... c′ a G H4\n",
+    "    ... c′ a′ H4\n",
+    "       <predicate omitted>\n",
+    "    ... c′ a′ [Q] dupdip G H4\n",
+    "    ... c′ a′ Q a′ G H4\n",
+    "    ... c‴ a′ G H4\n",
+    "    ... c‴ a″ H4\n",
+    "       <predicate omitted>\n",
+    "    ... c‴ a″ [Q] dupdip G H4\n",
+    "    ... c‴ a″ Q a″ G H4\n",
+    "    ... c‴ a″ G H4\n",
+    "    ... c‴ a‴ H4\n",
+    "       <predicate omitted>\n",
+    "    ... c‴ a‴ pop\n",
+    "    ... c‴"
    ]
   },
   {
    "metadata": {},
    "source": [
     "#### `range` with `H1`\n",
-    "    H1 == [P]    [pop c]  [G]      [dip F]     genrec\n",
+    "    H1 == [P]    [pop c]  [G]      [dip Q]     genrec\n",
     "       == [0 <=] [pop []] [-- dup] [dip swons] genrec"
    ]
   },
    "metadata": {},
    "source": [
     "#### `range` with `H2`\n",
-    "    H2 == c  swap [P]    [pop] [G      [F]     dip] tailrec\n",
+    "    H2 == c  swap [P]    [pop] [G      [Q]     dip] tailrec\n",
     "       == [] swap [0 <=] [pop] [-- dup [swons] dip] tailrec"
    ]
   },
    "metadata": {},
    "source": [
     "#### `range` with `H3`\n",
-    "    H3 == [P]    [pop c]  [[G]  dupdip] [dip F]     genrec\n",
+    "    H3 == [P]    [pop c]  [[G]  dupdip] [dip Q]     genrec\n",
     "       == [0 <=] [pop []] [[--] dupdip] [dip swons] genrec"
    ]
   },
    "metadata": {},
    "source": [
     "#### `range` with `H4`\n",
-    "    H4 == c  swap [P]    [pop] [[F]     dupdip G ] primrec\n",
+    "    H4 == c  swap [P]    [pop] [[Q]     dupdip G ] primrec\n",
     "       == [] swap [0 <=] [pop] [[swons] dupdip --] primrec"
    ]
   },
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "## Catamorphism\n",
-    "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",
+    "## Example: Factorial Function\n",
+    "\n",
+    "For the Factorial function:\n",
     "\n",
-    "    C == [not] c [uncons swap] [F] hylomorphism\n",
+    "    H4 == c swap [P] [pop] [[Q] dupdip G] tailrec\n",
     "\n",
-    "An example of a catamorphism is the sum function.\n",
+    "With:\n",
     "\n",
-    "    sum == [not] 0 [uncons swap] [+] hylomorphism"
+    "    c == 1\n",
+    "    Q == *\n",
+    "    G == --\n",
+    "    P == 1 <="
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 17,
+   "execution_count": 24,
    "metadata": {},
    "outputs": [
     {
     }
    ],
    "source": [
-    "clear "
+    "clear"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 18,
+   "execution_count": 25,
    "metadata": {},
    "outputs": [
     {
     }
    ],
    "source": [
-    "[sum [not] 0 [uncons swap] [+] hylomorphism] inscribe"
+    "[factorial 1 swap [1 <=] [pop] [[*] dupdip --] tailrec] inscribe"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 19,
-   "metadata": {},
+   "execution_count": 26,
+   "metadata": {
+    "scrolled": false
+   },
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "15"
+      "120"
      ]
     }
    ],
    "source": [
-    "[5 4 3 2 1] sum"
+    "5 factorial"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Example: Filter Function\n",
+    "\n",
+    "An often-used function is `filter` which takes a list and a predicate and makes a new list with only those items from the input list that make the predicate true:\n",
+    "\n",
+    "       [...] [P] filter\n",
+    "    ----------------------\n",
+    "            [...]′\n",
+    "\n",
+    "Let's start by making a simpler function that just recreates the input list:\n",
+    "\n",
+    "    F == [not] [] [J] ifte\n",
+    "\n",
+    "To figure out the recursive branch `J` we start by setting a dummy list in front of it.\n",
+    "\n",
+    "    [a b c] J\n",
+    "    [a b c] uncons swap J′\n",
+    "    a [b c]        swap J′\n",
+    "    [b c] a             J′\n",
+    "\n",
+    "    J == uncons swap J′\n",
+    "\n",
+    "We don't have the output list to which to `cons` that `a` so we recur instead and *then* `cons` (more precisely `swons`) it:\n",
+    "\n",
+    "    J′ == [Q] dip swons\n",
+    "\n",
+    "    [b c] a [Q] dip swons\n",
+    "    [b c] Q a swons\n",
+    "    ...\n",
+    "    [c] Q b swons a swons\n",
+    "    ...\n",
+    "    [] c swons b swons a swons\n",
+    "    ...\n",
+    "    [a b c]\n",
+    "\n",
+    "So:\n",
+    "\n",
+    "    J == uncons swap [Q] dip swons\n",
+    "\n",
+    "And:\n",
+    "\n",
+    "    F == [not] [] [uncons swap [F] dip swons] ifte\n",
+    "         [not] [] [uncons swap]   [dip swons] genrec\n",
+    "\n"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 20,
+   "execution_count": 27,
    "metadata": {},
    "outputs": [
     {
     }
    ],
    "source": [
-    "clear "
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "### The `step` combinator\n",
-    "The `step` combinator will usually be better to use than `catamorphism`."
+    "clear"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 21,
+   "execution_count": 28,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "\n",
-      "==== Help on step ====\n",
-      "\n",
-      "Run a quoted program on each item in a sequence.\n",
-      "::\n",
-      "\n",
-      "       ... [] [Q] . step\n",
-      "    -----------------------\n",
-      "          ... .\n",
-      "\n",
-      "\n",
-      "       ... [a] [Q] . step\n",
-      "    ------------------------\n",
-      "         ... a . Q\n",
-      "\n",
-      "\n",
-      "       ... [a b c] [Q] . step\n",
-      "    ----------------------------------------\n",
-      "             ... a . Q [b c] [Q] step\n",
-      "\n",
-      "The step combinator executes the quotation on each member of the list\n",
-      "on top of the stack.\n",
-      "\n",
-      "---- end (step)\n",
-      "\n",
-      "\n"
+      "[1 2 3]"
      ]
     }
    ],
    "source": [
-    "[step] help"
+    "[1 2 3] [not] [] [uncons swap] [dip swons] genrec"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "scrolled": false
+   },
+   "source": [
+    "It would seem that all we need to do now is turn the `swons` into an expression that applies the input `P` predicate to the items and only puts them on the output list if they pass.\n",
+    "\n",
+    "    filter == [not] [] [uncons swap] [dip W] genrec\n",
+    "\n",
+    "Resulting in, e.g.:\n",
+    "\n",
+    "    [] c W b W a W\n",
+    "\n",
+    "However, the input list will be on the stack just below the item, so `W` has to take account of that.  If our predicate function doesn't use any values from below the item under consideration then we're okay, but if it does then we have to deal with the input list somehow.\n",
+    "\n",
+    "We know `W` would be something like:\n",
+    "\n",
+    "    W == [...[P]...] [swons] [pop] ifte\n",
+    "\n",
+    "Let's examine the situation:\n",
+    "\n",
+    "    ... [...] item [...[P]...] [swons] [pop] ifte\n",
+    "\n",
+    "Since the predicate of the `ifte` combinator is applied `nullary` we can just `pop` the output list:\n",
+    "\n",
+    "    ... [...] item popd P\n",
+    "\n",
+    "And since `[P]` is already a quote:\n",
+    "\n",
+    "    W == [popd P] [swons] [pop] ifte\n",
+    "\n",
+    "Ergo:\n",
+    "\n",
+    "    [P] filter == [not] [] [uncons swap] [dip [popd P] [swons] [pop] ifte] genrec\n",
+    "\n",
+    "Getting that `P` into position is straightforward.  Working in reverse:\n",
+    "\n",
+    "    [not] [] [uncons swap] [dip [popd P] [swons] [pop] ifte] genrec\n",
+    "\n",
+    "Undip the first three terms:\n",
+    "\n",
+    "    [dip [popd P] [swons] [pop] ifte] [[not] [] [uncons swap]] dip genrec\n",
+    "                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
+    "\n",
+    "Take off the `[dip]` prefix:\n",
+    "\n",
+    "    [[popd P] [swons] [pop] ifte] [dip] swoncat [[not] [] [uncons swap]] dip genrec\n",
+    "                                  ^^^^^^^^^^^^^\n",
+    "\n",
+    "Uncons the term containing `P`:\n",
+    "\n",
+    "    [popd P] [[swons] [pop] ifte] cons [dip] swoncat [[not] [] [uncons swap]] dip genrec\n",
+    "    ^^^^^^^^                      ^^^^\n",
+    "\n",
+    "And then take off the `[popd]` prefix:\n",
+    "\n",
+    "    [P] [popd] swoncat [[swons] [pop] ifte] cons [dip] swoncat [[not] [] [uncons swap]] dip genrec\n",
+    "        ^^^^^^^^^^^^^^\n",
+    "\n",
+    "And so:\n",
+    "\n",
+    "    filter == [popd] swoncat [[swons] [pop] ifte] cons [dip] swoncat [[not] [] [uncons swap]] dip genrec\n"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 22,
+   "execution_count": 29,
    "metadata": {},
    "outputs": [
     {
     }
    ],
    "source": [
-    "[sum 0 swap [+] step] inscribe"
+    "clear"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 23,
+   "execution_count": 30,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
-     "text": [
-      "15"
-     ]
+     "text": []
     }
    ],
    "source": [
-    "[5 4 3 2 1] sum"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "## Example: Factorial Function\n",
-    "\n",
-    "For the Factorial function:\n",
-    "\n",
-    "    H4 == c swap [P] [pop] [[F] dupdip G] primrec\n",
-    "\n",
-    "With:\n",
-    "\n",
-    "    c == 1\n",
-    "    F == *\n",
-    "    G == --\n",
-    "    P == 1 <="
+    "[filter [popd] swoncat [[swons] [pop] ifte] cons [dip] swoncat [[not] [] [uncons swap]] dip genrec] inscribe"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 24,
+   "execution_count": 31,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
-     "text": []
+     "text": [
+      "[1 2 3 4 5 6 7 8] [2 mod not]"
+     ]
     }
    ],
    "source": [
-    "clear"
+    "[1 2 3 4 5 6 7 8] [2 mod not]"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 25,
+   "execution_count": 32,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
-     "text": []
+     "text": [
+      "[2 4 6 8]"
+     ]
     }
    ],
    "source": [
-    "[factorial 1 swap [1 <=] [pop] [[*] dupdip --] tailrec] inscribe"
+    "filter"
    ]
   },
   {
-   "cell_type": "code",
-   "execution_count": 26,
+   "cell_type": "markdown",
    "metadata": {
     "scrolled": false
    },
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "120"
-     ]
-    }
-   ],
    "source": [
-    "5 factorial"
+    "This isn't completely satisfying.  For one thing, it would be nice to apply the predicate as we go so we are not putting items (and `W`) onto the expression for items that will fail the predicate `P`."
    ]
   },
   {
   },
   {
    "cell_type": "code",
-   "execution_count": 27,
+   "execution_count": 33,
    "metadata": {},
    "outputs": [
     {
   },
   {
    "cell_type": "code",
-   "execution_count": 28,
+   "execution_count": 34,
    "metadata": {},
    "outputs": [
     {
   },
   {
    "cell_type": "code",
-   "execution_count": 29,
+   "execution_count": 35,
    "metadata": {},
    "outputs": [
     {
     "\n",
     "### Hylo-, Ana-, Cata-\n",
     "\n",
-    "    H == [P  ] [pop c ] [G          ] [dip F        ] genrec\n",
+    "    H == [P  ] [pop c ] [G          ] [dip Q        ] genrec\n",
     "    A == [P  ] [pop []] [G          ] [dip swap cons] genrec\n",
-    "    C == [not] [pop c ] [uncons swap] [dip F        ] genrec\n",
+    "    C == [not] [pop c ] [uncons swap] [dip Q        ] genrec\n",
     "\n",
     "### Para-, ?-, ?-\n",
     "\n",
-    "    P == c  swap [P  ] [pop] [[F        ] dupdip G          ] primrec\n",
+    "    P == c  swap [P  ] [pop] [[Q        ] dupdip G          ] primrec\n",
     "    ? == [] swap [P  ] [pop] [[swap cons] dupdip G          ] primrec\n",
-    "    ? == c  swap [not] [pop] [[F        ] dupdip uncons swap] primrec\n"
+    "    ? == c  swap [not] [pop] [[Q        ] dupdip uncons swap] primrec\n"
    ]
   },
   {
    "source": [
     "## Appendix: Fun with Symbols\n",
     "\n",
-    "    |[ (c, F), (G, P) ]| == (|c, F|) • [(G, P)]\n",
+    "    |[ (c, Q), (G, P) ]| == (|c, Q|) • [(G, P)]\n",
     "\n",
     "[\"Bananas, Lenses, & Barbed Wire\"](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.41.125)\n",
     "\n",
diff --git a/docs/Remove-Function.ipynb b/docs/Remove-Function.ipynb
new file mode 100644 (file)
index 0000000..4c2b5ad
--- /dev/null
@@ -0,0 +1,484 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "id": "0edff064",
+   "metadata": {},
+   "source": [
+    "# `remove`\n",
+    "\n",
+    "       [1 2 3 4] 5 remove\n",
+    "    ------------------------\n",
+    "          [1 2 3 4]\n",
+    "\n",
+    "       [1 2 3 4] 2 remove\n",
+    "    ------------------------\n",
+    "          [1 3 4]\n",
+    "\n",
+    "       [] a remove\n",
+    "    ------------------------\n",
+    "          []\n",
+    "\n",
+    "## First attempt\n",
+    "\n",
+    "First let's handle the case of an empty list:\n",
+    "\n",
+    "    remove == [pop not] [pop] [remove'] ifte\n",
+    "\n",
+    "For non-empty lists, the predicate and base case are easy:\n",
+    "\n",
+    "    remove' == [swap first =] [pop rest] [R0] [R1] genrec\n",
+    "\n",
+    "The recursive branch:\n",
+    "\n",
+    "    [1 2 3 4] 3 R0 [remove'] R1\n",
+    "\n",
+    "For `R0` use `[uncons] dip`:\n",
+    "\n",
+    "    [1 2 3 4] 3 [uncons] dip [remove'] R1\n",
+    "    [1 2 3 4] uncons 3 [remove'] R1\n",
+    "    1 [2 3 4] 3 [remove'] R1\n",
+    "\n",
+    "For `R1` let's try `i cons`:\n",
+    "\n",
+    "    1 [2 3 4] 3 [remove'] i cons\n",
+    "    1 [2 3 4] 3 remove' cons\n",
+    "    ...\n",
+    "    1 2 [3 4] 3 remove' cons cons\n",
+    "    ...\n",
+    "    1 2 [4] cons cons\n",
+    "    ...\n",
+    "    [1 2 4]\n",
+    "\n",
+    "Ergo:\n",
+    "\n",
+    "    remove' == [swap first =] [pop rest] [[uncons] dip] [i cons] genrec\n",
+    "    remove  == [pop not] [pop] [remove'] ifte\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "id": "80f0926d",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": []
+    }
+   ],
+   "source": [
+    "[remove' [swap first =] [pop rest] [[uncons] dip] [i cons] genrec] inscribe\n",
+    "[remo [pop not] [pop] [remove'] ifte] inscribe"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "id": "6ef0d06a",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[1 2 3 4] 3"
+     ]
+    }
+   ],
+   "source": [
+    "[1 2 3 4] 3 "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "id": "e0c12f34",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[1 2 4]"
+     ]
+    }
+   ],
+   "source": [
+    "remo"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "e34f9996",
+   "metadata": {},
+   "source": [
+    "So far so good but I made a mistake.  The recursive part doesn't handle empty lists, so it's broken for the case of the item not being in the list:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "id": "ecb11a12",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[1 2 4] 45"
+     ]
+    }
+   ],
+   "source": [
+    "45"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "fb6472f5",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    " remo"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "fd33d021",
+   "metadata": {},
+   "source": [
+    "## Second attempt\n",
+    "\n",
+    "    remove == [pop not] [pop] [R0] [R1] genrec\n",
+    "    remove == [pop not] [pop] [R0 [remove] R1] ifte\n",
+    "\n",
+    "Non-empty:\n",
+    "\n",
+    "    [a b c] item R0 [remove] R1\n",
+    "\n",
+    "\n",
+    "                       R0 [remove] R1\n",
+    "    -----------------------------------------------------\n",
+    "       [swap first =] [pop rest] [E1 [remove] E2] ifte\n",
+    "\n",
+    "Recursive branch:\n",
+    "\n",
+    "    [a b c] d E1 [remove] E2\n",
+    "\n",
+    "With:\n",
+    "\n",
+    "    E1 == [uncons] dip\n",
+    "    E2 == i cons\n",
+    "\n",
+    "    [a b c] d [uncons] dip [remove] i cons\n",
+    "    a [b c] d [remove] i cons\n",
+    "    a [b c] d remove cons\n",
+    "\n",
+    "How to make it?\n",
+    "\n",
+    "    R0 == [swap first =] [pop rest]\n",
+    "\n",
+    "Then we want:\n",
+    "\n",
+    "    R1 == [[uncons] dip [remove] i cons] ifte\n",
+    "\n",
+    "But of course `[remove]` can't appear in there like that, we have to package it up:\n",
+    "\n",
+    "    R1 == [i cons] cons [[uncons] dip] swoncat ifte\n",
+    "\n",
+    "Or better yet:\n",
+    "\n",
+    "    [[uncons] dip remove cons] ifte\n",
+    "\n",
+    "    R1 == [cons] concat [[uncons] dip] swoncat ifte\n",
+    "\n",
+    "Clunky, but it works:\n",
+    "\n",
+    "    remove == [pop not] [pop] [[swap first =] [pop rest]] [[cons] concat [[uncons] dip] swoncat ifte] genrec\n",
+    "    "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "id": "891135c8",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[1 2 4] 45"
+     ]
+    }
+   ],
+   "source": [
+    "[remo2 [pop not] [pop] [[swap first =] [pop rest]] [[cons] concat [[uncons] dip] swoncat ifte] genrec] inscribe"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "id": "c32ea032",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[1 2 4]"
+     ]
+    }
+   ],
+   "source": [
+    "remo2"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "id": "6bd05f5b",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[1 2 4] 2"
+     ]
+    }
+   ],
+   "source": [
+    "2"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "id": "20bdec4c",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[1 4]"
+     ]
+    }
+   ],
+   "source": [
+    "remo2"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "7605e056",
+   "metadata": {},
+   "source": [
+    "## Third attempt\n",
+    "\n",
+    "What if we let `[remove]` be on the stack instead of building the else-part each iteration?:\n",
+    "\n",
+    "    remove == [pop not] [pop] []        [[P] [THEN] [ELSE] ifte] genrec\n",
+    "    remove == [pop not] [pop] [ [remove] [P] [THEN] [ELSE] ifte] ifte\n",
+    "\n",
+    "So:\n",
+    "\n",
+    "    [a b c] item [remove] [P] [THEN] [ELSE] ifte\n",
+    "    \n",
+    "    P == pop swap first =\n",
+    "    \n",
+    "    THEN == popop rest\n",
+    "    \n",
+    "    ELSE == ...\n",
+    "\n",
+    "Hmm...\n",
+    "\n",
+    "    [a b c] item [remove] ELSE\n",
+    "    [a b c] item [remove] [uncons] dipd i cons\n",
+    "    a [b c] item [remove] i cons\n",
+    "    a [b c] item remove cons\n",
+    "    ...\n",
+    "    a [b c] cons\n",
+    "    [a b c]\n",
+    "\n",
+    "So:\n",
+    "\n",
+    "    ELSE == [uncons] dipd i cons\n",
+    "\n",
+    "And:\n",
+    "\n",
+    "    remove == [pop not] [pop] [] [[pop swap first =] [popop rest] [[uncons] dipd i cons] ifte] genrec"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "id": "acd3f326",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[1 4]"
+     ]
+    }
+   ],
+   "source": [
+    "[remo3 [pop not] [pop] [] [[pop swap first =] [popop rest] [[uncons] dipd i cons] ifte] genrec] inscribe"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "id": "70178b16",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[1 4 5 6]"
+     ]
+    }
+   ],
+   "source": [
+    "[5 6] concat"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "id": "f6cb0b12",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[1 4 5 6] 5"
+     ]
+    }
+   ],
+   "source": [
+    "5"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 13,
+   "id": "d2e6aeb8",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[1 4 6]"
+     ]
+    }
+   ],
+   "source": [
+    "remo3"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 14,
+   "id": "f2c8c0be",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[1 4 6] 5"
+     ]
+    }
+   ],
+   "source": [
+    "5"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 15,
+   "id": "deb5e389",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[1 4 6]"
+     ]
+    }
+   ],
+   "source": [
+    "remo3"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 16,
+   "id": "84fc4e3f",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[] 5"
+     ]
+    }
+   ],
+   "source": [
+    "pop [] 5"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 17,
+   "id": "ee99b894",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[]"
+     ]
+    }
+   ],
+   "source": [
+    "remo3"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "0518f168",
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Joypy",
+   "language": "",
+   "name": "thun"
+  },
+  "language_info": {
+   "file_extension": ".joy",
+   "mimetype": "text/plain",
+   "name": "Joy"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}