OSDN Git Service

Switch to Joy kernel.
authorSimon Forman <sforman@hushmail.com>
Wed, 1 Dec 2021 05:00:26 +0000 (21:00 -0800)
committerSimon Forman <sforman@hushmail.com>
Wed, 1 Dec 2021 05:00:26 +0000 (21:00 -0800)
docs/Recursion_Combinators.ipynb

index cd89f98..bfa97db 100644 (file)
@@ -1,21 +1,20 @@
 {
  "cells": [
   {
-   "cell_type": "code",
-   "execution_count": 1,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "from notebook_preamble import D, DefinitionWrapper, J, V, define"
-   ]
-  },
-  {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
     "# Recursion Combinators\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",
     "                          [if] [then] [rec1] [rec2] genrec\n",
     "    ---------------------------------------------------------------------\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. Typically it will then execute the bundled form, either with i or\n",
-    "with app2, or some other combinator.\""
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
+    "with app2, or some other combinator.\"\n",
+    "\n",
     "## Designing Recursive Functions\n",
-    "The way to design one of these is to fix your base case and \n",
-    "test and then treat `R1` and `R2` as an else-part \"sandwiching\"\n",
-    "a quotation of the whole function.\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 == [I] [T] [R1]   [R2] genrec\n",
-    "      == [I] [T] [R1 [F] R2] ifte\n",
+    "    F == [P] [T] [R1]   [R2] genrec\n",
+    "      == [P] [T] [R1 [F] R2] ifte\n",
     "\n",
-    "If the `[I]` predicate is false you must derive `R1` and `R2` from:\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`\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",
+    "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",
-    "    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",
-    "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",
-    "- A generator `G :: A -> (B, A)`\n",
-    "- A combiner `F :: (B, C) -> C`\n",
-    "- A predicate `P :: A -> Bool` to detect the base case\n",
-    "- A base case value `c :: C`\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",
+    "\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",
     "- 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 imperative Python code."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 2,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "def hylomorphism(c, F, P, G):\n",
-    "    '''Return a hylomorphism function H.'''\n",
+    "It may be helpful to see this function implemented in pseudocode (Python).\n",
     "\n",
-    "    def H(a):\n",
-    "        if P(a):\n",
-    "            result = c\n",
-    "        else:\n",
+    "    def hylomorphism(c, Q, P, G):\n",
+    "        '''Return a hylomorphism function H.'''\n",
+    "\n",
+    "        def H(a):\n",
+    "            if P(a):\n",
+    "                return c\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 result\n",
+    "            return Q(b, H(aa))\n",
+    "\n",
+    "        return H\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",
     "\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": [
+    "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",
     "## 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",
     "\n",
-    "    H == [P] c [G] [F] hylomorphism\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`.  (The then-part just\n",
-    "discards the leftover `a` and replaces it with the base case value `c`.)\n",
+    "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",
     "The else-part `J` gets just the argument `a` on the stack.\n",
     "\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",
-    "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",
+    "        a G\n",
+    "    ----------\n",
+    "       aa b\n",
+    "\n",
+    "So:\n",
+    "\n",
+    "    J == G J′\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 == G [H] dip F\n",
+    "    J″ == Q\n",
     "\n",
-    "Plug it in and convert to genrec.\n",
+    "Summing up:\n",
     "\n",
-    "    H == [P] [pop c] [G [H] dip F] ifte\n",
-    "    H == [P] [pop c] [G]   [dip F] genrec\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",
     "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",
     "\n",
-    "    H == [P] c [G] [F] hylomorphism == [P] [pop c] [G] [dip F] genrec"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
+    "    [P]      c  [G]     [Q] hylomorphism\n",
+    "    [P] [pop c] [G] [dip Q] genrec\n",
+    "\n",
     "## Derivation of `hylomorphism` combinator\n",
     "\n",
     "Now we just need to derive a definition that builds the `genrec` arguments\n",
     "- Use `unit` to dequote `c`.\n",
     "- Use `dipd` to untangle `[unit [pop] swoncat]` from the givens.\n",
     "\n",
-    "So:\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",
   },
   {
    "cell_type": "code",
-   "execution_count": 3,
+   "execution_count": 1,
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": []
+    }
+   ],
    "source": [
-    "define('hylomorphism == [unit [pop] swoncat] dipd [dip] swoncat genrec')"
+    "[hylomorphism [unit [pop] swoncat] dipd [dip] swoncat genrec] inscribe"
    ]
   },
   {
   },
   {
    "cell_type": "code",
-   "execution_count": 4,
+   "execution_count": 2,
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": []
+    }
+   ],
    "source": [
-    "define('triangular_number == [1 <=] 0 [-- dup] [+] hylomorphism')"
+    "[triangular_number [1 <=] 0 [-- dup] [+] hylomorphism] inscribe"
    ]
   },
   {
   },
   {
    "cell_type": "code",
-   "execution_count": 5,
+   "execution_count": 3,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "10\n"
+      "10"
      ]
     }
    ],
    "source": [
-    "J('5 triangular_number')"
+    "5 triangular_number"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 6,
+   "execution_count": 4,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "[0 0 1 3 6 10 15]\n"
+      "[0 0 1 3 6 10 15 21]"
      ]
     }
    ],
    "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!"
    ]
   },
   {
    "metadata": {},
    "source": [
     "### `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",
     "\n",
     "Each of the above variations can be used to make four slightly different `range` functions."
   },
   {
    "cell_type": "code",
-   "execution_count": 7,
+   "execution_count": 5,
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": []
+    }
+   ],
    "source": [
-    "define('range == [0 <=] [] [-- dup] [swons] hylomorphism')"
+    "clear "
    ]
   },
   {
    "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": {
     "scrolled": false
    },
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "[4 3 2 1 0]\n"
+      "[4 3 2 1 0]"
      ]
     }
    ],
    "source": [
-    "J('5 range')"
+    "5 range"
    ]
   },
   {
    "metadata": {},
    "source": [
     "#### `range` with `H2`\n",
-    "    H2 == c  swap [P]    [pop] [G      [F]     dip] primrec\n",
-    "       == [] swap [0 <=] [pop] [-- dup [swons] dip] primrec"
+    "    H2 == c  swap [P]    [pop] [G      [F]     dip] tailrec\n",
+    "       == [] 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",
    "execution_count": 9,
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": []
+    }
+   ],
    "source": [
-    "define('range_reverse == [] swap [0 <=] [pop] [-- dup [swons] dip] primrec')"
+    "[range_reverse [] swap [0 <=] [pop] [-- dup [swons] dip] tailrec] inscribe"
    ]
   },
   {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "[0 1 2 3 4]\n"
+      "[0 1 2 3 4]"
      ]
     }
    ],
    "source": [
-    "J('5 range_reverse')"
+    "5 range_reverse"
    ]
   },
   {
    "cell_type": "code",
    "execution_count": 11,
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": []
+    }
+   ],
    "source": [
-    "define('ranger == [0 <=] [pop []] [[--] dupdip] [dip swons] genrec')"
+    "clear "
    ]
   },
   {
    "cell_type": "code",
    "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": {
     "scrolled": true
    },
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "[5 4 3 2 1]\n"
+      "[5 4 3 2 1]"
      ]
     }
    ],
    "source": [
-    "J('5 ranger')"
+    "5 ranger"
    ]
   },
   {
   },
   {
    "cell_type": "code",
-   "execution_count": 13,
+   "execution_count": 14,
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": []
+    }
+   ],
    "source": [
-    "define('ranger_reverse == [] swap [0 <=] [pop] [[swons] dupdip --] primrec')"
+    "clear "
    ]
   },
   {
    "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": {
     "scrolled": true
    },
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "[1 2 3 4 5]\n"
+      "[1 2 3 4 5]"
      ]
     }
    ],
    "source": [
-    "J('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."
+    "5 ranger_reverse"
    ]
   },
   {
    "metadata": {},
    "source": [
     "## Catamorphism\n",
-    "A catamorphism can be defined as a hylomorphism that uses `[uncons swap]` for `[G]`\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",
+    "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",
-    "    C == [not] c [uncons swap] [F] hylomorphism"
+    "An example of a catamorphism is the sum function.\n",
+    "\n",
+    "    sum == [not] 0 [uncons swap] [+] hylomorphism"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 15,
+   "execution_count": 17,
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": []
+    }
+   ],
    "source": [
-    "define('swuncons == uncons swap')  # Awkward name."
+    "clear "
    ]
   },
   {
-   "cell_type": "markdown",
+   "cell_type": "code",
+   "execution_count": 18,
    "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": []
+    }
+   ],
    "source": [
-    "An example of a catamorphism is the sum function.\n",
-    "\n",
-    "    sum == [not] 0 [swuncons] [+] hylomorphism"
+    "[sum [not] 0 [uncons swap] [+] hylomorphism] inscribe"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 16,
+   "execution_count": 19,
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "15"
+     ]
+    }
+   ],
    "source": [
-    "define('sum == [not] 0 [swuncons] [+] hylomorphism')"
+    "[5 4 3 2 1] sum"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 17,
+   "execution_count": 20,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
-     "text": [
-      "15\n"
-     ]
+     "text": []
     }
    ],
    "source": [
-    "J('[5 4 3 2 1] sum')"
+    "clear "
    ]
   },
   {
   },
   {
    "cell_type": "code",
-   "execution_count": 18,
+   "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",
+      "       ... [] [Q] . step\n",
+      "    -----------------------\n",
+      "          ... .\n",
       "\n",
       "\n",
       "       ... [a] [Q] . step\n",
       "    ------------------------\n",
-      "             ... a . Q\n",
+      "         ... a . Q\n",
       "\n",
       "\n",
-      "     ... [a b c] [Q] . step\n",
-      "  ----------------------------------------\n",
-      "               ... a . Q [b c] [Q] step\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": [
-    "J('[step] help')"
+    "[step] help"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 19,
+   "execution_count": 22,
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": []
+    }
+   ],
    "source": [
-    "define('sum == 0 swap [+] step')"
+    "[sum 0 swap [+] step] inscribe"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 20,
+   "execution_count": 23,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "15\n"
+      "15"
      ]
     }
    ],
    "source": [
-    "J('[5 4 3 2 1] sum')"
+    "[5 4 3 2 1] sum"
    ]
   },
   {
   },
   {
    "cell_type": "code",
-   "execution_count": 21,
+   "execution_count": 24,
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": []
+    }
+   ],
    "source": [
-    "define('factorial == 1 swap [1 <=] [pop] [[*] dupdip --] primrec')"
+    "clear"
    ]
   },
   {
    "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": {
     "scrolled": false
    },
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "120\n"
+      "120"
      ]
     }
    ],
    "source": [
-    "J('5 factorial')"
+    "5 factorial"
    ]
   },
   {
     "        [1 2 3] tails\n",
     "    --------------------\n",
     "       [[] [3] [2 3]]\n",
-    "    "
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "We can build as we go, and we want `F` to run after `G`, so we use pattern `H2`:\n",
+    "    \n",
+    "\n",
+    "We can build as we go, and we want `Q` to run after `G`, so we use pattern `H2`:\n",
+    "\n",
+    "    H2 == c swap [P] [pop] [G [Q] dip] tailrec\n",
     "\n",
-    "    H2 == c swap [P] [pop] [G [F] dip] primrec"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
     "We would use:\n",
     "\n",
     "    c == []\n",
-    "    F == swons\n",
+    "    Q == swons\n",
     "    G == rest dup\n",
     "    P == not"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 23,
+   "execution_count": 27,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": []
+    }
+   ],
+   "source": [
+    "clear"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 28,
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": []
+    }
+   ],
    "source": [
-    "define('tails == [] swap [not] [pop] [rest dup [swons] dip] primrec')"
+    "[tails [] swap [not] [pop] [rest dup [swons] dip] tailrec] inscribe"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 24,
+   "execution_count": 29,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "[[] [3] [2 3]]\n"
+      "[[] [3] [2 3]]"
      ]
     }
    ],
    "source": [
-    "J('[1 2 3] tails')"
+    "[1 2 3] tails"
    ]
   },
   {
  ],
  "metadata": {
   "kernelspec": {
-   "display_name": "Python 2",
-   "language": "python",
-   "name": "python2"
+   "display_name": "Joypy",
+   "language": "",
+   "name": "thun"
   },
   "language_info": {
-   "codemirror_mode": {
-    "name": "ipython",
-    "version": 2
-   },
-   "file_extension": ".py",
-   "mimetype": "text/x-python",
-   "name": "python",
-   "nbconvert_exporter": "python",
-   "pygments_lexer": "ipython2",
-   "version": "2.7.15"
+   "file_extension": ".joy",
+   "mimetype": "text/plain",
+   "name": "Joy"
   }
  },
  "nbformat": 4,